From cd75213f76ea3b53a1f5d9ba1c694137264a2ff6 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Thu, 12 Oct 2023 21:39:13 +0200 Subject: [PATCH 01/18] fix: a bunch of generator fixes --- generator/features/collateralsUpdates.ts | 11 +---------- generator/features/rateUpdates.ts | 2 +- generator/features/types.ts | 1 - generator/prompts.ts | 1 + generator/templates/script.template.ts | 4 ++-- remappings.txt | 5 ++--- 6 files changed, 7 insertions(+), 17 deletions(-) diff --git a/generator/features/collateralsUpdates.ts b/generator/features/collateralsUpdates.ts index ed70b2800..de7b07140 100644 --- a/generator/features/collateralsUpdates.ts +++ b/generator/features/collateralsUpdates.ts @@ -27,11 +27,6 @@ export async function fetchCollateralUpdate( message: 'Liquidation protocol fee', disableKeepCurrent, }), - eModeCategory: await eModeSelect({ - message: 'e mode category', - disableKeepCurrent, - pool, - }), }; } @@ -71,11 +66,7 @@ export const collateralsUpdates: FeatureModule = { liqThreshold: ${cfg.liqThreshold}, liqBonus: ${cfg.liqBonus}, debtCeiling: ${cfg.debtCeiling}, - liqProtocolFee: ${cfg.liqProtocolFee}, - eModeCategory: ${ - cfg.eModeCategory === ENGINE_FLAGS.KEEP_CURRENT - ? `EngineFlags.KEEP_CURRENT` - : cfg.eModeCategory + liqProtocolFee: ${cfg.liqProtocolFee} } });` ) diff --git a/generator/features/rateUpdates.ts b/generator/features/rateUpdates.ts index 7152c07ca..a691cb404 100644 --- a/generator/features/rateUpdates.ts +++ b/generator/features/rateUpdates.ts @@ -108,7 +108,7 @@ export const rateUpdates: FeatureModule = { : cfg .map( (cfg, ix) => `rateStrategies[${ix}] = IEngine.RateStrategyUpdate({ - asset: ${pool}Assets.${cfg.asset}_UNDERLYING, + asset: ${cfg.asset}, params: Rates.RateStrategyParams({ optimalUsageRatio: ${cfg.params.optimalUtilizationRate}, baseVariableBorrowRate: ${cfg.params.baseVariableBorrowRate}, diff --git a/generator/features/types.ts b/generator/features/types.ts index 18b8c64fb..456b24459 100644 --- a/generator/features/types.ts +++ b/generator/features/types.ts @@ -35,7 +35,6 @@ export interface CollateralUpdatePartial { liqBonus: PercentInputValues; debtCeiling: NumberInputValues; liqProtocolFee: PercentInputValues; - eModeCategory: string; } export interface CollateralUpdate extends CollateralUpdatePartial, AssetSelector {} diff --git a/generator/prompts.ts b/generator/prompts.ts index db0d724c8..97d03f9c4 100644 --- a/generator/prompts.ts +++ b/generator/prompts.ts @@ -21,6 +21,7 @@ function isAddressOrKeepCurrent(value: string) { // TRANSFORMS function transformNumberToPercent(value: string) { if (value && isNumber(value)) { + if (Number(value) <= 9) value = value.padStart(2, '0'); return value.replace(/(?=(\d{2}$)+(?!\d))/g, '.') + ' %'; } return value; diff --git a/generator/templates/script.template.ts b/generator/templates/script.template.ts index 2ece723e3..2cc10765d 100644 --- a/generator/templates/script.template.ts +++ b/generator/templates/script.template.ts @@ -93,13 +93,13 @@ contract CreateProposal is EthereumScript { .join('\n'); template += `payloads[${ix}] = GovV3Helpers.build${ chain == 'Ethereum' ? 'Mainnet' : chain - }(vm, actions${chain});\n`; + }Payload(vm, actions${chain});\n`; return template; }) .join('\n')} // create proposal - GovV3Helpers.createProposal(payloads, GovHelpers.ipfsHashFile(vm, 'src/${folderName}/${ + GovV3Helpers.createProposal(payloads, GovV3Helpers.ipfsHashFile(vm, 'src/${folderName}/${ options.shortName }.md')); } diff --git a/remappings.txt b/remappings.txt index 1a380e7d2..620a76fc2 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,10 +1,9 @@ @aave/core-v3/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-core/ @aave/periphery-v3/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-periphery/ aave-address-book/=lib/aave-helpers/lib/aave-address-book/src/ -aave-helpers/=lib/aave-helpers/ +aave-helpers/=lib/aave-helpers/src/ aave-v3-core/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-core/ aave-v3-periphery/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-periphery/ ds-test/=lib/aave-helpers/lib/forge-std/lib/ds-test/src/ forge-std/=lib/aave-helpers/lib/forge-std/src/ -governance-crosschain-bridges/=lib/aave-helpers/lib/governance-crosschain-bridges/ -solidity-utils/=lib/aave-helpers/lib/solidity-utils/ \ No newline at end of file +solidity-utils/=lib/aave-helpers/lib/solidity-utils/src/ \ No newline at end of file From 95ef8d7ac74f2ce9667bf67269c86af9174702f5 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Thu, 12 Oct 2023 22:04:58 +0200 Subject: [PATCH 02/18] ci: add ci again --- .github/workflows/comment.yml | 12 +++++ .github/workflows/ipfs.yml | 57 ++++++++++++++++++++++ .github/workflows/main.yml | 12 ----- .github/workflows/pull_request_template.md | 11 +++++ .github/workflows/test.yml | 18 +++++++ 5 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/comment.yml create mode 100644 .github/workflows/ipfs.yml delete mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/pull_request_template.md create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml new file mode 100644 index 000000000..0a8a422fd --- /dev/null +++ b/.github/workflows/comment.yml @@ -0,0 +1,12 @@ +name: PR Comment + +on: + workflow_run: + workflows: [Test] + types: + - completed + +jobs: + test: + uses: bgd-labs/github-workflows/.github/workflows/comment.yml@main + secrets: inherit diff --git a/.github/workflows/ipfs.yml b/.github/workflows/ipfs.yml new file mode 100644 index 000000000..5bb6c97a7 --- /dev/null +++ b/.github/workflows/ipfs.yml @@ -0,0 +1,57 @@ +name: Ipfs uploader +# Uploads all changed md files to ipfs once merged to main +# Comments the pr + +concurrency: + group: ${{ github.workflow }} +# cancel-in-progress: true + +on: + pull_request: + push: + branches: + - main + +jobs: + ipfs-upload: + runs-on: ubuntu-latest + name: Ipfs uploader + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v3 + with: + node-version: 18 + registry-url: "https://registry.npmjs.org" + cache: "yarn" + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Get all changed *.md file(s) + id: changed-files + uses: tj-actions/changed-files@f569b77fb1d9ad9f1a125757d7e9e07b1f320199 + with: + json: true + write_output_files: true + files: | + src/**/*.md + + - name: Run step if any *.md file(s) change + if: steps.changed-files.outputs.any_changed == 'true' + run: | + cat .github/outputs/all_changed_files.json + + - name: Upload + if: steps.changed-files.outputs.any_changed == 'true' + env: + PINATA_KEY: ${{ secrets.PINATA_KEY }} + PINATA_SECRET: ${{ secrets.PINATA_SECRET }} + run: | + json_array=($(jq -r '.[]' ".github/outputs/all_changed_files.json")) + for i in "${json_array[@]}" + do + npx aave-cli ipfs $i -u ${{ github.event_name != 'pull_request'}} + done diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 2c4e7d8fb..000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Main workflow - -on: - pull_request: - push: - branches: - - main - workflow_dispatch: - -jobs: - test: - uses: bgd-labs/github-workflows/.github/workflows/foundry-test.yml@main diff --git a/.github/workflows/pull_request_template.md b/.github/workflows/pull_request_template.md new file mode 100644 index 000000000..deaf15b38 --- /dev/null +++ b/.github/workflows/pull_request_template.md @@ -0,0 +1,11 @@ +## AIP checklist + +- [ ] payload contains header comment linking discussion & snapshot +- [ ] a test covering the changes is included +- [ ] new scripts are included (excluding ipfs hash & deployed payload addresses) +- [ ] DO NOT ALTER CODE UNRELATED TO THIS SPECIFIC AIP + +## References + +- [Discussion](link to forum) +- [Snapshot](link to snapshot) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..41960afef --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,18 @@ +name: Test + +concurrency: + group: ${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + uses: bgd-labs/github-workflows/.github/workflows/foundry-test.yml@main + secrets: inherit + with: + mode: "CHANGED" From 88e9ec113747376cf795f15e178b865568e2a1a6 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Thu, 12 Oct 2023 22:18:26 +0200 Subject: [PATCH 03/18] feat: generator improvements --- generator/features/assetListing.ts | 7 +++++- generator/features/types.ts | 1 + generator/generator.ts | 6 +---- generator/templates/proposal.template.ts | 9 ++++---- generator/templates/script.template.ts | 7 +++--- generator/templates/utils.ts | 29 ++++++++++++++++++++++++ scripts/Ghost.s.sol | 13 ----------- 7 files changed, 45 insertions(+), 27 deletions(-) create mode 100644 generator/templates/utils.ts delete mode 100644 scripts/Ghost.s.sol diff --git a/generator/features/assetListing.ts b/generator/features/assetListing.ts index 299d527d0..8d794ac07 100644 --- a/generator/features/assetListing.ts +++ b/generator/features/assetListing.ts @@ -1,5 +1,5 @@ import {CodeArtifact, FeatureModule, PoolIdentifier} from '../types'; -import {addressInput, stringInput} from '../prompts'; +import {addressInput, eModeSelect, stringInput} from '../prompts'; import {fetchBorrowUpdate} from './borrowsUpdates'; import {fetchRateStrategyParams} from './rateUpdates'; import {fetchCollateralUpdate} from './collateralsUpdates'; @@ -49,6 +49,11 @@ async function fetchListing(pool: PoolIdentifier): Promise { ...(await fetchBorrowUpdate(true)), ...(await fetchCapsUpdate(true)), rateStrategyParams: await fetchRateStrategyParams(pool, true), + eModeCategory: await eModeSelect({ + message: `Select the eMode you want to assign to ${asset}`, + disableKeepCurrent: true, + pool, + }), asset, }; } diff --git a/generator/features/types.ts b/generator/features/types.ts index 456b24459..cddcdb496 100644 --- a/generator/features/types.ts +++ b/generator/features/types.ts @@ -84,6 +84,7 @@ export interface Listing asset: Hex; assetSymbol: string; rateStrategyParams: RateStrategyParams; + eModeCategory: number; } export interface ListingWithCustomImpl { diff --git a/generator/generator.ts b/generator/generator.ts index 4a0802c91..2601e07f8 100644 --- a/generator/generator.ts +++ b/generator/generator.ts @@ -164,7 +164,6 @@ if (!configFileLoaded) { } } -console.log('### JSON config emitted to be stored for reuse ###'); const logOptions = { rootOptions: options, poolOptions: Object.keys(poolConfigs).reduce((acc, pool) => { @@ -172,8 +171,6 @@ const logOptions = { return acc; }, {} as PoolConfigs), } as ConfigFile; -console.log(JSON.stringify(logOptions, null, 2)); -console.log('### ###'); const baseName = generateFolderName(options); const baseFolder = path.join(process.cwd(), 'src', baseName); @@ -190,7 +187,7 @@ if (fs.existsSync(baseFolder) && !options.force) { console.log('If you want to overwrite, supply --force'); } else { fs.mkdirSync(baseFolder, {recursive: true}); - + fs.writeFileSync(path.join(baseFolder, 'config.json'), JSON.stringify(logOptions, null, 2)); async function createFiles(options: Options, pool: PoolIdentifier) { const contractName = generateContractName(options, pool); fs.writeFileSync( @@ -212,7 +209,6 @@ if (fs.existsSync(baseFolder) && !options.force) { await Promise.all(options.pools.map((pool) => createFiles(options, pool))); - console.log(generateScript(options)); fs.writeFileSync( path.join(baseFolder, `${generateContractName(options)}.s.sol`), prettier.format(generateScript(options), { diff --git a/generator/templates/proposal.template.ts b/generator/templates/proposal.template.ts index 8de70f652..aaaac5314 100644 --- a/generator/templates/proposal.template.ts +++ b/generator/templates/proposal.template.ts @@ -1,5 +1,6 @@ import {generateContractName, getPoolChain, getVersion, pragma} from '../common'; import {CodeArtifact, Options, PoolIdentifier} from '../types'; +import {prefixWithImports, prefixWithPragma} from './utils'; enum EngineImports { IEngine = 'IEngine', @@ -100,9 +101,9 @@ export const proposalTemplate = ( ${functions} }`; - return `${pragma} + return prefixWithPragma( + prefixWithImports(`${getImports(pool, engineDependencies, poolDependencies)} - ${getImports(pool, engineDependencies, poolDependencies)} - - ${contract}`; + ${contract}`) + ); }; diff --git a/generator/templates/script.template.ts b/generator/templates/script.template.ts index 2cc10765d..d0b41f18b 100644 --- a/generator/templates/script.template.ts +++ b/generator/templates/script.template.ts @@ -1,5 +1,4 @@ import { - CHAINS_WITH_GOV_SUPPORT, generateContractName, generateFolderName, getChainAlias, @@ -7,15 +6,15 @@ import { pragma, } from '../common'; import {Options} from '../types'; +import {prefixWithImports, prefixWithPragma} from './utils'; export function generateScript(options: Options) { const folderName = generateFolderName(options); const fileName = generateContractName(options); - let template = pragma; + let template = ''; const chains = [...new Set(options.pools.map((pool) => getPoolChain(pool)!))]; // generate imports - template += `import {GovV3Helpers} from 'aave-helpers/GovV3Helpers.sol';\n`; template += `import {${['Ethereum', ...chains.filter((c) => c !== 'Ethereum')] .map((chain) => `${chain}Script`) .join(', ')}} from 'aave-helpers/ScriptUtils.sol';\n`; @@ -104,5 +103,5 @@ contract CreateProposal is EthereumScript { }.md')); } }`; - return template; + return prefixWithPragma(prefixWithImports(template)); } diff --git a/generator/templates/utils.ts b/generator/templates/utils.ts new file mode 100644 index 000000000..73dcae01e --- /dev/null +++ b/generator/templates/utils.ts @@ -0,0 +1,29 @@ +import {pragma} from '../common'; + +export function prefixWithPragma(code: string) { + return pragma + code; +} + +const GovernanceImports = [ + 'GovV3Helpers', + 'IPayloadsControllerCore', + 'PayloadsControllerUtils', +] as const; + +function findMatches(code: string, needles: string[] | readonly string[]) { + return needles.filter((needle) => RegExp(needle + '\\.', 'g').test(code)); +} + +/** + * TODO: support more imports + * @param code + * @returns + */ +export function prefixWithImports(code: string) { + let imports = ''; + const govMatches = findMatches(code, GovernanceImports); + if (govMatches.length > 0) + imports += `import {${govMatches}} from 'aave-helpers/GovV3Helpers.sol';`; + + return imports; +} diff --git a/scripts/Ghost.s.sol b/scripts/Ghost.s.sol deleted file mode 100644 index e0546b366..000000000 --- a/scripts/Ghost.s.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {Script} from 'forge-std/Script.sol'; -import {Ghost} from '../src/contracts/Ghost.sol'; - -contract Deploy is Script { - function run() external { - vm.startBroadcast(); - new Ghost(); - vm.stopBroadcast(); - } -} From 6adc6b4f9dd0d3618de9b95a6391323fb83757ca Mon Sep 17 00:00:00 2001 From: sakulstra Date: Sat, 14 Oct 2023 12:28:27 +0200 Subject: [PATCH 04/18] fix: improve types --- generator/features/borrowsUpdates.ts | 8 ++-- generator/features/types.ts | 11 +++-- generator/prompts.ts | 66 ++++++++++++++++++++-------- generator/templates/test.template.ts | 8 ++-- 4 files changed, 61 insertions(+), 32 deletions(-) diff --git a/generator/features/borrowsUpdates.ts b/generator/features/borrowsUpdates.ts index 2c7c041b2..7477f482b 100644 --- a/generator/features/borrowsUpdates.ts +++ b/generator/features/borrowsUpdates.ts @@ -1,10 +1,8 @@ import {CodeArtifact, FeatureModule} from '../types'; import {assetsSelect, booleanSelect, percentInput} from '../prompts'; -import {BorrowUpdate, BorrowUpdatePartial} from './types'; +import {BorrowUpdate} from './types'; -export async function fetchBorrowUpdate( - disableKeepCurrent?: boolean -): Promise { +export async function fetchBorrowUpdate(disableKeepCurrent?: T) { return { enabledToBorrow: await booleanSelect({ message: 'enabled to borrow', @@ -46,7 +44,7 @@ export const borrowsUpdates: FeatureModule = { const response: BorrowUpdates = []; for (const asset of assets) { console.log(`Fetching information for BorrowUpdates on ${pool} ${asset}`); - response.push({...(await fetchBorrowUpdate()), asset}); + response.push({...(await fetchBorrowUpdate(false)), asset}); } return response; }, diff --git a/generator/features/types.ts b/generator/features/types.ts index cddcdb496..9cc6bab14 100644 --- a/generator/features/types.ts +++ b/generator/features/types.ts @@ -1,5 +1,10 @@ import {Hex} from 'viem'; -import {BooleanSelectValues, NumberInputValues, PercentInputValues} from '../prompts'; +import { + AddressInputValues, + BooleanSelectValues, + NumberInputValues, + PercentInputValues, +} from '../prompts'; export interface AssetSelector { asset: string; @@ -56,7 +61,7 @@ export interface EModeCategoryUpdate { ltv: NumberInputValues; liqThreshold: NumberInputValues; liqBonus: NumberInputValues; - priceSource: Hex; + priceSource: AddressInputValues; label: string; } @@ -84,7 +89,7 @@ export interface Listing asset: Hex; assetSymbol: string; rateStrategyParams: RateStrategyParams; - eModeCategory: number; + eModeCategory: string; } export interface ListingWithCustomImpl { diff --git a/generator/prompts.ts b/generator/prompts.ts index 97d03f9c4..ce7f68bd8 100644 --- a/generator/prompts.ts +++ b/generator/prompts.ts @@ -1,7 +1,7 @@ import {checkbox, input, select} from '@inquirer/prompts'; import {ENGINE_FLAGS, PoolIdentifier} from './types'; import {getAssets, getEModes} from './common'; -import {getAddress, isAddress} from 'viem'; +import {Hex, getAddress, isAddress} from 'viem'; // VALIDATION function isNumber(value: string) { @@ -61,9 +61,9 @@ function translateAssetToAssetLibUnderlying(value: string, pool: PoolIdentifier) } // PROMPTS -interface GenericPrompt { +interface GenericPrompt { message: string; - disableKeepCurrent?: boolean; + disableKeepCurrent?: T; transform?: (value: string) => string; defaultValue?: string; } @@ -73,24 +73,39 @@ export type BooleanSelectValues = | typeof ENGINE_FLAGS.ENABLED | typeof ENGINE_FLAGS.DISABLED; -export async function booleanSelect({message, disableKeepCurrent}: GenericPrompt) { - return select({ +export async function booleanSelect({ + message, + disableKeepCurrent, +}: GenericPrompt): Promise< + T extends true ? Exclude : BooleanSelectValues +> { + const choices = [ + ...(disableKeepCurrent ? [] : [{value: ENGINE_FLAGS.KEEP_CURRENT}]), + {value: ENGINE_FLAGS.ENABLED}, + {value: ENGINE_FLAGS.DISABLED}, + ]; + const value = await select({ message, - choices: [ - ...(disableKeepCurrent ? [] : [{value: ENGINE_FLAGS.KEEP_CURRENT}]), - {value: ENGINE_FLAGS.ENABLED}, - {value: ENGINE_FLAGS.DISABLED}, - ], + choices: choices, }); + return value as T extends true + ? Exclude + : BooleanSelectValues; } -interface PercentInputPrompt extends GenericPrompt { +interface PercentInputPrompt extends GenericPrompt { toRay?: boolean; } export type PercentInputValues = typeof ENGINE_FLAGS.KEEP_CURRENT | string; -export async function percentInput({message, disableKeepCurrent, toRay}: PercentInputPrompt) { +export async function percentInput({ + message, + disableKeepCurrent, + toRay, +}: PercentInputPrompt): Promise< + T extends true ? PercentInputValues : Exclude +> { const value = await input({ message, transformer: transformNumberToPercent, @@ -112,16 +127,21 @@ export async function numberInput({message, disableKeepCurrent}: GenericPrompt) return translateJsNumberToSol(value); } -export async function addressInput({message, disableKeepCurrent}: GenericPrompt) { +export type AddressInputValues = Hex | typeof ENGINE_FLAGS.KEEP_CURRENT_ADDRESS; + +export async function addressInput({ + message, + disableKeepCurrent, +}: GenericPrompt): Promise { const value = await input({ message, validate: disableKeepCurrent ? isAddress : isAddressOrKeepCurrent, ...(disableKeepCurrent ? {} : {default: ENGINE_FLAGS.KEEP_CURRENT_ADDRESS}), }); - return translateJsAddressToSol(value); + return translateJsAddressToSol(value) as T extends true ? Hex : AddressInputValues; } -interface AssetsSelectPrompt extends Omit { +interface AssetsSelectPrompt extends Exclude { pool: PoolIdentifier; } @@ -138,11 +158,15 @@ export async function assetsSelect({pool, message}: AssetsSelectPrompt) { return values.map((v) => translateAssetToAssetLibUnderlying(v, pool)); } -interface EModeSelectPrompt extends GenericPrompt { +interface EModeSelectPrompt extends GenericPrompt { pool: PoolIdentifier; } -export async function eModeSelect({message, disableKeepCurrent, pool}: EModeSelectPrompt) { +export async function eModeSelect({ + message, + disableKeepCurrent, + pool, +}: EModeSelectPrompt) { const eModes = getEModes(pool as any); const eMode = await select({ message, @@ -154,7 +178,7 @@ export async function eModeSelect({message, disableKeepCurrent, pool}: EModeSele return translateEModeToEModeLib(eMode, pool); } -export async function eModesSelect({message, pool}: EModeSelectPrompt) { +export async function eModesSelect({message, pool}: EModeSelectPrompt) { const eModes = getEModes(pool as any); const values = await checkbox({ message, @@ -167,7 +191,11 @@ export async function eModesSelect({message, pool}: EModeSelectPrompt) { return values.map((mode) => translateEModeToEModeLib(mode, pool)); } -export async function stringInput({message, defaultValue, disableKeepCurrent}: GenericPrompt) { +export async function stringInput({ + message, + defaultValue, + disableKeepCurrent, +}: GenericPrompt) { return input({ message, default: defaultValue, diff --git a/generator/templates/test.template.ts b/generator/templates/test.template.ts index 8292adabe..57f4da3a8 100644 --- a/generator/templates/test.template.ts +++ b/generator/templates/test.template.ts @@ -7,6 +7,7 @@ import { isV2Pool, } from '../common'; import {CodeArtifact, Options, PoolIdentifier} from '../types'; +import {prefixWithImports, prefixWithPragma} from './utils'; export const getBlock = async (chain) => { return await createPublicClient({ @@ -30,11 +31,8 @@ export const testTemplate = async ( .flat() .filter((f) => f !== undefined) .join('\n'); - let template = `// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - + let template = ` import 'forge-std/Test.sol'; -import {GovV3Helpers} from 'aave-helpers/GovV3Helpers.sol'; import {${pool}, ${pool}Assets} from 'aave-address-book/${pool}.sol'; import {${testBase}, ReserveConfig} from 'aave-helpers/${testBase}.sol'; import {${contractName}} from './${contractName}.sol'; @@ -72,5 +70,5 @@ contract ${contractName}_Test is ${testBase} { ${functions} }`; - return template; + return prefixWithPragma(prefixWithImports(template)); }; From 03062aa31c5427dfe1039ca27a4732258b9fb70a Mon Sep 17 00:00:00 2001 From: sakulstra Date: Wed, 18 Oct 2023 17:38:38 +0200 Subject: [PATCH 05/18] fix: update generator --- generator/cli.ts | 160 ++++++++++ generator/common.ts | 4 +- generator/features/assetListing.ts | 12 +- generator/features/borrowsUpdates.ts | 5 +- generator/features/capsUpdates.ts | 5 +- generator/features/collateralsUpdates.ts | 5 +- generator/features/eModesAssets.ts | 5 +- generator/features/eModesUpdates.ts | 5 +- generator/features/flashBorrower.ts | 9 +- generator/features/priceFeedsUpdates.ts | 5 +- generator/features/rateUpdates.ts | 117 +++++--- generator/features/types.ts | 7 + generator/generator.ts | 281 ++++++------------ generator/prompts.ts | 2 +- generator/templates/aip.template.ts | 15 +- generator/templates/proposal.template.ts | 55 +--- generator/templates/script.template.ts | 3 +- generator/templates/test.template.ts | 3 +- generator/templates/utils.ts | 24 -- generator/types.ts | 26 +- generator/utils/importsResolver.spec.ts | 34 +++ generator/utils/importsResolver.ts | 98 +++++++ package.json | 8 +- yarn.lock | 358 ++++++++++++++++++++++- 24 files changed, 892 insertions(+), 354 deletions(-) create mode 100644 generator/cli.ts create mode 100644 generator/utils/importsResolver.spec.ts create mode 100644 generator/utils/importsResolver.ts diff --git a/generator/cli.ts b/generator/cli.ts new file mode 100644 index 000000000..8aa217aee --- /dev/null +++ b/generator/cli.ts @@ -0,0 +1,160 @@ +import path from 'path'; +import {Command, Option} from 'commander'; +import {getDate, isV2Pool, pascalCase} from './common'; +import {input, checkbox} from '@inquirer/prompts'; +import { + CodeArtifact, + ConfigFile, + FEATURE, + FeatureModule, + Options, + POOLS, + PoolConfig, + PoolConfigs, +} from './types'; +import {flashBorrower} from './features/flashBorrower'; +import {capsUpdates} from './features/capsUpdates'; +import {rateUpdatesV2, rateUpdatesV3} from './features/rateUpdates'; +import {collateralsUpdates} from './features/collateralsUpdates'; +import {borrowsUpdates} from './features/borrowsUpdates'; +import {eModeUpdates} from './features/eModesUpdates'; +import {eModeAssets} from './features/eModesAssets'; +import {priceFeedsUpdates} from './features/priceFeedsUpdates'; +import {assetListing, assetListingCustom} from './features/assetListing'; +import {generateFiles, writeFiles} from './generator'; + +const program = new Command(); + +program + .name('proposal-generator') + .description('CLI to generate aave proposals') + .version('1.0.0') + .addOption(new Option('-f, --force', 'force creation (might overwrite existing files)')) + .addOption(new Option('-p, --pools ').choices(POOLS)) + .addOption(new Option('-t, --title ', 'aip title')) + .addOption(new Option('-a, --author ', 'author')) + .addOption(new Option('-d, --discussion ', 'forum link')) + .addOption(new Option('-s, --snapshot ', 'snapshot link')) + .addOption(new Option('-c, --configFile ', 'path to config file')) + .allowExcessArguments(false) + .parse(process.argv); + +let options = program.opts(); +let poolConfigs: PoolConfigs = {}; + +const PLACEHOLDER_MODULE: FeatureModule = { + description: 'Something different not supported by configEngine', + value: FEATURE.OTHERS, + cli: async (opt, pool) => { + return {}; + }, + build: (opt, pool, cfg) => { + const response: CodeArtifact = { + code: {execute: ['// custom code goes here']}, + }; + return response; + }, +}; +const FEATURE_MODULES_V2 = [rateUpdatesV2, PLACEHOLDER_MODULE]; +const FEATURE_MODULES_V3 = [ + rateUpdatesV3, + capsUpdates, + collateralsUpdates, + borrowsUpdates, + flashBorrower, + priceFeedsUpdates, + eModeUpdates, + eModeAssets, + assetListing, + assetListingCustom, + PLACEHOLDER_MODULE, +]; + +if (options.configFile) { + const cfgFile: ConfigFile = await import(path.join(process.cwd(), options.configFile)); + options = cfgFile.rootOptions; + poolConfigs = cfgFile.poolOptions as any; + for (const pool of options.pools) { + const v2 = isV2Pool(pool); + poolConfigs[pool]!.artifacts = []; + for (const feature of poolConfigs[pool]!.features) { + const module = v2 + ? FEATURE_MODULES_V2.find((m) => m.value === feature)! + : FEATURE_MODULES_V3.find((m) => m.value === feature)!; + poolConfigs[pool]!.artifacts.push( + module.build(options, pool, poolConfigs[pool]!.configs[feature]) + ); + } + } +} else { + // workaround as there's validate is not currently supported on checkbox + // https://github.com/SBoudrias/Inquirer.js/issues/1257 + while (!options.pools?.length === true) { + options.pools = await checkbox({ + message: 'Chains this proposal targets', + choices: POOLS.map((v) => ({name: v, value: v})), + // validate(input) { + // // currently ignored due to a bug + // if (input.length == 0) return 'You must target at least one chain in your proposal!'; + // return true; + // }, + }); + } + + if (!options.title) { + options.title = await input({ + message: 'Title of your proposal', + validate(input) { + if (input.length == 0) return "Your title can't be empty"; + return true; + }, + }); + } + options.shortName = pascalCase(options.title); + options.date = getDate(); + + if (!options.author) { + options.author = await input({ + message: 'Author of your proposal', + validate(input) { + if (input.length == 0) return "Your author can't be empty"; + return true; + }, + }); + } + + if (!options.discussion) { + options.discussion = await input({ + message: 'Link to forum discussion', + }); + } + + if (!options.snapshot) { + options.snapshot = await input({ + message: 'Link to snapshot', + }); + } + + for (const pool of options.pools) { + poolConfigs[pool] = {configs: {}, artifacts: [], features: []} as PoolConfig; + const v2 = isV2Pool(pool); + poolConfigs[pool]!.features = await checkbox({ + message: `What do you want to do on ${pool}?`, + choices: v2 + ? FEATURE_MODULES_V2.map((m) => ({value: m.value, name: m.description})) + : FEATURE_MODULES_V3.map((m) => ({value: m.value, name: m.description})), + }); + for (const feature of poolConfigs[pool]!.features) { + const module = v2 + ? FEATURE_MODULES_V2.find((m) => m.value === feature)! + : FEATURE_MODULES_V3.find((m) => m.value === feature)!; + poolConfigs[pool]!.configs[feature] = await module.cli(options, pool); + poolConfigs[pool]!.artifacts.push( + module.build(options, pool, poolConfigs[pool]!.configs[feature]) + ); + } + } +} + +const files = await generateFiles(options, poolConfigs); +await writeFiles(options, files); diff --git a/generator/common.ts b/generator/common.ts index 9d01f9906..4bd368658 100644 --- a/generator/common.ts +++ b/generator/common.ts @@ -73,7 +73,7 @@ export function getDate() { * @returns */ export function generateFolderName(options: Options) { - return `${getDate()}_${options.pools.length === 1 ? options.pools[0] : 'Multi'}_${ + return `${options.date}_${options.pools.length === 1 ? options.pools[0] : 'Multi'}_${ options.shortName }`; } @@ -87,7 +87,7 @@ export function generateFolderName(options: Options) { export function generateContractName(options: Options, pool?: PoolIdentifier) { let name = pool ? `${pool}_` : ''; name += `${options.shortName}`; - name += `_${getDate()}`; + name += `_${options.date}`; return name; } diff --git a/generator/features/assetListing.ts b/generator/features/assetListing.ts index 8d794ac07..db193c9b0 100644 --- a/generator/features/assetListing.ts +++ b/generator/features/assetListing.ts @@ -1,7 +1,7 @@ -import {CodeArtifact, FeatureModule, PoolIdentifier} from '../types'; +import {CodeArtifact, FEATURE, FeatureModule, PoolIdentifier} from '../types'; import {addressInput, eModeSelect, stringInput} from '../prompts'; import {fetchBorrowUpdate} from './borrowsUpdates'; -import {fetchRateStrategyParams} from './rateUpdates'; +import {fetchRateStrategyParamsV3} from './rateUpdates'; import {fetchCollateralUpdate} from './collateralsUpdates'; import {fetchCapsUpdate} from './capsUpdates'; import {Listing, ListingWithCustomImpl, TokenImplementations} from './types'; @@ -48,7 +48,7 @@ async function fetchListing(pool: PoolIdentifier): Promise { ...(await fetchCollateralUpdate(pool, true)), ...(await fetchBorrowUpdate(true)), ...(await fetchCapsUpdate(true)), - rateStrategyParams: await fetchRateStrategyParams(pool, true), + rateStrategyParams: await fetchRateStrategyParamsV3(true), eModeCategory: await eModeSelect({ message: `Select the eMode you want to assign to ${asset}`, disableKeepCurrent: true, @@ -67,7 +67,8 @@ async function fetchCustomImpl(): Promise { } export const assetListing: FeatureModule = { - value: 'newListings (listing a new asset)', + value: FEATURE.ASSET_LISTING, + description: 'newListings (listing a new asset)', async cli(opt, pool) { const response: Listing[] = []; console.log(`Fetching information for Assets assets on ${pool}`); @@ -133,7 +134,8 @@ export const assetListing: FeatureModule = { }; export const assetListingCustom: FeatureModule = { - value: 'newListingsCustom (listing a new asset, with custom imeplementations)', + value: FEATURE.ASSET_LISTING_CUSTOM, + description: 'newListingsCustom (listing a new asset, with custom imeplementations)', async cli(opt, pool) { const response: ListingWithCustomImpl[] = []; let more: boolean = true; diff --git a/generator/features/borrowsUpdates.ts b/generator/features/borrowsUpdates.ts index 7477f482b..14ed0a03b 100644 --- a/generator/features/borrowsUpdates.ts +++ b/generator/features/borrowsUpdates.ts @@ -1,4 +1,4 @@ -import {CodeArtifact, FeatureModule} from '../types'; +import {CodeArtifact, FEATURE, FeatureModule} from '../types'; import {assetsSelect, booleanSelect, percentInput} from '../prompts'; import {BorrowUpdate} from './types'; @@ -34,7 +34,8 @@ export async function fetchBorrowUpdate(disableKeepCurrent?: type BorrowUpdates = BorrowUpdate[]; export const borrowsUpdates: FeatureModule = { - value: + value: FEATURE.BORROWS_UPDATE, + description: 'BorrowsUpdates (enabledToBorrow, flashloanable, stableRateModeEnabled, borrowableInIsolation, withSiloedBorrowing, reserveFactor)', async cli(opt, pool) { const assets = await assetsSelect({ diff --git a/generator/features/capsUpdates.ts b/generator/features/capsUpdates.ts index 99ab52657..8444163f0 100644 --- a/generator/features/capsUpdates.ts +++ b/generator/features/capsUpdates.ts @@ -1,4 +1,4 @@ -import {CodeArtifact, FeatureModule, PoolIdentifier} from '../types'; +import {CodeArtifact, FEATURE, FeatureModule, PoolIdentifier} from '../types'; import {assetsSelect, numberInput} from '../prompts'; import {CapsUpdate, CapsUpdatePartial} from './types'; @@ -18,7 +18,8 @@ export async function fetchCapsUpdate(disableKeepCurrent?: boolean): Promise = { - value: 'CapsUpdates (supplyCap, borrowCap)', + value: FEATURE.CAPS_UPDATE, + description: 'CapsUpdates (supplyCap, borrowCap)', async cli(opt, pool) { console.log(`Fetching information for CapsUpdates on ${pool}`); const assets = await assetsSelect({ diff --git a/generator/features/collateralsUpdates.ts b/generator/features/collateralsUpdates.ts index de7b07140..c6327cc6c 100644 --- a/generator/features/collateralsUpdates.ts +++ b/generator/features/collateralsUpdates.ts @@ -1,4 +1,4 @@ -import {CodeArtifact, ENGINE_FLAGS, FeatureModule, PoolIdentifier} from '../types'; +import {CodeArtifact, ENGINE_FLAGS, FEATURE, FeatureModule, PoolIdentifier} from '../types'; import {assetsSelect, eModeSelect, numberInput, percentInput} from '../prompts'; import {CollateralUpdate, CollateralUpdatePartial} from './types'; @@ -33,7 +33,8 @@ export async function fetchCollateralUpdate( type CollateralUpdates = CollateralUpdate[]; export const collateralsUpdates: FeatureModule = { - value: 'CollateralsUpdates (ltv,lt,lb,debtCeiling,liqProtocolFee,eModeCategory)', + value: FEATURE.COLLATERALS_UPDATE, + description: 'CollateralsUpdates (ltv,lt,lb,debtCeiling,liqProtocolFee,eModeCategory)', async cli(opt, pool) { console.log(`Fetching information for Collateral Updates on ${pool}`); diff --git a/generator/features/eModesAssets.ts b/generator/features/eModesAssets.ts index faf486192..5409e1b1f 100644 --- a/generator/features/eModesAssets.ts +++ b/generator/features/eModesAssets.ts @@ -1,4 +1,4 @@ -import {CodeArtifact, FeatureModule, PoolIdentifier} from '../types'; +import {CodeArtifact, FEATURE, FeatureModule, PoolIdentifier} from '../types'; import {assetsSelect, eModeSelect} from '../prompts'; import {AssetEModeUpdate} from './types'; @@ -26,7 +26,8 @@ async function subCli(pool: PoolIdentifier) { type EmodeAssetUpdates = AssetEModeUpdate[]; export const eModeAssets: FeatureModule = { - value: 'assetsEModeUpdates (setting eMode for an asset)', + value: FEATURE.EMODES_ASSETS, + description: 'assetsEModeUpdates (setting eMode for an asset)', async cli(opt, pool) { const response: EmodeAssetUpdates = await subCli(pool); return response; diff --git a/generator/features/eModesUpdates.ts b/generator/features/eModesUpdates.ts index 39d64ac72..a6c8d4871 100644 --- a/generator/features/eModesUpdates.ts +++ b/generator/features/eModesUpdates.ts @@ -1,4 +1,4 @@ -import {CodeArtifact, FeatureModule, PoolIdentifier} from '../types'; +import {CodeArtifact, FEATURE, FeatureModule, PoolIdentifier} from '../types'; import {addressInput, eModesSelect, percentInput, stringInput} from '../prompts'; import {EModeCategoryUpdate} from './types'; @@ -34,7 +34,8 @@ async function subCli(pool: PoolIdentifier) { type EmodeUpdates = EModeCategoryUpdate[]; export const eModeUpdates: FeatureModule = { - value: 'eModeCategoriesUpdates (altering/adding eModes)', + value: FEATURE.EMODES_UPDATES, + description: 'eModeCategoriesUpdates (altering/adding eModes)', async cli(opt, pool) { const response: EmodeUpdates = await subCli(pool); return response; diff --git a/generator/features/flashBorrower.ts b/generator/features/flashBorrower.ts index 46949c6af..0eef49bed 100644 --- a/generator/features/flashBorrower.ts +++ b/generator/features/flashBorrower.ts @@ -1,17 +1,20 @@ -import {CodeArtifact, FeatureModule} from '../types'; +import {CodeArtifact, FEATURE, FeatureModule} from '../types'; import {addressInput} from '../prompts'; +import {Hex} from 'viem'; type FlashBorrower = { - address: string; + address: Hex; }; export const flashBorrower: FeatureModule = { - value: 'FlashBorrower (whitelist address as 0% fee flashborrower)', + value: FEATURE.FLASH_BORROWER, + description: 'FlashBorrower (whitelist address as 0% fee flashborrower)', async cli(opt, pool) { console.log(`Fetching information for FlashBorrower on ${pool}`); const response: FlashBorrower = { address: await addressInput({ message: 'Who do you want to grant the flashBorrower role', + disableKeepCurrent: true, }), }; return response; diff --git a/generator/features/priceFeedsUpdates.ts b/generator/features/priceFeedsUpdates.ts index 53e06ebb8..6bac2d2fe 100644 --- a/generator/features/priceFeedsUpdates.ts +++ b/generator/features/priceFeedsUpdates.ts @@ -1,4 +1,4 @@ -import {CodeArtifact, FeatureModule, PoolIdentifier} from '../types'; +import {CodeArtifact, FEATURE, FeatureModule, PoolIdentifier} from '../types'; import {addressInput, assetsSelect} from '../prompts'; import {PriceFeedUpdate, PriceFeedUpdatePartial} from './types'; @@ -12,7 +12,8 @@ async function fetchPriceFeedUpdate(): Promise { } export const priceFeedsUpdates: FeatureModule = { - value: 'PriceFeedsUpdates (replacing priceFeeds)', + value: FEATURE.PRICE_FEEDS_UPDATE, + description: 'PriceFeedsUpdates (replacing priceFeeds)', async cli(opt, pool) { const response: PriceFeedUpdate[] = []; const assets = await assetsSelect({ diff --git a/generator/features/rateUpdates.ts b/generator/features/rateUpdates.ts index a691cb404..d77aebcee 100644 --- a/generator/features/rateUpdates.ts +++ b/generator/features/rateUpdates.ts @@ -1,10 +1,8 @@ -import {CodeArtifact, FeatureModule, PoolIdentifier} from '../types'; -import {isV2Pool} from '../common'; +import {CodeArtifact, FEATURE, FeatureModule, PoolIdentifier} from '../types'; import {assetsSelect, percentInput} from '../prompts'; import {RateStrategyParams, RateStrategyUpdate} from './types'; -export async function fetchRateStrategyParams( - pool: PoolIdentifier, +export async function fetchRateStrategyParamsV2( disableKeepCurrent?: boolean ): Promise { return { @@ -38,30 +36,34 @@ export async function fetchRateStrategyParams( toRay: true, disableKeepCurrent, }), - ...(isV2Pool(pool) - ? {} - : { - baseStableRateOffset: await percentInput({ - message: 'baseStableRateOffset', - toRay: true, - disableKeepCurrent, - }), - stableRateExcessOffset: await percentInput({ - message: 'stableRateExcessOffset', - toRay: true, - disableKeepCurrent, - }), - optimalStableToTotalDebtRatio: await percentInput({ - message: 'stableRateExcessOffset', - toRay: true, - disableKeepCurrent, - }), - }), }; } -export const rateUpdates: FeatureModule = { - value: 'RateStrategiesUpdates', +export async function fetchRateStrategyParamsV3(disableKeepCurrent?: boolean) { + const params = await fetchRateStrategyParamsV2(); + return { + ...params, + baseStableRateOffset: await percentInput({ + message: 'baseStableRateOffset', + toRay: true, + disableKeepCurrent, + }), + stableRateExcessOffset: await percentInput({ + message: 'stableRateExcessOffset', + toRay: true, + disableKeepCurrent, + }), + optimalStableToTotalDebtRatio: await percentInput({ + message: 'stableRateExcessOffset', + toRay: true, + disableKeepCurrent, + }), + }; +} + +export const rateUpdatesV2: FeatureModule = { + value: FEATURE.RATE_UPDATE_V2, + description: 'RateStrategiesUpdates', async cli(opt, pool) { console.log(`Fetching information for RatesUpdate on ${pool}`); const assets = await assetsSelect({ @@ -71,7 +73,7 @@ export const rateUpdates: FeatureModule = { const response: RateStrategyUpdate[] = []; for (const asset of assets) { console.log(`Fetching info for ${asset}`); - response.push({asset, params: await fetchRateStrategyParams(pool)}); + response.push({asset, params: await fetchRateStrategyParamsV2()}); } return response; }, @@ -88,11 +90,9 @@ export const rateUpdates: FeatureModule = { IEngine.RateStrategyUpdate[] memory rateStrategies = new IEngine.RateStrategyUpdate[](${ cfg.length }); - ${ - isV2Pool(pool) - ? cfg - .map( - (cfg, ix) => `rateStrategies[${ix}] = IEngine.RateStrategyUpdate({ + ${cfg + .map( + (cfg, ix) => `rateStrategies[${ix}] = IEngine.RateStrategyUpdate({ asset: ${cfg.asset}, params: Rates.RateStrategyParams({ optimalUtilizationRate: ${cfg.params.optimalUtilizationRate}, @@ -103,11 +103,51 @@ export const rateUpdates: FeatureModule = { stableRateSlope2: ${cfg.params.stableRateSlope2} }) });` - ) - .join('\n') - : cfg - .map( - (cfg, ix) => `rateStrategies[${ix}] = IEngine.RateStrategyUpdate({ + ) + .join('\n')} + + + return rateStrategies; + }`, + ], + }, + }; + return response; + }, +}; + +export const rateUpdatesV3: FeatureModule = { + value: FEATURE.RATE_UPDATE_V3, + description: 'RateStrategiesUpdates', + async cli(opt, pool) { + console.log(`Fetching information for RatesUpdate on ${pool}`); + const assets = await assetsSelect({ + message: 'Select the assets you want to amend', + pool, + }); + const response: RateStrategyUpdate[] = []; + for (const asset of assets) { + console.log(`Fetching info for ${asset}`); + response.push({asset, params: await fetchRateStrategyParamsV3()}); + } + return response; + }, + build(opt, pool, cfg) { + const response: CodeArtifact = { + code: { + fn: [ + `function rateStrategiesUpdates() + public + pure + override + returns (IEngine.RateStrategyUpdate[] memory) + { + IEngine.RateStrategyUpdate[] memory rateStrategies = new IEngine.RateStrategyUpdate[](${ + cfg.length + }); + ${cfg + .map( + (cfg, ix) => `rateStrategies[${ix}] = IEngine.RateStrategyUpdate({ asset: ${cfg.asset}, params: Rates.RateStrategyParams({ optimalUsageRatio: ${cfg.params.optimalUtilizationRate}, @@ -121,9 +161,8 @@ export const rateUpdates: FeatureModule = { optimalStableToTotalDebtRatio: ${cfg.params.optimalStableToTotalDebtRatio!} }) });` - ) - .join('\n') - } + ) + .join('\n')} return rateStrategies; diff --git a/generator/features/types.ts b/generator/features/types.ts index 9cc6bab14..6dd6b0cbd 100644 --- a/generator/features/types.ts +++ b/generator/features/types.ts @@ -96,3 +96,10 @@ export interface ListingWithCustomImpl { base: Listing; implementations: TokenImplementations; } + +export interface TokenStream { + asset: Hex; + receiver: Hex; + duration: string; + amount: string; +} diff --git a/generator/generator.ts b/generator/generator.ts index 2601e07f8..88c2bf950 100644 --- a/generator/generator.ts +++ b/generator/generator.ts @@ -1,226 +1,111 @@ import fs from 'fs'; import path from 'path'; -import {Command, Option} from 'commander'; -import {generateContractName, generateFolderName, isV2Pool, pascalCase} from './common'; +import {generateContractName, generateFolderName} from './common'; import {proposalTemplate} from './templates/proposal.template'; import {testTemplate} from './templates/test.template'; -import {input, checkbox, confirm} from '@inquirer/prompts'; -import { - CodeArtifact, - ConfigFile, - FeatureModule, - Options, - POOLS, - PoolConfig, - PoolConfigs, - PoolIdentifier, -} from './types'; -import {flashBorrower} from './features/flashBorrower'; -import {capsUpdates} from './features/capsUpdates'; -import {rateUpdates} from './features/rateUpdates'; +import {confirm} from '@inquirer/prompts'; +import {ConfigFile, Options, PoolConfigs, PoolIdentifier} from './types'; import prettier from 'prettier'; import {generateScript} from './templates/script.template'; import {generateAIP} from './templates/aip.template'; -import {collateralsUpdates} from './features/collateralsUpdates'; -import {borrowsUpdates} from './features/borrowsUpdates'; -import {eModeUpdates} from './features/eModesUpdates'; -import {eModeAssets} from './features/eModesAssets'; -import {priceFeedsUpdates} from './features/priceFeedsUpdates'; -import {assetListing, assetListingCustom} from './features/assetListing'; const prettierSolCfg = await prettier.resolveConfig('foo.sol'); const prettierMDCfg = await prettier.resolveConfig('foo.md'); -const program = new Command(); - -program - .name('proposal-generator') - .description('CLI to generate aave proposals') - .version('1.0.0') - .addOption(new Option('-f, --force', 'force creation (might overwrite existing files)')) - .addOption(new Option('-p, --pools ').choices(POOLS)) - .addOption(new Option('-t, --title ', 'aip title')) - .addOption(new Option('-a, --author ', 'author')) - .addOption(new Option('-d, --discussion ', 'forum link')) - .addOption(new Option('-s, --snapshot ', 'snapshot link')) - .addOption(new Option('-c, --configFile ', 'path to config file')) - .allowExcessArguments(false) - .parse(process.argv); - -let options = program.opts(); -let poolConfigs: PoolConfigs = {}; - -let configFileLoaded = false; -if (options.configFile) { - const cfgFile: ConfigFile = await import(path.join(process.cwd(), options.configFile)); - options = cfgFile.rootOptions; - poolConfigs = cfgFile.poolOptions as any; - configFileLoaded = true; -} - -// workaround as there's validate is not currently supported on checkbox -// https://github.com/SBoudrias/Inquirer.js/issues/1257 -while (!options.pools?.length === true) { - options.pools = await checkbox({ - message: 'Chains this proposal targets', - choices: POOLS.map((v) => ({name: v, value: v})), - // validate(input) { - // // currently ignored due to a bug - // if (input.length == 0) return 'You must target at least one chain in your proposal!'; - // return true; - // }, - }); -} - -if (!options.title) { - options.title = await input({ - message: 'Title of your proposal', - validate(input) { - if (input.length == 0) return "Your title can't be empty"; - return true; - }, - }); -} -options.shortName = pascalCase(options.title); - -if (!options.author) { - options.author = await input({ - message: 'Author of your proposal', - validate(input) { - if (input.length == 0) return "Your author can't be empty"; - return true; - }, - }); -} +type Files = { + jsonConfig: string; + script: string; + aip: string; + payloads: {payload: string; test: string; contractName: string}[]; +}; -if (!options.discussion) { - options.discussion = await input({ - message: 'Link to forum discussion', - }); -} +/** + * Generates all the file contents for aip/tests/payloads & script + * @param options + * @param poolConfigs + * @returns + */ +export async function generateFiles(options: Options, poolConfigs: PoolConfigs): Promise { + const jsonConfig = JSON.stringify( + { + rootOptions: options, + poolOptions: Object.keys(poolConfigs).reduce((acc, pool) => { + acc[pool] = {configs: poolConfigs[pool].configs, features: poolConfigs[pool].features}; + return acc; + }, {} as PoolConfigs), + } as ConfigFile, + null, + 2 + ); -if (!options.snapshot) { - options.snapshot = await input({ - message: 'Link to snapshot', - }); -} -const PLACEHOLDER_MODULE = { - value: 'Something different not supported by configEngine', - cli: async (opt, pool) => { - return {}; - }, - build: (opt, pool, cfg) => { - const response: CodeArtifact = { - code: {execute: ['// custom code goes here']}, - }; - return response; - }, -}; -const FEATURE_MODULES_V2 = [rateUpdates, PLACEHOLDER_MODULE]; -const FEATURE_MODULES_V3 = [ - rateUpdates, - capsUpdates, - collateralsUpdates, - borrowsUpdates, - flashBorrower, - priceFeedsUpdates, - eModeUpdates, - eModeAssets, - assetListing, - assetListingCustom, - PLACEHOLDER_MODULE, -]; + const baseName = generateFolderName(options); + const baseFolder = path.join(process.cwd(), 'src', baseName); -if (!configFileLoaded) { - for (const pool of options.pools) { - poolConfigs[pool] = {configs: {}, artifacts: [], features: []} as PoolConfig; - const v2 = isV2Pool(pool); - poolConfigs[pool]!.features = await checkbox({ - message: `What do you want to do on ${pool}?`, - choices: v2 ? FEATURE_MODULES_V2 : FEATURE_MODULES_V3, + if (!options.force && fs.existsSync(baseFolder)) { + options.force = await confirm({ + message: 'A proposal already exists at that location, do you want to override?', + default: false, }); - for (const feature of poolConfigs[pool]!.features) { - const module = v2 - ? FEATURE_MODULES_V2.find((m) => m.value === feature)! - : FEATURE_MODULES_V3.find((m) => m.value === feature)!; - poolConfigs[pool]!.configs[feature] = await module.cli(options, pool); - poolConfigs[pool]!.artifacts.push( - module.build(options, pool, poolConfigs[pool]!.configs[feature]) - ); - } - } -} else { - for (const pool of options.pools) { - const v2 = isV2Pool(pool); - poolConfigs[pool]!.artifacts = []; - for (const feature of poolConfigs[pool]!.features) { - const module = v2 - ? FEATURE_MODULES_V2.find((m) => m.value === feature)! - : FEATURE_MODULES_V3.find((m) => m.value === feature)!; - poolConfigs[pool]!.artifacts.push( - module.build(options, pool, poolConfigs[pool]!.configs[feature]) - ); - } } -} - -const logOptions = { - rootOptions: options, - poolOptions: Object.keys(poolConfigs).reduce((acc, pool) => { - acc[pool] = {configs: poolConfigs[pool].configs, features: poolConfigs[pool].features}; - return acc; - }, {} as PoolConfigs), -} as ConfigFile; - -const baseName = generateFolderName(options); -const baseFolder = path.join(process.cwd(), 'src', baseName); - -if (!options.force && fs.existsSync(baseFolder)) { - options.force = await confirm({ - message: 'A proposal already exists at that location, do you want to override?', - default: false, - }); -} -// create files -if (fs.existsSync(baseFolder) && !options.force) { - console.log('Creation skipped as folder already exists.'); - console.log('If you want to overwrite, supply --force'); -} else { - fs.mkdirSync(baseFolder, {recursive: true}); - fs.writeFileSync(path.join(baseFolder, 'config.json'), JSON.stringify(logOptions, null, 2)); - async function createFiles(options: Options, pool: PoolIdentifier) { + async function createPayloadAndTest(options: Options, pool: PoolIdentifier) { const contractName = generateContractName(options, pool); - fs.writeFileSync( - path.join(baseFolder, `${contractName}.sol`), - prettier.format(proposalTemplate(options, pool, poolConfigs[pool]?.artifacts), { + const testCode = await testTemplate(options, pool, poolConfigs[pool]?.artifacts); + return { + payload: prettier.format(proposalTemplate(options, pool, poolConfigs[pool]?.artifacts), { ...prettierSolCfg, filepath: 'foo.sol', - }) - ); - const testCode = await testTemplate(options, pool, poolConfigs[pool]?.artifacts); - fs.writeFileSync( - path.join(baseFolder, `${contractName}.t.sol`), - prettier.format(testCode, { + }), + test: prettier.format(testCode, { ...prettierSolCfg, filepath: 'foo.sol', - }) - ); + }), + contractName: contractName, + }; } - await Promise.all(options.pools.map((pool) => createFiles(options, pool))); - - fs.writeFileSync( - path.join(baseFolder, `${generateContractName(options)}.s.sol`), - prettier.format(generateScript(options), { + return { + jsonConfig, + script: prettier.format(generateScript(options), { ...prettierSolCfg, filepath: 'foo.sol', - }) - ); - fs.writeFileSync( - path.join(baseFolder, `${options.shortName}.md`), - prettier.format(generateAIP(options), { + }), + aip: prettier.format(generateAIP(options, poolConfigs), { ...prettierMDCfg, filepath: 'foo.md', - }) - ); + }), + payloads: await Promise.all(options.pools.map((pool) => createPayloadAndTest(options, pool))), + }; +} + +/** + * Writes the files according to defined folder/file format + * @param options + * @param param1 + */ +export async function writeFiles(options: Options, {jsonConfig, script, aip, payloads}: Files) { + const baseName = generateFolderName(options); + const baseFolder = path.join(process.cwd(), 'src', baseName); + if (!options.force && fs.existsSync(baseFolder)) { + options.force = await confirm({ + message: 'A proposal already exists at that location, do you want to override?', + default: false, + }); + } + if (fs.existsSync(baseFolder) && !options.force) { + console.log('Creation skipped as folder already exists.'); + console.log('If you want to overwrite, supply --force'); + } else { + fs.mkdirSync(baseFolder, {recursive: true}); + // write config + fs.writeFileSync(path.join(baseFolder, 'config.json'), jsonConfig); + // write aip + fs.writeFileSync(path.join(baseFolder, `${options.shortName}.md`), aip); + // write scripts + fs.writeFileSync(path.join(baseFolder, `${generateContractName(options)}.s.sol`), script); + + payloads.map(({payload, test, contractName}) => { + fs.writeFileSync(path.join(baseFolder, `${contractName}.sol`), payload); + fs.writeFileSync(path.join(baseFolder, `${contractName}.t.sol`), test); + }); + } } diff --git a/generator/prompts.ts b/generator/prompts.ts index ce7f68bd8..b1d2f91c6 100644 --- a/generator/prompts.ts +++ b/generator/prompts.ts @@ -146,7 +146,7 @@ interface AssetsSelectPrompt extends Exclude { + let template = `On ${pool} the following steps are performed:\n`; + template += configs[pool].artifacts + .filter((artifact) => artifact.aip) + .map((artifact) => artifact.aip); +})} + ## References - Implementation: ${options.pools .map( (pool) => - `[${pool}](https://github.com/bgd-labs/aave-proposals/blob/main/src/${generateFolderName( + `[${pool}](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/${generateFolderName( options )}/${generateContractName(options, pool)}.sol)` ) @@ -27,7 +34,7 @@ discussions: ${`"${options.discussion}"` || 'TODO'} - Tests: ${options.pools .map( (pool) => - `[${pool}](https://github.com/bgd-labs/aave-proposals/blob/main/src/${generateFolderName( + `[${pool}](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/${generateFolderName( options )}/${generateContractName(options, pool)}.t.sol)` ) diff --git a/generator/templates/proposal.template.ts b/generator/templates/proposal.template.ts index aaaac5314..54a011e5c 100644 --- a/generator/templates/proposal.template.ts +++ b/generator/templates/proposal.template.ts @@ -1,50 +1,7 @@ import {generateContractName, getPoolChain, getVersion, pragma} from '../common'; import {CodeArtifact, Options, PoolIdentifier} from '../types'; -import {prefixWithImports, prefixWithPragma} from './utils'; - -enum EngineImports { - IEngine = 'IEngine', - EngineFlags = 'EngineFlags', - Rates = 'Rates', -} - -enum LibraryImports { - Assets = 'Assets', - EModes = 'EModes', -} - -function getEngineDependencies(content: string) { - return Object.keys(EngineImports).filter((engineFlag) => - RegExp(engineFlag + '\\.', 'g').test(content) - ); -} - -function getPoolDependencies(pool: string, content: string) { - return [pool, ...Object.keys(LibraryImports).map((flag) => `${pool}${flag}`)].filter((library) => - RegExp(library + '\\.', 'g').test(content) - ); -} - -function getImports( - pool: PoolIdentifier, - engineDependencies: string[], - poolDependencies: string[] -) { - let template = ''; - const chain = getPoolChain(pool); - const version = getVersion(pool); - if (engineDependencies.length > 0) { - template += `import {Aave${version}Payload${chain}, ${engineDependencies.join( - ', ' - )}} from 'aave-helpers/${version.toLowerCase()}-config-engine/Aave${version}Payload${chain}.sol';`; - } else { - template += `import {IProposalGenericExecutor} from 'aave-helpers/interfaces/IProposalGenericExecutor.sol';\n`; - } - if (poolDependencies.length > 0) { - template += `import {${poolDependencies.join(', ')}} from 'aave-address-book/${pool}.sol';\n`; - } - return template; -} +import {prefixWithImports} from '../utils/importsResolver'; +import {prefixWithPragma} from './utils'; export const proposalTemplate = ( options: Options, @@ -71,8 +28,6 @@ export const proposalTemplate = ( .flat() .filter((f) => f !== undefined) .join('\n'); - const engineDependencies = getEngineDependencies(functions + innerExecute); - const poolDependencies = getPoolDependencies(pool, functions + innerExecute); let optionalExecute = ''; if (engineDependencies.length > 0) { @@ -101,9 +56,5 @@ export const proposalTemplate = ( ${functions} }`; - return prefixWithPragma( - prefixWithImports(`${getImports(pool, engineDependencies, poolDependencies)} - - ${contract}`) - ); + return prefixWithPragma(prefixWithImports(contract)); }; diff --git a/generator/templates/script.template.ts b/generator/templates/script.template.ts index d0b41f18b..96196549e 100644 --- a/generator/templates/script.template.ts +++ b/generator/templates/script.template.ts @@ -6,7 +6,8 @@ import { pragma, } from '../common'; import {Options} from '../types'; -import {prefixWithImports, prefixWithPragma} from './utils'; +import {prefixWithImports} from '../utils/importsResolver'; +import {prefixWithPragma} from './utils'; export function generateScript(options: Options) { const folderName = generateFolderName(options); diff --git a/generator/templates/test.template.ts b/generator/templates/test.template.ts index 57f4da3a8..22b3dc660 100644 --- a/generator/templates/test.template.ts +++ b/generator/templates/test.template.ts @@ -7,7 +7,8 @@ import { isV2Pool, } from '../common'; import {CodeArtifact, Options, PoolIdentifier} from '../types'; -import {prefixWithImports, prefixWithPragma} from './utils'; +import {prefixWithPragma} from './utils'; +import {prefixWithImports} from '../utils/importsResolver'; export const getBlock = async (chain) => { return await createPublicClient({ diff --git a/generator/templates/utils.ts b/generator/templates/utils.ts index 73dcae01e..352136f5d 100644 --- a/generator/templates/utils.ts +++ b/generator/templates/utils.ts @@ -3,27 +3,3 @@ import {pragma} from '../common'; export function prefixWithPragma(code: string) { return pragma + code; } - -const GovernanceImports = [ - 'GovV3Helpers', - 'IPayloadsControllerCore', - 'PayloadsControllerUtils', -] as const; - -function findMatches(code: string, needles: string[] | readonly string[]) { - return needles.filter((needle) => RegExp(needle + '\\.', 'g').test(code)); -} - -/** - * TODO: support more imports - * @param code - * @returns - */ -export function prefixWithImports(code: string) { - let imports = ''; - const govMatches = findMatches(code, GovernanceImports); - if (govMatches.length > 0) - imports += `import {${govMatches}} from 'aave-helpers/GovV3Helpers.sol';`; - - return imports; -} diff --git a/generator/types.ts b/generator/types.ts index cb02b076f..12474f352 100644 --- a/generator/types.ts +++ b/generator/types.ts @@ -10,6 +10,7 @@ export interface Options { discussion: string; snapshot: string; configFile: string; + date: string; } export interface PoolConfig { @@ -29,16 +30,29 @@ export type CodeArtifact = { test?: { fn?: string[]; }; + aip?: { + specification: string[]; + }; }; -export type Feature = { - name: string; - value: string; - module?: FeatureModule; -}; +export enum FEATURE { + ASSET_LISTING = 'ASSET_LISTING', + ASSET_LISTING_CUSTOM = 'ASSET_LISTING_CUSTOM', + BORROWS_UPDATE = 'BORROWS_UPDATE', + CAPS_UPDATE = 'CAPS_UPDATE', + COLLATERALS_UPDATE = 'COLLATERALS_UPDATE', + EMODES_ASSETS = 'EMODES_ASSETS', + EMODES_UPDATES = 'EMODES_UPDATES', + FLASH_BORROWER = 'FLASH_BORROWER', + PRICE_FEEDS_UPDATE = 'PRICE_FEEDS_UPDATE', + RATE_UPDATE_V3 = 'RATE_UPDATE_V3', + RATE_UPDATE_V2 = 'RATE_UPDATE_V2', + OTHERS = 'OTHERS', +} export interface FeatureModule { - value: string; + description: string; + value: FEATURE; cli: (opt: Options, pool: PoolIdentifier) => Promise; build: (opt: Options, pool: PoolIdentifier, cfg: T) => CodeArtifact; } diff --git a/generator/utils/importsResolver.spec.ts b/generator/utils/importsResolver.spec.ts new file mode 100644 index 000000000..e70ff2190 --- /dev/null +++ b/generator/utils/importsResolver.spec.ts @@ -0,0 +1,34 @@ +// sum.test.js +import {expect, describe, it} from 'vitest'; +import {prefixWithImports} from './importsResolver'; + +describe('prefixWithImports', () => { + it('should resolve Engine imports', () => { + expect(prefixWithImports(`GovV3Helpers.createPayload`)).toContain( + `import {GovV3Helpers} from 'aave-helpers/GovV3Helpers.sol';` + ); + }); + + it('should detect v3 Engine imports', () => { + expect(prefixWithImports(`EngineFlags.KEEP_CURRENT`)).toContain( + `import {EngineFlags} from 'aave-helpers/v3-config-engine/EngineFlags.sol';` + ); + + expect(prefixWithImports('IAaveV3ConfigEngine.CapsUpdate')).toContain( + `import {IAaveV3ConfigEngine} from 'aave-helpers/v3-config-engine/IAaveV3ConfigEngine.sol';` + ); + }); + + it('should detect v2 Engine imports', () => { + expect(prefixWithImports('IAaveV2ConfigEngine.RateStrategyUpdate')).toContain( + `import {IAaveV2ConfigEngine} from 'aave-helpers/v2-config-engine/IAaveV2ConfigEngine.sol';` + ); + }); + + it('should detect addressbook imports', () => { + console.log(prefixWithImports('AaveV2Ethereum.POOL AaveV2EthereumAssets.DAI')); + expect(prefixWithImports('AaveV2Ethereum.POOL AaveV2EthereumAssets.DAI')).toContain( + `import {AaveV2Ethereum,AaveV2EthereumAssets} from 'aave-address-book/AaveV2Ethereum.sol';` + ); + }); +}); diff --git a/generator/utils/importsResolver.ts b/generator/utils/importsResolver.ts new file mode 100644 index 000000000..a3fbaf767 --- /dev/null +++ b/generator/utils/importsResolver.ts @@ -0,0 +1,98 @@ +/** + * As a payload can consist of multiple features combined it's a mess to manage imports + * Therefore instead of maintaining imports, we just extract them from the generated code instead. + */ + +const GovernanceImports = [ + 'GovV3Helpers', + 'IPayloadsControllerCore', + 'PayloadsControllerUtils', +] as const; + +/** + * @dev matches the code fro known address book imports and generates an import statment satisfying the used libraries + * @param code + * @returns + */ +function generateAddressBookImports(code: string) { + const imports: string[] = []; + let root = ''; + const addressBookMatch = code.match(/(AaveV[2..3][A-Z][a-z]+)\./); + if (addressBookMatch) { + imports.push(addressBookMatch[1]); + root = addressBookMatch[1]; + } + const assetsMatch = code.match(/(AaveV[2..3][A-Z][a-z]+)Assets\./); + if (assetsMatch) { + imports.push(assetsMatch[1] + 'Assets'); + root = assetsMatch[1]; + } + const eModesMatch = code.match(/(AaveV[2..3][A-Z][a-z]+)EModes\./); + if (eModesMatch) { + imports.push(eModesMatch[1] + 'EModes'); + root = eModesMatch[1]; + } + if (imports.length > 0) return `import {${imports}} from 'aave-address-book/${root}.sol';\n`; +} + +function generateEngineImport(code: string) { + const matches = code.match(/Aave(V[2..3])Payload([A-Z][a-z]+)/g); + if (matches) + return `import {${matches[0]}} from 'aave-helpers/${matches[1].toLowerCase()}-config-engine/${ + matches[0] + }';\n`; +} + +function findMatches(code: string, needles: string[] | readonly string[]) { + return needles.filter((needle) => RegExp(needle + '\\.', 'g').test(code)); +} + +function findMatch(code: string, needle: string) { + return RegExp(needle + '\\.', 'g').test(code); +} + +/** + * @dev Returnes the input string prefixed with imports + * @param code + * @returns + */ +export function prefixWithImports(code: string) { + let imports = ''; + const govMatches = findMatches(code, GovernanceImports); + // gov related imports + if (govMatches.length > 0) + imports += `import {${govMatches}} from 'aave-helpers/GovV3Helpers.sol';\n`; + // address book imports + const addressBookImports = generateAddressBookImports(code); + if (addressBookImports) { + imports += addressBookImports; + } + // generic Executor + if (findMatch(code, 'IProposalGenericExecutor')) { + imports += `import {IProposalGenericExecutor} from 'aave-helpers/interfaces/IProposalGenericExecutor.sol';\n`; + } + const configEngineImport = generateEngineImport(code); + if (configEngineImport) { + imports += configEngineImport; + } + // shared config engine imports + if (findMatch(code, 'EngineFlags')) { + imports += `import {EngineFlags} from 'aave-helpers/v3-config-engine/EngineFlags.sol';\n`; + } + // v3 config engine imports + if (findMatch(code, 'IAaveV3ConfigEngine')) { + imports += `import {IAaveV3ConfigEngine} from 'aave-helpers/v3-config-engine/IAaveV3ConfigEngine.sol';\n`; + } + if (findMatch(code, 'IV3RateStrategyFactory')) { + imports += `import {IV3RateStrategyFactory} from 'aave-helpers/v3-config-engine/IV3RateStrategyFactory.sol';\n`; + } + // v2 config engine imports + if (findMatch(code, 'IAaveV2ConfigEngine')) { + imports += `import {IAaveV2ConfigEngine} from 'aave-helpers/v2-config-engine/IAaveV2ConfigEngine.sol';\n`; + } + if (findMatch(code, 'IV2RateStrategyFactory')) { + imports += `import {IV2RateStrategyFactory} from 'aave-helpers/v2-config-engine/IV2RateStrategyFactory.sol';\n`; + } + + return imports + code; +} diff --git a/package.json b/package.json index de9e8b1b2..e008ca8f4 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,11 @@ "name": "bgd-forge-template", "version": "1.0.0", "scripts": { + "test": "vitest generator", "lint": "prettier ./", "lint:fix": "npm run lint -- --write", - "generate": "tsx generator/generator", - "generate:bgd": "tsx generator/generator -a 'BGD labs'" + "generate": "tsx generator/cli", + "generate:bgd": "tsx generator/cli -a 'BGD labs'" }, "engines": { "node": ">=18.0.0" @@ -24,7 +25,8 @@ "homepage": "https://github.com/bgd-labs/aave-proposals-v3#readme", "devDependencies": { "prettier": "2.8.7", - "prettier-plugin-solidity": "1.1.3" + "prettier-plugin-solidity": "1.1.3", + "vitest": "^0.34.6" }, "dependencies": { "@bgd-labs/aave-address-book": "^2.7.0", diff --git a/yarn.lock b/yarn.lock index 8f8c19620..d528b1e5b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -294,6 +294,18 @@ resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.1.5.tgz#b8c171f755859c8159b10e41e1e3a88f0ca99d7f" integrity sha512-wmwHvHozpPo4IZkkNtbYenem/0wnfI6hvOcGKmPEa0DwuaH5XUQzFqy6OpEpjEegZMhYIk8HDYITI16BPLtrRA== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jridgewell/sourcemap-codec@^1.4.15": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + "@multiformats/base-x@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121" @@ -386,6 +398,11 @@ "@noble/hashes" "~1.3.0" "@scure/base" "~1.1.0" +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + "@solidity-parser/parser@^0.16.0": version "0.16.0" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.16.0.tgz#1fb418c816ca1fc3a1e94b08bcfe623ec4e1add4" @@ -393,6 +410,18 @@ dependencies: antlr4ts "^0.5.0-alpha.4" +"@types/chai-subset@^1.3.3": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.4.tgz#7938fa929dd12db451457e4d6faa27bcd599a729" + integrity sha512-CCWNXrJYSUIojZ1149ksLl3AN9cmZ5djf+yUoVVV+NuYrtydItQVlL2ZDqyC6M6O9LWRnVf8yYDxbXHO2TfQZg== + dependencies: + "@types/chai" "*" + +"@types/chai@*", "@types/chai@^4.3.5": + version "4.3.9" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.9.tgz#144d762491967db8c6dea38e03d2206c2623feec" + integrity sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg== + "@types/long@^4.0.1": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" @@ -427,11 +456,64 @@ resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== +"@vitest/expect@0.34.6": + version "0.34.6" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.34.6.tgz#608a7b7a9aa3de0919db99b4cc087340a03ea77e" + integrity sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw== + dependencies: + "@vitest/spy" "0.34.6" + "@vitest/utils" "0.34.6" + chai "^4.3.10" + +"@vitest/runner@0.34.6": + version "0.34.6" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-0.34.6.tgz#6f43ca241fc96b2edf230db58bcde5b974b8dcaf" + integrity sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ== + dependencies: + "@vitest/utils" "0.34.6" + p-limit "^4.0.0" + pathe "^1.1.1" + +"@vitest/snapshot@0.34.6": + version "0.34.6" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-0.34.6.tgz#b4528cf683b60a3e8071cacbcb97d18b9d5e1d8b" + integrity sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w== + dependencies: + magic-string "^0.30.1" + pathe "^1.1.1" + pretty-format "^29.5.0" + +"@vitest/spy@0.34.6": + version "0.34.6" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-0.34.6.tgz#b5e8642a84aad12896c915bce9b3cc8cdaf821df" + integrity sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ== + dependencies: + tinyspy "^2.1.1" + +"@vitest/utils@0.34.6": + version "0.34.6" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-0.34.6.tgz#38a0a7eedddb8e7291af09a2409cb8a189516968" + integrity sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A== + dependencies: + diff-sequences "^29.4.3" + loupe "^2.3.6" + pretty-format "^29.5.0" + abitype@0.9.8: version "0.9.8" resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c" integrity sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ== +acorn-walk@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.10.0, acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + ansi-escapes@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -458,6 +540,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" @@ -475,6 +562,11 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + base-x@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" @@ -524,6 +616,11 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -538,6 +635,19 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +chai@^4.3.10: + version "4.3.10" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" + integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -560,6 +670,13 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + cids@^1.0.0, cids@^1.1.5, cids@^1.1.6: version "1.1.9" resolved "https://registry.yarnpkg.com/cids/-/cids-1.1.9.tgz#402c26db5c07059377bcd6fb82f2a24e7f2f4a4f" @@ -609,7 +726,7 @@ commander@^11.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== -debug@^4.3.1: +debug@^4.3.1, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -629,11 +746,23 @@ decamelize@^1.1.0, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== +deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== +diff-sequences@^29.4.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + dotenv@^16.3.1: version "16.3.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" @@ -656,7 +785,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -esbuild@~0.18.20: +esbuild@^0.18.10, esbuild@~0.18.20: version "0.18.20" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== @@ -725,11 +854,16 @@ find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -fsevents@~2.3.3: +fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + get-tsconfig@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" @@ -956,6 +1090,11 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -966,6 +1105,11 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +local-pkg@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963" + integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g== + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -978,6 +1122,13 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -985,6 +1136,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +magic-string@^0.30.1: + version "0.30.5" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" + integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -1039,6 +1197,16 @@ minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +mlly@^1.2.0, mlly@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.4.2.tgz#7cf406aa319ff6563d25da6b36610a93f2a8007e" + integrity sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg== + dependencies: + acorn "^8.10.0" + pathe "^1.1.1" + pkg-types "^1.0.3" + ufo "^1.3.0" + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -1095,6 +1263,11 @@ mute-stream@^1.0.0: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + node-fetch@^2.6.1, node-fetch@^2.6.9: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -1139,6 +1312,13 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" + integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== + dependencies: + yocto-queue "^1.0.0" + p-locate@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" @@ -1171,6 +1351,39 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +pathe@^1.1.0, pathe@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a" + integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +pkg-types@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" + integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== + dependencies: + jsonc-parser "^3.2.0" + mlly "^1.2.0" + pathe "^1.1.0" + +postcss@^8.4.27: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + prettier-plugin-solidity@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz#9a35124f578404caf617634a8cab80862d726cba" @@ -1185,6 +1398,15 @@ prettier@2.8.7: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450" integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw== +pretty-format@^29.5.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + protobufjs@^6.10.2: version "6.11.4" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.4.tgz#29a412c38bf70d89e537b6d02d904a6f448173aa" @@ -1221,6 +1443,11 @@ rabin-wasm@^0.1.4: node-fetch "^2.6.1" readable-stream "^3.6.0" +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -1271,6 +1498,13 @@ resolve@^1.10.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +rollup@^3.27.1: + version "3.29.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" + integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== + optionalDependencies: + fsevents "~2.3.2" + run-async@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad" @@ -1313,6 +1547,11 @@ semver@^7.3.8: dependencies: lru-cache "^6.0.0" +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" @@ -1323,6 +1562,11 @@ solidity-comments-extractor@^0.0.7: resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-support@^0.5.21: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -1377,6 +1621,16 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.3.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.4.3.tgz#326f11db518db751c83fd58574f449b7c3060910" + integrity sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q== + string-width@^4.1.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -1412,6 +1666,13 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" +strip-literal@^1.0.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-1.3.0.tgz#db3942c2ec1699e6836ad230090b84bb458e3a07" + integrity sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg== + dependencies: + acorn "^8.10.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -1431,6 +1692,21 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +tinybench@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.5.1.tgz#3408f6552125e53a5a48adee31261686fd71587e" + integrity sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg== + +tinypool@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.7.0.tgz#88053cc99b4a594382af23190c609d93fddf8021" + integrity sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww== + +tinyspy@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.0.tgz#9dc04b072746520b432f77ea2c2d17933de5d6ce" + integrity sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -1459,6 +1735,11 @@ tsx@^3.13.0: optionalDependencies: fsevents "~2.3.3" +type-detect@^4.0.0, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.18.0: version "0.18.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" @@ -1479,6 +1760,11 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +ufo@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.1.tgz#e085842f4627c41d4c1b60ebea1f75cdab4ce86b" + integrity sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw== + uint8arrays@^2.0.5, uint8arrays@^2.1.2: version "2.1.10" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-2.1.10.tgz#34d023c843a327c676e48576295ca373c56e286a" @@ -1535,6 +1821,59 @@ viem@^1.15.1, viem@^1.16.4: isows "1.0.3" ws "8.13.0" +vite-node@0.34.6: + version "0.34.6" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.34.6.tgz#34d19795de1498562bf21541a58edcd106328a17" + integrity sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA== + dependencies: + cac "^6.7.14" + debug "^4.3.4" + mlly "^1.4.0" + pathe "^1.1.1" + picocolors "^1.0.0" + vite "^3.0.0 || ^4.0.0 || ^5.0.0-0" + +"vite@^3.0.0 || ^4.0.0 || ^5.0.0-0", "vite@^3.1.0 || ^4.0.0 || ^5.0.0-0": + version "4.4.11" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.11.tgz#babdb055b08c69cfc4c468072a2e6c9ca62102b0" + integrity sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + +vitest@^0.34.6: + version "0.34.6" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-0.34.6.tgz#44880feeeef493c04b7f795ed268f24a543250d7" + integrity sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q== + dependencies: + "@types/chai" "^4.3.5" + "@types/chai-subset" "^1.3.3" + "@types/node" "*" + "@vitest/expect" "0.34.6" + "@vitest/runner" "0.34.6" + "@vitest/snapshot" "0.34.6" + "@vitest/spy" "0.34.6" + "@vitest/utils" "0.34.6" + acorn "^8.9.0" + acorn-walk "^8.2.0" + cac "^6.7.14" + chai "^4.3.10" + debug "^4.3.4" + local-pkg "^0.4.3" + magic-string "^0.30.1" + pathe "^1.1.1" + picocolors "^1.0.0" + std-env "^3.3.3" + strip-literal "^1.0.1" + tinybench "^2.5.0" + tinypool "^0.7.0" + vite "^3.1.0 || ^4.0.0 || ^5.0.0-0" + vite-node "0.34.6" + why-is-node-running "^2.2.2" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -1548,6 +1887,14 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +why-is-node-running@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.2.2.tgz#4185b2b4699117819e7154594271e7e344c9973e" + integrity sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -1572,6 +1919,11 @@ yargs-parser@^20.2.3: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yocto-queue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" + integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== + zod@^3.22.3: version "3.22.4" resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" From 156fcd06452794e756953b0b4897b13baaef01d9 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Thu, 19 Oct 2023 22:30:08 +0200 Subject: [PATCH 06/18] fix: patch some more generator quirks --- generator/cli.ts | 3 +- generator/common.ts | 3 -- generator/generator.ts | 5 ++-- generator/templates/aip.template.ts | 2 +- generator/templates/proposal.template.ts | 37 ++++++++++++------------ generator/templates/script.template.ts | 8 +---- generator/templates/test.template.ts | 21 +++++--------- generator/templates/utils.ts | 7 +++-- generator/types.ts | 13 +++++---- generator/utils/importsResolver.ts | 6 ++-- 10 files changed, 48 insertions(+), 57 deletions(-) diff --git a/generator/cli.ts b/generator/cli.ts index 8aa217aee..6f5bf088a 100644 --- a/generator/cli.ts +++ b/generator/cli.ts @@ -81,6 +81,7 @@ if (options.configFile) { const module = v2 ? FEATURE_MODULES_V2.find((m) => m.value === feature)! : FEATURE_MODULES_V3.find((m) => m.value === feature)!; + poolConfigs[pool]!.pool = pool; poolConfigs[pool]!.artifacts.push( module.build(options, pool, poolConfigs[pool]!.configs[feature]) ); @@ -136,7 +137,7 @@ if (options.configFile) { } for (const pool of options.pools) { - poolConfigs[pool] = {configs: {}, artifacts: [], features: []} as PoolConfig; + poolConfigs[pool] = {configs: {}, artifacts: [], features: [], pool} as PoolConfig; const v2 = isV2Pool(pool); poolConfigs[pool]!.features = await checkbox({ message: `What do you want to do on ${pool}?`, diff --git a/generator/common.ts b/generator/common.ts index 4bd368658..fd1f63d31 100644 --- a/generator/common.ts +++ b/generator/common.ts @@ -104,9 +104,6 @@ export function pascalCase(str: string) { .replace(/ /g, ''); } -export const pragma = `// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0;\n\n`; - export const CHAIN_TO_CHAIN_OBJECT = { Ethereum: mainnet, Polygon: polygon, diff --git a/generator/generator.ts b/generator/generator.ts index 88c2bf950..cd0a8d331 100644 --- a/generator/generator.ts +++ b/generator/generator.ts @@ -49,9 +49,9 @@ export async function generateFiles(options: Options, poolConfigs: PoolConfigs): } async function createPayloadAndTest(options: Options, pool: PoolIdentifier) { const contractName = generateContractName(options, pool); - const testCode = await testTemplate(options, pool, poolConfigs[pool]?.artifacts); + const testCode = await testTemplate(options, poolConfigs[pool]!); return { - payload: prettier.format(proposalTemplate(options, pool, poolConfigs[pool]?.artifacts), { + payload: prettier.format(proposalTemplate(options, poolConfigs[pool]!), { ...prettierSolCfg, filepath: 'foo.sol', }), @@ -83,6 +83,7 @@ export async function generateFiles(options: Options, poolConfigs: PoolConfigs): * @param param1 */ export async function writeFiles(options: Options, {jsonConfig, script, aip, payloads}: Files) { + console.log(options); const baseName = generateFolderName(options); const baseFolder = path.join(process.cwd(), 'src', baseName); if (!options.force && fs.existsSync(baseFolder)) { diff --git a/generator/templates/aip.template.ts b/generator/templates/aip.template.ts index 6af8b83d2..9401c82f8 100644 --- a/generator/templates/aip.template.ts +++ b/generator/templates/aip.template.ts @@ -1,5 +1,5 @@ import {generateContractName, generateFolderName} from '../common'; -import {CodeArtifact, Options, PoolConfigs} from '../types'; +import {Options, PoolConfigs} from '../types'; export function generateAIP(options: Options, configs: PoolConfigs) { return `--- diff --git a/generator/templates/proposal.template.ts b/generator/templates/proposal.template.ts index 54a011e5c..dcd2e91bb 100644 --- a/generator/templates/proposal.template.ts +++ b/generator/templates/proposal.template.ts @@ -1,43 +1,44 @@ -import {generateContractName, getPoolChain, getVersion, pragma} from '../common'; -import {CodeArtifact, Options, PoolIdentifier} from '../types'; +import {generateContractName, getPoolChain, getVersion} from '../common'; +import {FEATURE, Options, PoolConfig} from '../types'; import {prefixWithImports} from '../utils/importsResolver'; import {prefixWithPragma} from './utils'; -export const proposalTemplate = ( - options: Options, - pool: PoolIdentifier, - artifacts: CodeArtifact[] = [] -) => { +export const proposalTemplate = (options: Options, poolConfig: PoolConfig) => { const {title, author, snapshot, discussion} = options; - const chain = getPoolChain(pool); - const version = getVersion(pool); - const contractName = generateContractName(options, pool); + const chain = getPoolChain(poolConfig.pool); + const version = getVersion(poolConfig.pool); + const contractName = generateContractName(options, poolConfig.pool); - const constants = artifacts + const constants = poolConfig.artifacts .map((artifact) => artifact.code?.constants) .flat() .filter((f) => f !== undefined) .join('\n'); - const functions = artifacts + const functions = poolConfig.artifacts .map((artifact) => artifact.code?.fn) .flat() .filter((f) => f !== undefined) .join('\n'); - const innerExecute = artifacts + const innerExecute = poolConfig.artifacts .map((artifact) => artifact.code?.execute) .flat() .filter((f) => f !== undefined) .join('\n'); let optionalExecute = ''; - if (engineDependencies.length > 0) { - optionalExecute = `function _preExecute() internal override { + const usesConfigEngine = poolConfig.features.some( + (f) => ![FEATURE.OTHERS, FEATURE.FLASH_BORROWER].includes(f) + ); + if (innerExecute) { + if (usesConfigEngine) { + optionalExecute = `function _preExecute() internal override { ${innerExecute} }`; - } else { - optionalExecute = `function execute() external { + } else { + optionalExecute = `function execute() external { ${innerExecute} }`; + } } const contract = `/** @@ -47,7 +48,7 @@ export const proposalTemplate = ( * - Discussion: ${discussion || 'TODO'} */ contract ${contractName} is ${ - engineDependencies.length > 0 ? `Aave${version}Payload${chain}` : 'IProposalGenericExecutor' + usesConfigEngine ? `Aave${version}Payload${chain}` : 'IProposalGenericExecutor' } { ${constants} diff --git a/generator/templates/script.template.ts b/generator/templates/script.template.ts index 96196549e..bc0376d06 100644 --- a/generator/templates/script.template.ts +++ b/generator/templates/script.template.ts @@ -1,10 +1,4 @@ -import { - generateContractName, - generateFolderName, - getChainAlias, - getPoolChain, - pragma, -} from '../common'; +import {generateContractName, generateFolderName, getChainAlias, getPoolChain} from '../common'; import {Options} from '../types'; import {prefixWithImports} from '../utils/importsResolver'; import {prefixWithPragma} from './utils'; diff --git a/generator/templates/test.template.ts b/generator/templates/test.template.ts index 22b3dc660..47dc86896 100644 --- a/generator/templates/test.template.ts +++ b/generator/templates/test.template.ts @@ -6,7 +6,7 @@ import { getPoolChain, isV2Pool, } from '../common'; -import {CodeArtifact, Options, PoolIdentifier} from '../types'; +import {Options, PoolConfig} from '../types'; import {prefixWithPragma} from './utils'; import {prefixWithImports} from '../utils/importsResolver'; @@ -17,24 +17,19 @@ export const getBlock = async (chain) => { }).getBlockNumber(); }; -export const testTemplate = async ( - options: Options, - pool: PoolIdentifier, - artifacts: CodeArtifact[] = [] -) => { - const chain = getPoolChain(pool); - const contractName = generateContractName(options, pool); +export const testTemplate = async (options: Options, poolConfig: PoolConfig) => { + const chain = getPoolChain(poolConfig.pool); + const contractName = generateContractName(options, poolConfig.pool); - const testBase = isV2Pool(pool) ? 'ProtocolV2TestBase' : 'ProtocolV3TestBase'; + const testBase = isV2Pool(poolConfig.pool) ? 'ProtocolV2TestBase' : 'ProtocolV3TestBase'; - const functions = artifacts + const functions = poolConfig.artifacts .map((artifact) => artifact.test?.fn) .flat() .filter((f) => f !== undefined) .join('\n'); let template = ` import 'forge-std/Test.sol'; -import {${pool}, ${pool}Assets} from 'aave-address-book/${pool}.sol'; import {${testBase}, ReserveConfig} from 'aave-helpers/${testBase}.sol'; import {${contractName}} from './${contractName}.sol'; @@ -53,7 +48,7 @@ contract ${contractName}_Test is ${testBase} { function testProposalExecution() public { ReserveConfig[] memory allConfigsBefore = createConfigurationSnapshot( 'pre${contractName}', - ${pool}.POOL + ${poolConfig.pool}.POOL ); GovV3Helpers.executePayload( @@ -63,7 +58,7 @@ contract ${contractName}_Test is ${testBase} { ReserveConfig[] memory allConfigsAfter = createConfigurationSnapshot( 'post${contractName}', - ${pool}.POOL + ${poolConfig.pool}.POOL ); diffReports('pre${contractName}', 'post${contractName}'); diff --git a/generator/templates/utils.ts b/generator/templates/utils.ts index 352136f5d..365b248b9 100644 --- a/generator/templates/utils.ts +++ b/generator/templates/utils.ts @@ -1,5 +1,6 @@ -import {pragma} from '../common'; - export function prefixWithPragma(code: string) { - return pragma + code; + return ( + `// SPDX-License-Identifier: MIT + pragma solidity ^0.8.0;\n\n` + code + ); } diff --git a/generator/types.ts b/generator/types.ts index 12474f352..28284cf50 100644 --- a/generator/types.ts +++ b/generator/types.ts @@ -13,12 +13,6 @@ export interface Options { date: string; } -export interface PoolConfig { - features: string[]; - artifacts: CodeArtifact[]; - configs: {[feature: string]: {}}; -} - export type PoolConfigs = Partial>; export type CodeArtifact = { @@ -96,3 +90,10 @@ export type ConfigFile = { rootOptions: Options; poolOptions: Record>; }; + +export interface PoolConfig { + pool: PoolIdentifier; + features: FEATURE[]; + artifacts: CodeArtifact[]; + configs: {[feature in FEATURE]?: any}; +} diff --git a/generator/utils/importsResolver.ts b/generator/utils/importsResolver.ts index a3fbaf767..39d97aef2 100644 --- a/generator/utils/importsResolver.ts +++ b/generator/utils/importsResolver.ts @@ -36,11 +36,11 @@ function generateAddressBookImports(code: string) { } function generateEngineImport(code: string) { - const matches = code.match(/Aave(V[2..3])Payload([A-Z][a-z]+)/g); - if (matches) + const matches = [...code.matchAll(/Aave(V[2..3])Payload([A-Z][a-z]+)/g)].flat(); + if (matches.length > 0) return `import {${matches[0]}} from 'aave-helpers/${matches[1].toLowerCase()}-config-engine/${ matches[0] - }';\n`; + }.sol';\n`; } function findMatches(code: string, needles: string[] | readonly string[]) { From 67b1b582073da24f02d7876e18272b8121b1a8b3 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Mon, 23 Oct 2023 10:01:24 +0200 Subject: [PATCH 07/18] fix: add transfer of 1 uint into post execution --- generator/features/assetListing.ts | 23 +++++++++++++++++++++++ generator/templates/proposal.template.ts | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/generator/features/assetListing.ts b/generator/features/assetListing.ts index db193c9b0..0097cbc96 100644 --- a/generator/features/assetListing.ts +++ b/generator/features/assetListing.ts @@ -27,6 +27,20 @@ async function fetchListing(pool: PoolIdentifier): Promise { stateMutability: 'view', type: 'function', }, + { + constant: true, + inputs: [], + name: 'decimals', + outputs: [ + { + name: '', + type: 'uint8', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, ], publicClient: CHAIN_TO_CHAIN_OBJECT[chain] as PublicClient, address: asset, @@ -37,6 +51,12 @@ async function fetchListing(pool: PoolIdentifier): Promise { } catch (e) { console.log('could not fetch the symbol - this is likely an error'); } + let decimals = 0; + try { + decimals = await erc20.read.decimals(); + } catch (e) { + console.log('could not fetch the symbol - this is likely an error'); + } return { assetSymbol: await stringInput({ @@ -85,6 +105,9 @@ export const assetListing: FeatureModule = { constants: cfg.map( (cfg) => `address public constant ${cfg.assetSymbol} = address(${cfg.asset});` ), + execute: cfg.map( + (cfg) => `${pool}.POOL.supply(${cfg.assetSymbol}, 10 ** ${cfg}, ${pool}.COLLECTOR, 0);` + ), fn: [ `function newListings() public pure override returns (IEngine.Listing[] memory) { IEngine.Listing[] memory listings = new IEngine.Listing[](${cfg.length}); diff --git a/generator/templates/proposal.template.ts b/generator/templates/proposal.template.ts index dcd2e91bb..f82a58e71 100644 --- a/generator/templates/proposal.template.ts +++ b/generator/templates/proposal.template.ts @@ -31,7 +31,7 @@ export const proposalTemplate = (options: Options, poolConfig: PoolConfig) => { ); if (innerExecute) { if (usesConfigEngine) { - optionalExecute = `function _preExecute() internal override { + optionalExecute = `function _postExecute() internal override { ${innerExecute} }`; } else { From 1ecfd9ef9146c089ab6bd4c12bc1d2da5930cd41 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Mon, 23 Oct 2023 15:41:08 +0200 Subject: [PATCH 08/18] feat: add asset listing test --- generator/features/assetListing.ts | 17 ++++++++++++- generator/features/flashBorrower.ts | 6 ++--- generator/features/types.ts | 1 + generator/templates/proposal.template.ts | 2 +- generator/templates/script.template.ts | 2 +- generator/templates/test.template.ts | 24 +++++-------------- .../utils.ts => utils/constants.ts} | 5 ++++ lib/aave-helpers | 2 +- 8 files changed, 33 insertions(+), 26 deletions(-) rename generator/{templates/utils.ts => utils/constants.ts} (58%) diff --git a/generator/features/assetListing.ts b/generator/features/assetListing.ts index 0097cbc96..1afe6859b 100644 --- a/generator/features/assetListing.ts +++ b/generator/features/assetListing.ts @@ -8,6 +8,7 @@ import {Listing, ListingWithCustomImpl, TokenImplementations} from './types'; import {CHAIN_TO_CHAIN_OBJECT, getPoolChain} from '../common'; import {PublicClient, getContract} from 'viem'; import {confirm} from '@inquirer/prompts'; +import {TEST_EXECUTE_PROPOSAL} from '../utils/constants'; async function fetchListing(pool: PoolIdentifier): Promise { const asset = await addressInput({ @@ -64,6 +65,7 @@ async function fetchListing(pool: PoolIdentifier): Promise { disableKeepCurrent: true, defaultValue: symbol, }), + decimals, priceFeed: await addressInput({message: 'PriceFeed address', disableKeepCurrent: true}), ...(await fetchCollateralUpdate(pool, true)), ...(await fetchBorrowUpdate(true)), @@ -106,7 +108,8 @@ export const assetListing: FeatureModule = { (cfg) => `address public constant ${cfg.assetSymbol} = address(${cfg.asset});` ), execute: cfg.map( - (cfg) => `${pool}.POOL.supply(${cfg.assetSymbol}, 10 ** ${cfg}, ${pool}.COLLECTOR, 0);` + (cfg) => + `${pool}.POOL.supply(${cfg.assetSymbol}, 10 ** ${cfg.decimals}, ${pool}.COLLECTOR, 0);` ), fn: [ `function newListings() public pure override returns (IEngine.Listing[] memory) { @@ -174,6 +177,10 @@ export const assetListingCustom: FeatureModule = { constants: cfg.map( (cfg) => `address public constant ${cfg.base.assetSymbol} = address(${cfg.base.asset});` ), + execute: cfg.map( + (cfg) => + `${pool}.POOL.supply(${cfg.base.assetSymbol}, 10 ** ${cfg.base.decimals}, ${pool}.COLLECTOR, 0);` + ), fn: [ `function newListingsCustom() public pure override returns (IEngine.ListingWithCustomImpl[] memory) { IEngine.ListingWithCustomImpl[] memory listings = new IEngine.ListingWithCustomImpl[](${ @@ -226,6 +233,14 @@ export const assetListingCustom: FeatureModule = { }`, ], }, + test: { + fn: cfg.map( + (cfg) => `function test_collectorHas${cfg.base.assetSymbol}Funds() public { + ${TEST_EXECUTE_PROPOSAL} + assertGte(IERC20(${cfg.base.asset}).balanceOf(${pool}.COLLECTOR), 10 ** ${cfg.base.decimals}); + }` + ), + }, }; return response; }, diff --git a/generator/features/flashBorrower.ts b/generator/features/flashBorrower.ts index 0eef49bed..cbf837c32 100644 --- a/generator/features/flashBorrower.ts +++ b/generator/features/flashBorrower.ts @@ -1,6 +1,7 @@ import {CodeArtifact, FEATURE, FeatureModule} from '../types'; import {addressInput} from '../prompts'; import {Hex} from 'viem'; +import {TEST_EXECUTE_PROPOSAL} from '../utils/constants'; type FlashBorrower = { address: Hex; @@ -28,10 +29,7 @@ export const flashBorrower: FeatureModule = { test: { fn: [ `function test_isFlashBorrower() external { - GovV3Helpers.executePayload( - vm, - address(proposal) - ); + ${TEST_EXECUTE_PROPOSAL} bool isFlashBorrower = ${pool}.ACL_MANAGER.isFlashBorrower(proposal.NEW_FLASH_BORROWER()); assertEq(isFlashBorrower, true); }`, diff --git a/generator/features/types.ts b/generator/features/types.ts index 6dd6b0cbd..94f565e23 100644 --- a/generator/features/types.ts +++ b/generator/features/types.ts @@ -90,6 +90,7 @@ export interface Listing assetSymbol: string; rateStrategyParams: RateStrategyParams; eModeCategory: string; + decimals: number; } export interface ListingWithCustomImpl { diff --git a/generator/templates/proposal.template.ts b/generator/templates/proposal.template.ts index f82a58e71..97ad23f80 100644 --- a/generator/templates/proposal.template.ts +++ b/generator/templates/proposal.template.ts @@ -1,7 +1,7 @@ import {generateContractName, getPoolChain, getVersion} from '../common'; import {FEATURE, Options, PoolConfig} from '../types'; import {prefixWithImports} from '../utils/importsResolver'; -import {prefixWithPragma} from './utils'; +import {prefixWithPragma} from '../utils/constants'; export const proposalTemplate = (options: Options, poolConfig: PoolConfig) => { const {title, author, snapshot, discussion} = options; diff --git a/generator/templates/script.template.ts b/generator/templates/script.template.ts index bc0376d06..b26f1aaff 100644 --- a/generator/templates/script.template.ts +++ b/generator/templates/script.template.ts @@ -1,7 +1,7 @@ import {generateContractName, generateFolderName, getChainAlias, getPoolChain} from '../common'; import {Options} from '../types'; import {prefixWithImports} from '../utils/importsResolver'; -import {prefixWithPragma} from './utils'; +import {prefixWithPragma} from '../utils/constants'; export function generateScript(options: Options) { const folderName = generateFolderName(options); diff --git a/generator/templates/test.template.ts b/generator/templates/test.template.ts index 47dc86896..72823d634 100644 --- a/generator/templates/test.template.ts +++ b/generator/templates/test.template.ts @@ -7,7 +7,7 @@ import { isV2Pool, } from '../common'; import {Options, PoolConfig} from '../types'; -import {prefixWithPragma} from './utils'; +import {prefixWithPragma} from '../utils/constants'; import {prefixWithImports} from '../utils/importsResolver'; export const getBlock = async (chain) => { @@ -45,23 +45,11 @@ contract ${contractName}_Test is ${testBase} { proposal = new ${contractName}(); } - function testProposalExecution() public { - ReserveConfig[] memory allConfigsBefore = createConfigurationSnapshot( - 'pre${contractName}', - ${poolConfig.pool}.POOL - ); - - GovV3Helpers.executePayload( - vm, - address(proposal) - ); - - ReserveConfig[] memory allConfigsAfter = createConfigurationSnapshot( - 'post${contractName}', - ${poolConfig.pool}.POOL - ); - - diffReports('pre${contractName}', 'post${contractName}'); + /** + * @dev executes the generic test suite including e2e and config snapshots + */ + function test_defaultProposalExecution() public { + defaultTest('${contractName}', ${poolConfig.pool}.POOL, address(proposal)); } ${functions} diff --git a/generator/templates/utils.ts b/generator/utils/constants.ts similarity index 58% rename from generator/templates/utils.ts rename to generator/utils/constants.ts index 365b248b9..4a231e9b2 100644 --- a/generator/templates/utils.ts +++ b/generator/utils/constants.ts @@ -4,3 +4,8 @@ export function prefixWithPragma(code: string) { pragma solidity ^0.8.0;\n\n` + code ); } + +export const TEST_EXECUTE_PROPOSAL = `GovV3Helpers.executePayload( + vm, + address(proposal) +);`; diff --git a/lib/aave-helpers b/lib/aave-helpers index 5b0231825..f6a905a6c 160000 --- a/lib/aave-helpers +++ b/lib/aave-helpers @@ -1 +1 @@ -Subproject commit 5b02318257d45b47bdaa38c0183840cc78fb01a3 +Subproject commit f6a905a6c2b2f4e1fd00c30d4f5f86ea275756e9 From 45d56e39eda0dfb1201d3c2fb359212b76276647 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Mon, 23 Oct 2023 16:05:54 +0200 Subject: [PATCH 09/18] fix: another bunch of fixes --- generator/features/assetListing.spec.ts | 10 ++++++++++ generator/features/assetListing.ts | 21 +++++++++++++-------- generator/features/borrowsUpdates.ts | 5 ++++- generator/features/rateUpdates.ts | 2 +- package.json | 2 +- yarn.lock | 16 +++++++++++++++- 6 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 generator/features/assetListing.spec.ts diff --git a/generator/features/assetListing.spec.ts b/generator/features/assetListing.spec.ts new file mode 100644 index 000000000..b2c4c6d5f --- /dev/null +++ b/generator/features/assetListing.spec.ts @@ -0,0 +1,10 @@ +// sum.test.js +import {expect, describe, it} from 'vitest'; +import {assetListing} from './assetListing'; + +describe('feature: assetListing', () => { + it('should return reasonable code', () => { + const output = assetListing.build({}, 'AaveV3Ethereum'); + expect(output).toMatchSnapshot(); + }); +}); diff --git a/generator/features/assetListing.ts b/generator/features/assetListing.ts index 1afe6859b..5bd1a36e6 100644 --- a/generator/features/assetListing.ts +++ b/generator/features/assetListing.ts @@ -6,7 +6,7 @@ import {fetchCollateralUpdate} from './collateralsUpdates'; import {fetchCapsUpdate} from './capsUpdates'; import {Listing, ListingWithCustomImpl, TokenImplementations} from './types'; import {CHAIN_TO_CHAIN_OBJECT, getPoolChain} from '../common'; -import {PublicClient, getContract} from 'viem'; +import {createPublicClient, getContract, http} from 'viem'; import {confirm} from '@inquirer/prompts'; import {TEST_EXECUTE_PROPOSAL} from '../utils/constants'; @@ -17,6 +17,7 @@ async function fetchListing(pool: PoolIdentifier): Promise { }); const chain = getPoolChain(pool); + console.log(pool, chain); const erc20 = getContract({ abi: [ { @@ -43,7 +44,7 @@ async function fetchListing(pool: PoolIdentifier): Promise { type: 'function', }, ], - publicClient: CHAIN_TO_CHAIN_OBJECT[chain] as PublicClient, + publicClient: createPublicClient({chain: CHAIN_TO_CHAIN_OBJECT[chain], transport: http()}), address: asset, }); let symbol = ''; @@ -51,13 +52,9 @@ async function fetchListing(pool: PoolIdentifier): Promise { symbol = await erc20.read.symbol(); } catch (e) { console.log('could not fetch the symbol - this is likely an error'); + console.log(e); } - let decimals = 0; - try { - decimals = await erc20.read.decimals(); - } catch (e) { - console.log('could not fetch the symbol - this is likely an error'); - } + const decimals = await erc20.read.decimals(); return { assetSymbol: await stringInput({ @@ -154,6 +151,14 @@ export const assetListing: FeatureModule = { }`, ], }, + test: { + fn: cfg.map( + (cfg) => `function test_collectorHas${cfg.assetSymbol}Funds() public { + ${TEST_EXECUTE_PROPOSAL} + assertGte(IERC20(${cfg.asset}).balanceOf(${pool}.COLLECTOR), 10 ** ${cfg.decimals}); + }` + ), + }, }; return response; }, diff --git a/generator/features/borrowsUpdates.ts b/generator/features/borrowsUpdates.ts index 14ed0a03b..4eef29600 100644 --- a/generator/features/borrowsUpdates.ts +++ b/generator/features/borrowsUpdates.ts @@ -1,4 +1,4 @@ -import {CodeArtifact, FEATURE, FeatureModule} from '../types'; +import {CodeArtifact, ENGINE_FLAGS, FEATURE, FeatureModule} from '../types'; import {assetsSelect, booleanSelect, percentInput} from '../prompts'; import {BorrowUpdate} from './types'; @@ -15,14 +15,17 @@ export async function fetchBorrowUpdate(disableKeepCurrent?: stableRateModeEnabled: await booleanSelect({ message: 'stable rate mode enabled', disableKeepCurrent, + defaultValue: ENGINE_FLAGS.DISABLED, }), borrowableInIsolation: await booleanSelect({ message: 'borrowable in isolation', disableKeepCurrent, + defaultValue: ENGINE_FLAGS.DISABLED, }), withSiloedBorrowing: await booleanSelect({ message: 'siloed borrowing', disableKeepCurrent, + defaultValue: ENGINE_FLAGS.DISABLED, }), reserveFactor: await percentInput({ message: 'reserve factor', diff --git a/generator/features/rateUpdates.ts b/generator/features/rateUpdates.ts index d77aebcee..4f65a5764 100644 --- a/generator/features/rateUpdates.ts +++ b/generator/features/rateUpdates.ts @@ -40,7 +40,7 @@ export async function fetchRateStrategyParamsV2( } export async function fetchRateStrategyParamsV3(disableKeepCurrent?: boolean) { - const params = await fetchRateStrategyParamsV2(); + const params = await fetchRateStrategyParamsV2(disableKeepCurrent); return { ...params, baseStableRateOffset: await percentInput({ diff --git a/package.json b/package.json index e008ca8f4..a3947fb81 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,6 @@ "@inquirer/prompts": "^3.2.0", "commander": "^11.0.0", "tsx": "^3.13.0", - "viem": "^1.16.4" + "viem": "^1.16.6" } } diff --git a/yarn.lock b/yarn.lock index d528b1e5b..dcfb29a6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1807,7 +1807,7 @@ varint@^6.0.0: resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== -viem@^1.15.1, viem@^1.16.4: +viem@^1.15.1: version "1.16.4" resolved "https://registry.yarnpkg.com/viem/-/viem-1.16.4.tgz#4cb90dd27d13356ea00d21f6fd363bdfe0628c4e" integrity sha512-T9ziN3EERXz0BtQSS2VJM+P1EJ2W7K7PviobFrmvWCEYmNQ/vJDhfFqGjvq0ZL9LVz9HvevCbenEy8oIdMEZ+w== @@ -1821,6 +1821,20 @@ viem@^1.15.1, viem@^1.16.4: isows "1.0.3" ws "8.13.0" +viem@^1.16.6: + version "1.16.6" + resolved "https://registry.yarnpkg.com/viem/-/viem-1.16.6.tgz#78118c9269506a59e2bc4deab13f1646e113d3fc" + integrity sha512-jcWcFQ+xzIfDwexwPJRvCuCRJKEkK9iHTStG7mpU5MmuSBpACs4nATBDyXNFtUiyYTFzLlVEwWkt68K0nCSImg== + dependencies: + "@adraffy/ens-normalize" "1.9.4" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "0.9.8" + isows "1.0.3" + ws "8.13.0" + vite-node@0.34.6: version "0.34.6" resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.34.6.tgz#34d19795de1498562bf21541a58edcd106328a17" From 077a528d3fccbbf255f00da482b537b85ca90a7d Mon Sep 17 00:00:00 2001 From: sakulstra Date: Mon, 23 Oct 2023 16:42:43 +0200 Subject: [PATCH 10/18] test: add tests for features --- generator/cli.ts | 9 +- .../__snapshots__/assetListing.spec.ts.snap | 292 ++++++++++++++++++ generator/features/assetListing.spec.ts | 18 +- generator/features/assetListing.ts | 5 +- generator/features/mocks/configs.ts | 46 +++ generator/generator.ts | 20 +- generator/prompts.ts | 1 + generator/types.ts | 4 +- generator/utils/constants.ts | 5 +- test.sol | 56 ++++ 10 files changed, 436 insertions(+), 20 deletions(-) create mode 100644 generator/features/__snapshots__/assetListing.spec.ts.snap create mode 100644 generator/features/mocks/configs.ts create mode 100644 test.sol diff --git a/generator/cli.ts b/generator/cli.ts index 6f5bf088a..4edf62902 100644 --- a/generator/cli.ts +++ b/generator/cli.ts @@ -157,5 +157,10 @@ if (options.configFile) { } } -const files = await generateFiles(options, poolConfigs); -await writeFiles(options, files); +try { + const files = await generateFiles(options, poolConfigs); + await writeFiles(options, files); +} catch (e) { + console.log(JSON.stringify({options, poolConfigs}, null, 2)); + throw e; +} diff --git a/generator/features/__snapshots__/assetListing.spec.ts.snap b/generator/features/__snapshots__/assetListing.spec.ts.snap new file mode 100644 index 000000000..a7c999c3c --- /dev/null +++ b/generator/features/__snapshots__/assetListing.spec.ts.snap @@ -0,0 +1,292 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`feature: assetListing > should properly generate files 1`] = ` +{ + "aip": "--- +title: \\"test\\" +author: \\"test\\" +discussions: \\"test\\" +--- + +## Simple Summary + +## Motivation + +## Specification + +## References + +- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20231023_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231023.sol) +- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20231023_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231023.t.sol) +- [Snapshot](test) +- [Discussion](test) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). +", + "jsonConfig": "{ + \\"rootOptions\\": { + \\"pools\\": [ + \\"AaveV3Ethereum\\" + ], + \\"title\\": \\"test\\", + \\"shortName\\": \\"Test\\", + \\"date\\": \\"20231023\\", + \\"author\\": \\"test\\", + \\"discussion\\": \\"test\\", + \\"snapshot\\": \\"test\\" + }, + \\"poolOptions\\": { + \\"AaveV3Ethereum\\": { + \\"configs\\": { + \\"ASSET_LISTING\\": [ + { + \\"assetSymbol\\": \\"PSP\\", + \\"decimals\\": 18, + \\"priceFeed\\": \\"0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8\\", + \\"ltv\\": \\"40_00\\", + \\"liqThreshold\\": \\"50_00\\", + \\"liqBonus\\": \\"5_00\\", + \\"debtCeiling\\": \\"100_000\\", + \\"liqProtocolFee\\": \\"20_00\\", + \\"enabledToBorrow\\": \\"ENABLED\\", + \\"flashloanable\\": \\"ENABLED\\", + \\"stableRateModeEnabled\\": \\"DISABLED\\", + \\"borrowableInIsolation\\": \\"DISABLED\\", + \\"withSiloedBorrowing\\": \\"DISABLED\\", + \\"reserveFactor\\": \\"20_00\\", + \\"supplyCap\\": \\"10_000\\", + \\"borrowCap\\": \\"5_000\\", + \\"rateStrategyParams\\": { + \\"optimalUtilizationRate\\": \\"_bpsToRay(80_00)\\", + \\"baseVariableBorrowRate\\": \\"_bpsToRay(0_00)\\", + \\"variableRateSlope1\\": \\"_bpsToRay(10_00)\\", + \\"variableRateSlope2\\": \\"_bpsToRay(100_00)\\", + \\"stableRateSlope1\\": \\"_bpsToRay(10_00)\\", + \\"stableRateSlope2\\": \\"_bpsToRay(100_00)\\", + \\"baseStableRateOffset\\": \\"_bpsToRay(1_00)\\", + \\"stableRateExcessOffset\\": \\"_bpsToRay()\\", + \\"optimalStableToTotalDebtRatio\\": \\"_bpsToRay(10_00)\\" + }, + \\"eModeCategory\\": \\"AaveV3EthereumEModes.NONE\\", + \\"asset\\": \\"0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5\\" + } + ] + }, + \\"features\\": [ + \\"ASSET_LISTING\\" + ] + } + } +}", + "payloads": [ + { + "contractName": "AaveV3Ethereum_Test_20231023", + "payload": "// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3Ethereum, AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol'; +import {AaveV3PayloadEthereum} from 'aave-helpers/v3-config-engine/AaveV3PayloadEthereum.sol'; + +/** + * @title test + * @author test + * - Snapshot: test + * - Discussion: test + */ +contract AaveV3Ethereum_Test_20231023 is AaveV3PayloadEthereum { + address public constant PSP = address(0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5); + + function _postExecute() internal override { + AaveV3Ethereum.POOL.supply(PSP, 10 ** 18, AaveV3Ethereum.COLLECTOR, 0); + } + + function newListings() public pure override returns (IEngine.Listing[] memory) { + IEngine.Listing[] memory listings = new IEngine.Listing[](1); + + listings[0] = IEngine.Listing({ + asset: PSP, + assetSymbol: 'PSP', + priceFeed: 0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8, + eModeCategory: AaveV3EthereumEModes.NONE, + enabledToBorrow: ENABLED, + stableRateModeEnabled: DISABLED, + borrowableInIsolation: DISABLED, + withSiloedBorrowing: DISABLED, + flashloanable: ENABLED, + ltv: 40_00, + liqThreshold: 50_00, + liqBonus: 5_00, + reserveFactor: 20_00, + supplyCap: 10_000, + borrowCap: 5_000, + debtCeiling: 100_000, + liqProtocolFee: 20_00, + rateStrategyParams: Rates.RateStrategyParams({ + optimalUsageRatio: _bpsToRay(80_00), + baseVariableBorrowRate: _bpsToRay(0_00), + variableRateSlope1: _bpsToRay(10_00), + variableRateSlope2: _bpsToRay(100_00), + stableRateSlope1: _bpsToRay(10_00), + stableRateSlope2: _bpsToRay(100_00), + baseStableRateOffset: _bpsToRay(1_00), + stableRateExcessOffset: _bpsToRay(), + optimalStableToTotalDebtRatio: _bpsToRay(10_00) + }) + }); + + return listings; + } +} +", + "test": "// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovV3Helpers} from 'aave-helpers/GovV3Helpers.sol'; +import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol'; + +import 'forge-std/Test.sol'; +import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol'; +import {AaveV3Ethereum_Test_20231023} from './AaveV3Ethereum_Test_20231023.sol'; + +/** + * @dev Test for AaveV3Ethereum_Test_20231023 + * command: make test-contract filter=AaveV3Ethereum_Test_20231023 + */ +contract AaveV3Ethereum_Test_20231023_Test is ProtocolV3TestBase { + AaveV3Ethereum_Test_20231023 internal proposal; + + function setUp() public { + vm.createSelectFork(vm.rpcUrl('mainnet'), 18413630); + proposal = new AaveV3Ethereum_Test_20231023(); + } + + /** + * @dev executes the generic test suite including e2e and config snapshots + */ + function test_defaultProposalExecution() public { + defaultTest('AaveV3Ethereum_Test_20231023', AaveV3Ethereum.POOL, address(proposal)); + } + + function test_collectorHasPSPFunds() public { + GovV3Helpers.executePayload(vm, address(proposal)); + assertGte( + IERC20(0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5).balanceOf(AaveV3Ethereum.COLLECTOR), + 10 ** 18 + ); + } +} +", + }, + ], + "script": "// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from 'aave-helpers/GovV3Helpers.sol'; +import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; +import {AaveV3Ethereum_Test_20231023} from './AaveV3Ethereum_Test_20231023.sol'; + +/** + * @dev Deploy Ethereum + * command: make deploy-ledger contract=src/20231023_AaveV3Ethereum_Test/Test_20231023.s.sol:DeployEthereum chain=mainnet + */ +contract DeployEthereum is EthereumScript { + function run() external broadcast { + // deploy payloads + AaveV3Ethereum_Test_20231023 payload0 = new AaveV3Ethereum_Test_20231023(); + + // compose action + IPayloadsControllerCore.ExecutionAction[] + memory actions = new IPayloadsControllerCore.ExecutionAction[](1); + actions[0] = GovV3Helpers.buildAction(address(payload0)); + + // register action at payloadsController + GovV3Helpers.createPayload(actions); + } +} + +/** + * @dev Create Proposal + * command: make deploy-ledger contract=src/20231023_AaveV3Ethereum_Test/Test_20231023.s.sol:CreateProposal chain=mainnet + */ +contract CreateProposal is EthereumScript { + function run() external broadcast { + // create payloads + PayloadsControllerUtils.Payload[] memory payloads = new PayloadsControllerUtils.Payload[](1); + + // compose actions for validation + IPayloadsControllerCore.ExecutionAction[] + memory actionsEthereum = new IPayloadsControllerCore.ExecutionAction[](1); + actionsEthereum[0] = GovV3Helpers.buildAction(address(0)); + payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum); + + // create proposal + GovV3Helpers.createProposal( + payloads, + GovV3Helpers.ipfsHashFile(vm, 'src/20231023_AaveV3Ethereum_Test/Test.md') + ); + } +} +", +} +`; + +exports[`feature: assetListing > should return reasonable code 1`] = ` +{ + "code": { + "constants": [ + "address public constant PSP = address(0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5);", + ], + "execute": [ + "AaveV3Ethereum.POOL.supply(PSP, 10 ** 18, AaveV3Ethereum.COLLECTOR, 0);", + ], + "fn": [ + "function newListings() public pure override returns (IEngine.Listing[] memory) { + IEngine.Listing[] memory listings = new IEngine.Listing[](1); + + listings[0] = IEngine.Listing({ + asset: PSP, + assetSymbol: \\"PSP\\", + priceFeed: 0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8, + eModeCategory: AaveV3EthereumEModes.NONE, + enabledToBorrow: ENABLED, + stableRateModeEnabled: DISABLED, + borrowableInIsolation: DISABLED, + withSiloedBorrowing: DISABLED, + flashloanable: ENABLED, + ltv: 40_00, + liqThreshold: 50_00, + liqBonus: 5_00, + reserveFactor: 20_00, + supplyCap: 10_000, + borrowCap: 5_000, + debtCeiling: 100_000, + liqProtocolFee: 20_00, + rateStrategyParams: Rates.RateStrategyParams({ + optimalUsageRatio: _bpsToRay(80_00), + baseVariableBorrowRate: _bpsToRay(0_00), + variableRateSlope1: _bpsToRay(10_00), + variableRateSlope2: _bpsToRay(100_00), + stableRateSlope1: _bpsToRay(10_00), + stableRateSlope2: _bpsToRay(100_00), + baseStableRateOffset: _bpsToRay(1_00), + stableRateExcessOffset: _bpsToRay(), + optimalStableToTotalDebtRatio: _bpsToRay(10_00) + }) + }); + + return listings; + }", + ], + }, + "test": { + "fn": [ + "function test_collectorHasPSPFunds() public { + GovV3Helpers.executePayload(vm,address(proposal)); + assertGte(IERC20(0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5).balanceOf(AaveV3Ethereum.COLLECTOR), 10 ** 18); + }", + ], + }, +} +`; diff --git a/generator/features/assetListing.spec.ts b/generator/features/assetListing.spec.ts index b2c4c6d5f..28018c495 100644 --- a/generator/features/assetListing.spec.ts +++ b/generator/features/assetListing.spec.ts @@ -1,10 +1,26 @@ // sum.test.js import {expect, describe, it} from 'vitest'; import {assetListing} from './assetListing'; +import {MOCK_OPTIONS, assetListingConfig} from './mocks/configs'; +import {generateFiles} from '../generator'; +import {FEATURE, PoolConfigs} from '../types'; describe('feature: assetListing', () => { it('should return reasonable code', () => { - const output = assetListing.build({}, 'AaveV3Ethereum'); + const output = assetListing.build(MOCK_OPTIONS, 'AaveV3Ethereum', assetListingConfig); expect(output).toMatchSnapshot(); }); + + it('should properly generate files', async () => { + const poolConfigs: PoolConfigs = { + [MOCK_OPTIONS.pools[0]]: { + pool: MOCK_OPTIONS.pools[0], + features: [FEATURE.ASSET_LISTING], + artifacts: [assetListing.build(MOCK_OPTIONS, 'AaveV3Ethereum', assetListingConfig)], + configs: {[FEATURE.ASSET_LISTING]: assetListingConfig}, + }, + }; + const files = await generateFiles(MOCK_OPTIONS, poolConfigs); + expect(files).toMatchSnapshot(); + }); }); diff --git a/generator/features/assetListing.ts b/generator/features/assetListing.ts index 5bd1a36e6..2bf723105 100644 --- a/generator/features/assetListing.ts +++ b/generator/features/assetListing.ts @@ -17,7 +17,6 @@ async function fetchListing(pool: PoolIdentifier): Promise { }); const chain = getPoolChain(pool); - console.log(pool, chain); const erc20 = getContract({ abi: [ { @@ -124,7 +123,7 @@ export const assetListing: FeatureModule = { borrowableInIsolation: ${cfg.borrowableInIsolation}, withSiloedBorrowing: ${cfg.withSiloedBorrowing}, flashloanable: ${cfg.flashloanable}, - ltv: ${cfg.ltv} + ltv: ${cfg.ltv}, liqThreshold: ${cfg.liqThreshold}, liqBonus: ${cfg.liqBonus}, reserveFactor: ${cfg.reserveFactor}, @@ -205,7 +204,7 @@ export const assetListingCustom: FeatureModule = { borrowableInIsolation: ${cfg.base.borrowableInIsolation}, withSiloedBorrowing: ${cfg.base.withSiloedBorrowing}, flashloanable: ${cfg.base.flashloanable}, - ltv: ${cfg.base.ltv} + ltv: ${cfg.base.ltv}, liqThreshold: ${cfg.base.liqThreshold}, liqBonus: ${cfg.base.liqBonus}, reserveFactor: ${cfg.base.reserveFactor}, diff --git a/generator/features/mocks/configs.ts b/generator/features/mocks/configs.ts new file mode 100644 index 000000000..7af85354d --- /dev/null +++ b/generator/features/mocks/configs.ts @@ -0,0 +1,46 @@ +import {Options} from '../../types'; +import {Listing} from '../types'; + +export const MOCK_OPTIONS: Options = { + pools: ['AaveV3Ethereum'], + title: 'test', + shortName: 'Test', + date: '20231023', + author: 'test', + discussion: 'test', + snapshot: 'test', +}; + +export const assetListingConfig: Listing[] = [ + { + assetSymbol: 'PSP', + decimals: 18, + priceFeed: '0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8', + ltv: '40_00', + liqThreshold: '50_00', + liqBonus: '5_00', + debtCeiling: '100_000', + liqProtocolFee: '20_00', + enabledToBorrow: 'ENABLED', + flashloanable: 'ENABLED', + stableRateModeEnabled: 'DISABLED', + borrowableInIsolation: 'DISABLED', + withSiloedBorrowing: 'DISABLED', + reserveFactor: '20_00', + supplyCap: '10_000', + borrowCap: '5_000', + rateStrategyParams: { + optimalUtilizationRate: '_bpsToRay(80_00)', + baseVariableBorrowRate: '_bpsToRay(0_00)', + variableRateSlope1: '_bpsToRay(10_00)', + variableRateSlope2: '_bpsToRay(100_00)', + stableRateSlope1: '_bpsToRay(10_00)', + stableRateSlope2: '_bpsToRay(100_00)', + baseStableRateOffset: '_bpsToRay(1_00)', + stableRateExcessOffset: '_bpsToRay()', + optimalStableToTotalDebtRatio: '_bpsToRay(10_00)', + }, + eModeCategory: 'AaveV3EthereumEModes.NONE', + asset: '0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5', + }, +]; diff --git a/generator/generator.ts b/generator/generator.ts index cd0a8d331..0b818ec40 100644 --- a/generator/generator.ts +++ b/generator/generator.ts @@ -62,17 +62,21 @@ export async function generateFiles(options: Options, poolConfigs: PoolConfigs): contractName: contractName, }; } + console.log('generating script'); + const script = prettier.format(generateScript(options), { + ...prettierSolCfg, + filepath: 'foo.sol', + }); + console.log('generating aip'); + const aip = prettier.format(generateAIP(options, poolConfigs), { + ...prettierMDCfg, + filepath: 'foo.md', + }); return { jsonConfig, - script: prettier.format(generateScript(options), { - ...prettierSolCfg, - filepath: 'foo.sol', - }), - aip: prettier.format(generateAIP(options, poolConfigs), { - ...prettierMDCfg, - filepath: 'foo.md', - }), + script, + aip, payloads: await Promise.all(options.pools.map((pool) => createPayloadAndTest(options, pool))), }; } diff --git a/generator/prompts.ts b/generator/prompts.ts index b1d2f91c6..ee15db28b 100644 --- a/generator/prompts.ts +++ b/generator/prompts.ts @@ -76,6 +76,7 @@ export type BooleanSelectValues = export async function booleanSelect({ message, disableKeepCurrent, + defaultValue, }: GenericPrompt): Promise< T extends true ? Exclude : BooleanSelectValues > { diff --git a/generator/types.ts b/generator/types.ts index 28284cf50..a5eacd33e 100644 --- a/generator/types.ts +++ b/generator/types.ts @@ -1,7 +1,7 @@ import * as addressBook from '@bgd-labs/aave-address-book'; export interface Options { - force: boolean; + force?: boolean; pools: PoolIdentifier[]; title: string; // automatically generated shortName from title @@ -9,7 +9,7 @@ export interface Options { author: string; discussion: string; snapshot: string; - configFile: string; + configFile?: string; date: string; } diff --git a/generator/utils/constants.ts b/generator/utils/constants.ts index 4a231e9b2..05cdcfe9f 100644 --- a/generator/utils/constants.ts +++ b/generator/utils/constants.ts @@ -5,7 +5,4 @@ export function prefixWithPragma(code: string) { ); } -export const TEST_EXECUTE_PROPOSAL = `GovV3Helpers.executePayload( - vm, - address(proposal) -);`; +export const TEST_EXECUTE_PROPOSAL = `GovV3Helpers.executePayload(vm,address(proposal));`; diff --git a/test.sol b/test.sol new file mode 100644 index 000000000..8c2acf2fe --- /dev/null +++ b/test.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3Ethereum, AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol'; +import {AaveV3PayloadEthereum} from 'aave-helpers/v3-config-engine/AaveV3PayloadEthereum.sol'; + +/** + * @title test + * @author test + * - Snapshot: test + * - Discussion: test + */ +contract AaveV3Ethereum_Test_20231023 is AaveV3PayloadEthereum { + address public constant PSP = address(0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5); + + function _postExecute() internal override { + AaveV3Ethereum.POOL.supply(PSP, 10 ** 18, AaveV3Ethereum.COLLECTOR, 0); + } + + function newListings() public pure override returns (IEngine.Listing[] memory) { + IEngine.Listing[] memory listings = new IEngine.Listing[](1); + + listings[0] = IEngine.Listing({ + asset: PSP, + assetSymbol: 'PSP', + priceFeed: 0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8, + eModeCategory: AaveV3EthereumEModes.NONE, + enabledToBorrow: ENABLED, + stableRateModeEnabled: DISABLED, + borrowableInIsolation: DISABLED, + withSiloedBorrowing: DISABLED, + flashloanable: ENABLED, + ltv: 40_00, + liqThreshold: 50_00, + liqBonus: 5_00, + reserveFactor: 20_00, + supplyCap: 10_000, + borrowCap: 5_000, + debtCeiling: 100_000, + liqProtocolFee: 20_00, + rateStrategyParams: Rates.RateStrategyParams({ + optimalUsageRatio: _bpsToRay(80_00), + baseVariableBorrowRate: _bpsToRay(0_00), + variableRateSlope1: _bpsToRay(10_00), + variableRateSlope2: _bpsToRay(100_00), + stableRateSlope1: _bpsToRay(10_00), + stableRateSlope2: _bpsToRay(100_00), + baseStableRateOffset: _bpsToRay(1_00), + stableRateExcessOffset: _bpsToRay(), + optimalStableToTotalDebtRatio: _bpsToRay(10_00) + }) + }); + + return listings; + } +} From a36d4f2b97e0bcb8826b10b027af1377bfe24ef8 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Mon, 23 Oct 2023 16:43:06 +0200 Subject: [PATCH 11/18] fix: remove some obsolete stuff --- deploy.sh | 5 ----- test.sol | 56 ------------------------------------------------------- 2 files changed, 61 deletions(-) delete mode 100755 deploy.sh delete mode 100644 test.sol diff --git a/deploy.sh b/deploy.sh deleted file mode 100755 index 517bda48b..000000000 --- a/deploy.sh +++ /dev/null @@ -1,5 +0,0 @@ -# To load the variables in the .env file -source .env - -# To deploy and verify our contract -forge script script/Ghost.s.sol:Deploy --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY -vvvv diff --git a/test.sol b/test.sol deleted file mode 100644 index 8c2acf2fe..000000000 --- a/test.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {AaveV3Ethereum, AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol'; -import {AaveV3PayloadEthereum} from 'aave-helpers/v3-config-engine/AaveV3PayloadEthereum.sol'; - -/** - * @title test - * @author test - * - Snapshot: test - * - Discussion: test - */ -contract AaveV3Ethereum_Test_20231023 is AaveV3PayloadEthereum { - address public constant PSP = address(0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5); - - function _postExecute() internal override { - AaveV3Ethereum.POOL.supply(PSP, 10 ** 18, AaveV3Ethereum.COLLECTOR, 0); - } - - function newListings() public pure override returns (IEngine.Listing[] memory) { - IEngine.Listing[] memory listings = new IEngine.Listing[](1); - - listings[0] = IEngine.Listing({ - asset: PSP, - assetSymbol: 'PSP', - priceFeed: 0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8, - eModeCategory: AaveV3EthereumEModes.NONE, - enabledToBorrow: ENABLED, - stableRateModeEnabled: DISABLED, - borrowableInIsolation: DISABLED, - withSiloedBorrowing: DISABLED, - flashloanable: ENABLED, - ltv: 40_00, - liqThreshold: 50_00, - liqBonus: 5_00, - reserveFactor: 20_00, - supplyCap: 10_000, - borrowCap: 5_000, - debtCeiling: 100_000, - liqProtocolFee: 20_00, - rateStrategyParams: Rates.RateStrategyParams({ - optimalUsageRatio: _bpsToRay(80_00), - baseVariableBorrowRate: _bpsToRay(0_00), - variableRateSlope1: _bpsToRay(10_00), - variableRateSlope2: _bpsToRay(100_00), - stableRateSlope1: _bpsToRay(10_00), - stableRateSlope2: _bpsToRay(100_00), - baseStableRateOffset: _bpsToRay(1_00), - stableRateExcessOffset: _bpsToRay(), - optimalStableToTotalDebtRatio: _bpsToRay(10_00) - }) - }); - - return listings; - } -} From a552e16fcd87a70e1facd8a8419ceb0e79500261 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Tue, 24 Oct 2023 00:05:55 +0200 Subject: [PATCH 12/18] fix: use v2.5 for now --- generator/templates/script.template.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator/templates/script.template.ts b/generator/templates/script.template.ts index b26f1aaff..d9335673c 100644 --- a/generator/templates/script.template.ts +++ b/generator/templates/script.template.ts @@ -93,7 +93,7 @@ contract CreateProposal is EthereumScript { .join('\n')} // create proposal - GovV3Helpers.createProposal(payloads, GovV3Helpers.ipfsHashFile(vm, 'src/${folderName}/${ + GovV3Helpers.createProposal2_5(payloads, GovV3Helpers.ipfsHashFile(vm, 'src/${folderName}/${ options.shortName }.md')); } From 20b2bcefdfa3a67cedefd5e9aa95de94f372343a Mon Sep 17 00:00:00 2001 From: sakulstra Date: Tue, 24 Oct 2023 13:28:13 +0200 Subject: [PATCH 13/18] chore: update deps --- lib/forge-std | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/forge-std b/lib/forge-std index 066ff16c5..f73c73d20 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 066ff16c5c03e6f931cd041fd366bc4be1fae82a +Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 From 63d894b771f3ed3cf73ecc2ec0bfb959fd738640 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Tue, 24 Oct 2023 14:57:04 +0200 Subject: [PATCH 14/18] fix: upgrade aave proposals --- lib/aave-helpers | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aave-helpers b/lib/aave-helpers index f6a905a6c..8f3870f8f 160000 --- a/lib/aave-helpers +++ b/lib/aave-helpers @@ -1 +1 @@ -Subproject commit f6a905a6c2b2f4e1fd00c30d4f5f86ea275756e9 +Subproject commit 8f3870f8fc162d356062f16b42d2769145b3b696 From 90c81d9d1a40946d5f9d757f8142c5583f64ac8a Mon Sep 17 00:00:00 2001 From: sakulstra Date: Tue, 24 Oct 2023 16:28:50 +0200 Subject: [PATCH 15/18] fix: remove obsolete helper --- generator/common.ts | 9 --------- package.json | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/generator/common.ts b/generator/common.ts index fd1f63d31..bad4f0d96 100644 --- a/generator/common.ts +++ b/generator/common.ts @@ -26,15 +26,6 @@ export const AVAILABLE_CHAINS = [ 'Gnosis', ] as const; -export const CHAINS_WITH_GOV_SUPPORT = [ - 'Ethereum', - 'Optimism', - 'Arbitrum', - 'Polygon', - 'Metis', - 'Base', -] as const satisfies readonly (typeof AVAILABLE_CHAINS)[number][]; - export function getAssets(pool: PoolIdentifier): string[] { const assets = addressBook[pool].ASSETS; return Object.keys(assets); diff --git a/package.json b/package.json index a3947fb81..1a1f94f7b 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "vitest": "^0.34.6" }, "dependencies": { - "@bgd-labs/aave-address-book": "^2.7.0", + "@bgd-labs/aave-address-book": "^2.8.0", "@bgd-labs/aave-cli": "0.0.27-454eafdfe0f9813ef73c81bc25457e3efd418c50.0", "@inquirer/prompts": "^3.2.0", "commander": "^11.0.0", From 4af3d371dae063247c8e19b70faa460fb73387cb Mon Sep 17 00:00:00 2001 From: sakulstra Date: Tue, 24 Oct 2023 17:01:22 +0200 Subject: [PATCH 16/18] fix: update aave-helpers --- .gitmodules | 3 -- .../__snapshots__/assetListing.spec.ts.snap | 17 +++---- generator/features/assetListing.ts | 18 +++---- generator/features/borrowsUpdates.ts | 8 ++-- generator/features/capsUpdates.ts | 8 ++-- generator/features/collateralsUpdates.ts | 6 +-- generator/features/eModesAssets.ts | 6 +-- generator/features/eModesUpdates.ts | 6 +-- generator/features/priceFeedsUpdates.ts | 6 +-- generator/features/rateUpdates.ts | 12 ++--- lib/aave-helpers | 2 +- lib/forge-std | 1 - .../AaveV3Ethereum_Test_20231024.sol | 26 ++++++++++ .../AaveV3Ethereum_Test_20231024.t.sol | 28 +++++++++++ src/20231024_AaveV3Ethereum_Test/Test.md | 22 +++++++++ .../Test_20231024.s.sol | 48 +++++++++++++++++++ src/20231024_AaveV3Ethereum_Test/config.json | 29 +++++++++++ 17 files changed, 201 insertions(+), 45 deletions(-) delete mode 160000 lib/forge-std create mode 100644 src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol create mode 100644 src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol create mode 100644 src/20231024_AaveV3Ethereum_Test/Test.md create mode 100644 src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol create mode 100644 src/20231024_AaveV3Ethereum_Test/config.json diff --git a/.gitmodules b/.gitmodules index 78d40275f..f7316a1d6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "lib/forge-std"] - path = lib/forge-std - url = https://github.com/foundry-rs/forge-std [submodule "lib/aave-helpers"] path = lib/aave-helpers url = https://github.com/bgd-labs/aave-helpers diff --git a/generator/features/__snapshots__/assetListing.spec.ts.snap b/generator/features/__snapshots__/assetListing.spec.ts.snap index a7c999c3c..428e19738 100644 --- a/generator/features/__snapshots__/assetListing.spec.ts.snap +++ b/generator/features/__snapshots__/assetListing.spec.ts.snap @@ -88,6 +88,7 @@ pragma solidity ^0.8.0; import {AaveV3Ethereum, AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol'; import {AaveV3PayloadEthereum} from 'aave-helpers/v3-config-engine/AaveV3PayloadEthereum.sol'; +import {IAaveV3ConfigEngine} from 'aave-helpers/v3-config-engine/IAaveV3ConfigEngine.sol'; /** * @title test @@ -102,10 +103,10 @@ contract AaveV3Ethereum_Test_20231023 is AaveV3PayloadEthereum { AaveV3Ethereum.POOL.supply(PSP, 10 ** 18, AaveV3Ethereum.COLLECTOR, 0); } - function newListings() public pure override returns (IEngine.Listing[] memory) { - IEngine.Listing[] memory listings = new IEngine.Listing[](1); + function newListings() public pure override returns (IAaveV3ConfigEngine.Listing[] memory) { + IAaveV3ConfigEngine.Listing[] memory listings = new IAaveV3ConfigEngine.Listing[](1); - listings[0] = IEngine.Listing({ + listings[0] = IAaveV3ConfigEngine.Listing({ asset: PSP, assetSymbol: 'PSP', priceFeed: 0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8, @@ -158,7 +159,7 @@ contract AaveV3Ethereum_Test_20231023_Test is ProtocolV3TestBase { AaveV3Ethereum_Test_20231023 internal proposal; function setUp() public { - vm.createSelectFork(vm.rpcUrl('mainnet'), 18413630); + vm.createSelectFork(vm.rpcUrl('mainnet'), 18420741); proposal = new AaveV3Ethereum_Test_20231023(); } @@ -222,7 +223,7 @@ contract CreateProposal is EthereumScript { payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum); // create proposal - GovV3Helpers.createProposal( + GovV3Helpers.createProposal2_5( payloads, GovV3Helpers.ipfsHashFile(vm, 'src/20231023_AaveV3Ethereum_Test/Test.md') ); @@ -242,10 +243,10 @@ exports[`feature: assetListing > should return reasonable code 1`] = ` "AaveV3Ethereum.POOL.supply(PSP, 10 ** 18, AaveV3Ethereum.COLLECTOR, 0);", ], "fn": [ - "function newListings() public pure override returns (IEngine.Listing[] memory) { - IEngine.Listing[] memory listings = new IEngine.Listing[](1); + "function newListings() public pure override returns (IAaveV3ConfigEngine.Listing[] memory) { + IAaveV3ConfigEngine.Listing[] memory listings = new IAaveV3ConfigEngine.Listing[](1); - listings[0] = IEngine.Listing({ + listings[0] = IAaveV3ConfigEngine.Listing({ asset: PSP, assetSymbol: \\"PSP\\", priceFeed: 0x72AFAECF99C9d9C8215fF44C77B94B99C28741e8, diff --git a/generator/features/assetListing.ts b/generator/features/assetListing.ts index 2bf723105..00bae7c5a 100644 --- a/generator/features/assetListing.ts +++ b/generator/features/assetListing.ts @@ -108,12 +108,14 @@ export const assetListing: FeatureModule = { `${pool}.POOL.supply(${cfg.assetSymbol}, 10 ** ${cfg.decimals}, ${pool}.COLLECTOR, 0);` ), fn: [ - `function newListings() public pure override returns (IEngine.Listing[] memory) { - IEngine.Listing[] memory listings = new IEngine.Listing[](${cfg.length}); + `function newListings() public pure override returns (IAaveV3ConfigEngine.Listing[] memory) { + IAaveV3ConfigEngine.Listing[] memory listings = new IAaveV3ConfigEngine.Listing[](${ + cfg.length + }); ${cfg .map( - (cfg, ix) => `listings[${ix}] = IEngine.Listing({ + (cfg, ix) => `listings[${ix}] = IAaveV3ConfigEngine.Listing({ asset: ${cfg.assetSymbol}, assetSymbol: "${cfg.assetSymbol}", priceFeed: ${cfg.priceFeed}, @@ -186,15 +188,15 @@ export const assetListingCustom: FeatureModule = { `${pool}.POOL.supply(${cfg.base.assetSymbol}, 10 ** ${cfg.base.decimals}, ${pool}.COLLECTOR, 0);` ), fn: [ - `function newListingsCustom() public pure override returns (IEngine.ListingWithCustomImpl[] memory) { - IEngine.ListingWithCustomImpl[] memory listings = new IEngine.ListingWithCustomImpl[](${ + `function newListingsCustom() public pure override returns (IAaveV3ConfigEngine.ListingWithCustomImpl[] memory) { + IAaveV3ConfigEngine.ListingWithCustomImpl[] memory listings = new IAaveV3ConfigEngine.ListingWithCustomImpl[](${ cfg.length }); ${cfg .map( - (cfg, ix) => `listings[${ix}] = IEngine.ListingWithCustomImpl( - IEngine.Listing({ + (cfg, ix) => `listings[${ix}] = IAaveV3ConfigEngine.ListingWithCustomImpl( + IAaveV3ConfigEngine.Listing({ asset: ${cfg.base.assetSymbol}, assetSymbol: "${cfg.base.assetSymbol}", priceFeed: ${cfg.base.priceFeed}, @@ -224,7 +226,7 @@ export const assetListingCustom: FeatureModule = { optimalStableToTotalDebtRatio: ${cfg.base.rateStrategyParams.optimalStableToTotalDebtRatio} }) }), - IEngine.TokenImplementations({ + IAaveV3ConfigEngine.TokenImplementations({ aToken: ${cfg.implementations.aToken}, vToken: ${cfg.implementations.vToken}, sToken: ${cfg.implementations.sToken} diff --git a/generator/features/borrowsUpdates.ts b/generator/features/borrowsUpdates.ts index 4eef29600..029751679 100644 --- a/generator/features/borrowsUpdates.ts +++ b/generator/features/borrowsUpdates.ts @@ -56,12 +56,14 @@ export const borrowsUpdates: FeatureModule = { const response: CodeArtifact = { code: { fn: [ - `function borrowsUpdates() public pure override returns (IEngine.BorrowUpdate[] memory) { - IEngine.BorrowUpdate[] memory borrowUpdates = new IEngine.BorrowUpdate[](${cfg.length}); + `function borrowsUpdates() public pure override returns (IAaveV3ConfigEngine.BorrowUpdate[] memory) { + IAaveV3ConfigEngine.BorrowUpdate[] memory borrowUpdates = new IAaveV3ConfigEngine.BorrowUpdate[](${ + cfg.length + }); ${cfg .map( - (cfg, ix) => `borrowUpdates[${ix}] = IEngine.BorrowUpdate({ + (cfg, ix) => `borrowUpdates[${ix}] = IAaveV3ConfigEngine.BorrowUpdate({ asset: ${cfg.asset}, enabledToBorrow: ${cfg.enabledToBorrow}, flashloanable: ${cfg.flashloanable}, diff --git a/generator/features/capsUpdates.ts b/generator/features/capsUpdates.ts index 8444163f0..f172f07f6 100644 --- a/generator/features/capsUpdates.ts +++ b/generator/features/capsUpdates.ts @@ -38,12 +38,14 @@ export const capsUpdates: FeatureModule = { const response: CodeArtifact = { code: { fn: [ - `function capsUpdates() public pure override returns (IEngine.CapsUpdate[] memory) { - IEngine.CapsUpdate[] memory capsUpdate = new IEngine.CapsUpdate[](${cfg.length}); + `function capsUpdates() public pure override returns (IAaveV3ConfigEngine.CapsUpdate[] memory) { + IAaveV3ConfigEngine.CapsUpdate[] memory capsUpdate = new IAaveV3ConfigEngine.CapsUpdate[](${ + cfg.length + }); ${cfg .map( - (cfg, ix) => `capsUpdate[${ix}] = IEngine.CapsUpdate({ + (cfg, ix) => `capsUpdate[${ix}] = IAaveV3ConfigEngine.CapsUpdate({ asset: ${cfg.asset}, supplyCap: ${cfg.supplyCap}, borrowCap: ${cfg.borrowCap} diff --git a/generator/features/collateralsUpdates.ts b/generator/features/collateralsUpdates.ts index c6327cc6c..b34f6c4ce 100644 --- a/generator/features/collateralsUpdates.ts +++ b/generator/features/collateralsUpdates.ts @@ -54,14 +54,14 @@ export const collateralsUpdates: FeatureModule = { const response: CodeArtifact = { code: { fn: [ - `function collateralsUpdates() public pure override returns (IEngine.CollateralUpdate[] memory) { - IEngine.CollateralUpdate[] memory collateralUpdate = new IEngine.CollateralUpdate[](${ + `function collateralsUpdates() public pure override returns (IAaveV3ConfigEngine.CollateralUpdate[] memory) { + IAaveV3ConfigEngine.CollateralUpdate[] memory collateralUpdate = new IAaveV3ConfigEngine.CollateralUpdate[](${ cfg.length }); ${cfg .map( - (cfg, ix) => `collateralUpdate[${ix}] = IEngine.CollateralUpdate({ + (cfg, ix) => `collateralUpdate[${ix}] = IAaveV3ConfigEngine.CollateralUpdate({ asset: ${cfg.asset}, ltv: ${cfg.ltv}, liqThreshold: ${cfg.liqThreshold}, diff --git a/generator/features/eModesAssets.ts b/generator/features/eModesAssets.ts index 5409e1b1f..6ec33d3d3 100644 --- a/generator/features/eModesAssets.ts +++ b/generator/features/eModesAssets.ts @@ -36,14 +36,14 @@ export const eModeAssets: FeatureModule = { const response: CodeArtifact = { code: { fn: [ - `function assetsEModeUpdates() public pure override returns (IEngine.AssetEModeUpdate[] memory) { - IEngine.AssetEModeUpdate[] memory assetEModeUpdates = new IEngine.AssetEModeUpdate[](${ + `function assetsEModeUpdates() public pure override returns (IAaveV3ConfigEngine.AssetEModeUpdate[] memory) { + IAaveV3ConfigEngine.AssetEModeUpdate[] memory assetEModeUpdates = new IAaveV3ConfigEngine.AssetEModeUpdate[](${ cfg.length }); ${cfg .map( - (cfg, ix) => `assetEModeUpdates[${ix}] = IEngine.AssetEModeUpdate({ + (cfg, ix) => `assetEModeUpdates[${ix}] = IAaveV3ConfigEngine.AssetEModeUpdate({ asset: ${cfg.asset}, eModeCategory: ${cfg.eModeCategory} });` diff --git a/generator/features/eModesUpdates.ts b/generator/features/eModesUpdates.ts index a6c8d4871..8a6ff2455 100644 --- a/generator/features/eModesUpdates.ts +++ b/generator/features/eModesUpdates.ts @@ -44,14 +44,14 @@ export const eModeUpdates: FeatureModule = { const response: CodeArtifact = { code: { fn: [ - `function eModeCategoriesUpdates() public pure override returns (IEngine.EModeCategoryUpdate[] memory) { - IEngine.EModeCategoryUpdate[] memory eModeUpdates = new IEngine.EModeCategoryUpdate[](${ + `function eModeCategoriesUpdates() public pure override returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) { + IAaveV3ConfigEngine.EModeCategoryUpdate[] memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](${ cfg.length }); ${cfg .map( - (cfg, ix) => `eModeUpdates[${ix}] = IEngine.EModeCategoryUpdate({ + (cfg, ix) => `eModeUpdates[${ix}] = IAaveV3ConfigEngine.EModeCategoryUpdate({ eModeCategory: ${cfg.eModeCategory}, ltv: ${cfg.ltv}, liqThreshold: ${cfg.liqThreshold}, diff --git a/generator/features/priceFeedsUpdates.ts b/generator/features/priceFeedsUpdates.ts index 6bac2d2fe..42e1b5c2b 100644 --- a/generator/features/priceFeedsUpdates.ts +++ b/generator/features/priceFeedsUpdates.ts @@ -30,14 +30,14 @@ export const priceFeedsUpdates: FeatureModule = { const response: CodeArtifact = { code: { fn: [ - `function priceFeedsUpdates() public pure override returns (IEngine.PriceFeedUpdate[] memory) { - IEngine.PriceFeedUpdate[] memory priceFeedsUpdates = new IEngine.PriceFeedUpdate[](${ + `function priceFeedsUpdates() public pure override returns (IAaveV3ConfigEngine.PriceFeedUpdate[] memory) { + IAaveV3ConfigEngine.PriceFeedUpdate[] memory priceFeedsUpdates = new IAaveV3ConfigEngine.PriceFeedUpdate[](${ cfg.length }); ${cfg .map( - (cfg, ix) => `priceFeedsUpdates[${ix}] = IEngine.PriceFeedUpdate({ + (cfg, ix) => `priceFeedsUpdates[${ix}] = IAaveV3ConfigEngine.PriceFeedUpdate({ asset: ${cfg.asset}, priceFeed: ${cfg.priceFeed} });` diff --git a/generator/features/rateUpdates.ts b/generator/features/rateUpdates.ts index 4f65a5764..68e1b4152 100644 --- a/generator/features/rateUpdates.ts +++ b/generator/features/rateUpdates.ts @@ -85,14 +85,14 @@ export const rateUpdatesV2: FeatureModule = { public pure override - returns (IEngine.RateStrategyUpdate[] memory) + returns (IAaveV2ConfigEngine.RateStrategyUpdate[] memory) { - IEngine.RateStrategyUpdate[] memory rateStrategies = new IEngine.RateStrategyUpdate[](${ + IAaveV2ConfigEngine.RateStrategyUpdate[] memory rateStrategies = new IAaveV2ConfigEngine.RateStrategyUpdate[](${ cfg.length }); ${cfg .map( - (cfg, ix) => `rateStrategies[${ix}] = IEngine.RateStrategyUpdate({ + (cfg, ix) => `rateStrategies[${ix}] = IAaveV2ConfigEngine.RateStrategyUpdate({ asset: ${cfg.asset}, params: Rates.RateStrategyParams({ optimalUtilizationRate: ${cfg.params.optimalUtilizationRate}, @@ -140,14 +140,14 @@ export const rateUpdatesV3: FeatureModule = { public pure override - returns (IEngine.RateStrategyUpdate[] memory) + returns (IAaveV3ConfigEngine.RateStrategyUpdate[] memory) { - IEngine.RateStrategyUpdate[] memory rateStrategies = new IEngine.RateStrategyUpdate[](${ + IAaveV3ConfigEngine.RateStrategyUpdate[] memory rateStrategies = new IAaveV3ConfigEngine.RateStrategyUpdate[](${ cfg.length }); ${cfg .map( - (cfg, ix) => `rateStrategies[${ix}] = IEngine.RateStrategyUpdate({ + (cfg, ix) => `rateStrategies[${ix}] = IAaveV3ConfigEngine.RateStrategyUpdate({ asset: ${cfg.asset}, params: Rates.RateStrategyParams({ optimalUsageRatio: ${cfg.params.optimalUtilizationRate}, diff --git a/lib/aave-helpers b/lib/aave-helpers index 8f3870f8f..707ad78ff 160000 --- a/lib/aave-helpers +++ b/lib/aave-helpers @@ -1 +1 @@ -Subproject commit 8f3870f8fc162d356062f16b42d2769145b3b696 +Subproject commit 707ad78ffd9f58fedd85a029f32ac52ef74af15a diff --git a/lib/forge-std b/lib/forge-std deleted file mode 160000 index f73c73d20..000000000 --- a/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 diff --git a/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol b/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol new file mode 100644 index 000000000..6523e9bdd --- /dev/null +++ b/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; +import {AaveV3PayloadEthereum} from 'aave-helpers/v3-config-engine/AaveV3PayloadEthereum.sol'; +import {IAaveV3ConfigEngine} from 'aave-helpers/v3-config-engine/IAaveV3ConfigEngine.sol'; + +/** + * @title Test + * @author BGD + * - Snapshot: link + * - Discussion: link + */ +contract AaveV3Ethereum_Test_20231024 is AaveV3PayloadEthereum { + function capsUpdates() public pure override returns (IAaveV3ConfigEngine.CapsUpdate[] memory) { + IAaveV3ConfigEngine.CapsUpdate[] memory capsUpdate = new IAaveV3ConfigEngine.CapsUpdate[](1); + + capsUpdate[0] = IAaveV3ConfigEngine.CapsUpdate({ + asset: AaveV3EthereumAssets.wstETH_UNDERLYING, + supplyCap: 10_000_000, + borrowCap: 100_000 + }); + + return capsUpdate; + } +} diff --git a/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol b/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol new file mode 100644 index 000000000..3267fcf13 --- /dev/null +++ b/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol'; + +import 'forge-std/Test.sol'; +import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol'; +import {AaveV3Ethereum_Test_20231024} from './AaveV3Ethereum_Test_20231024.sol'; + +/** + * @dev Test for AaveV3Ethereum_Test_20231024 + * command: make test-contract filter=AaveV3Ethereum_Test_20231024 + */ +contract AaveV3Ethereum_Test_20231024_Test is ProtocolV3TestBase { + AaveV3Ethereum_Test_20231024 internal proposal; + + function setUp() public { + vm.createSelectFork(vm.rpcUrl('mainnet'), 18420791); + proposal = new AaveV3Ethereum_Test_20231024(); + } + + /** + * @dev executes the generic test suite including e2e and config snapshots + */ + function test_defaultProposalExecution() public { + defaultTest('AaveV3Ethereum_Test_20231024', AaveV3Ethereum.POOL, address(proposal)); + } +} diff --git a/src/20231024_AaveV3Ethereum_Test/Test.md b/src/20231024_AaveV3Ethereum_Test/Test.md new file mode 100644 index 000000000..a7a499cd4 --- /dev/null +++ b/src/20231024_AaveV3Ethereum_Test/Test.md @@ -0,0 +1,22 @@ +--- +title: "Test" +author: "BGD" +discussions: "link" +--- + +## Simple Summary + +## Motivation + +## Specification + +## References + +- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol) +- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol) +- [Snapshot](link) +- [Discussion](link) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol b/src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol new file mode 100644 index 000000000..54774de98 --- /dev/null +++ b/src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from 'aave-helpers/GovV3Helpers.sol'; +import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; +import {AaveV3Ethereum_Test_20231024} from './AaveV3Ethereum_Test_20231024.sol'; + +/** + * @dev Deploy Ethereum + * command: make deploy-ledger contract=src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol:DeployEthereum chain=mainnet + */ +contract DeployEthereum is EthereumScript { + function run() external broadcast { + // deploy payloads + AaveV3Ethereum_Test_20231024 payload0 = new AaveV3Ethereum_Test_20231024(); + + // compose action + IPayloadsControllerCore.ExecutionAction[] + memory actions = new IPayloadsControllerCore.ExecutionAction[](1); + actions[0] = GovV3Helpers.buildAction(address(payload0)); + + // register action at payloadsController + GovV3Helpers.createPayload(actions); + } +} + +/** + * @dev Create Proposal + * command: make deploy-ledger contract=src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol:CreateProposal chain=mainnet + */ +contract CreateProposal is EthereumScript { + function run() external broadcast { + // create payloads + PayloadsControllerUtils.Payload[] memory payloads = new PayloadsControllerUtils.Payload[](1); + + // compose actions for validation + IPayloadsControllerCore.ExecutionAction[] + memory actionsEthereum = new IPayloadsControllerCore.ExecutionAction[](1); + actionsEthereum[0] = GovV3Helpers.buildAction(address(0)); + payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum); + + // create proposal + GovV3Helpers.createProposal2_5( + payloads, + GovV3Helpers.ipfsHashFile(vm, 'src/20231024_AaveV3Ethereum_Test/Test.md') + ); + } +} diff --git a/src/20231024_AaveV3Ethereum_Test/config.json b/src/20231024_AaveV3Ethereum_Test/config.json new file mode 100644 index 000000000..4bffb50dc --- /dev/null +++ b/src/20231024_AaveV3Ethereum_Test/config.json @@ -0,0 +1,29 @@ +{ + "rootOptions": { + "pools": [ + "AaveV3Ethereum" + ], + "title": "Test", + "shortName": "Test", + "date": "20231024", + "author": "BGD", + "discussion": "link", + "snapshot": "link" + }, + "poolOptions": { + "AaveV3Ethereum": { + "configs": { + "CAPS_UPDATE": [ + { + "asset": "AaveV3EthereumAssets.wstETH_UNDERLYING", + "supplyCap": "10_000_000", + "borrowCap": "100_000" + } + ] + }, + "features": [ + "CAPS_UPDATE" + ] + } + } +} \ No newline at end of file From 3c679aec6a88da94768b1414f7cbe4c6a7270d59 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Tue, 24 Oct 2023 17:13:36 +0200 Subject: [PATCH 17/18] fix: add initial readme --- .github/workflows/pull_request_template.md | 8 +- README.md | 97 ++++++++++++++++------ 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/.github/workflows/pull_request_template.md b/.github/workflows/pull_request_template.md index deaf15b38..2edea017a 100644 --- a/.github/workflows/pull_request_template.md +++ b/.github/workflows/pull_request_template.md @@ -2,10 +2,4 @@ - [ ] payload contains header comment linking discussion & snapshot - [ ] a test covering the changes is included -- [ ] new scripts are included (excluding ipfs hash & deployed payload addresses) -- [ ] DO NOT ALTER CODE UNRELATED TO THIS SPECIFIC AIP - -## References - -- [Discussion](link to forum) -- [Snapshot](link to snapshot) +- [ ] scripts are included diff --git a/README.md b/README.md index cfedd1231..e2e364778 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,16 @@ -# BGD forge template +# Aave proposals v3 -Basic template with prettier and rest configuration +This repository contains various proposals targeting the Aave governance. +In addition to the actual proposals this repository also contains tooling to standardize certain protocol tasks. +The tooling documentation is co-located with the relevant smart contracts. -To create a new project using this template run +## Tooling -```shell -$ forge init --template bgd-labs/bgd-forge-template my_new_project -``` - -## Recommended modules - -[bgd-labs/solidity-utils](https://github.com/bgd-labs/solidity-utils) - common contracts we use everywhere, ie transparent proxy and around - -[bgd-labs/aave-address-book](https://github.com/bgd-labs/aave-address-book) - the best and only source about all deployed Aave ecosystem related contracts across all the chains - -[bgd-labs/aave-helpers](https://github.com/bgd-labs/aave-helpers) - useful utils for integration, and not only testing related to Aave ecosystem contracts +### Config engine -[Rari-Capital/solmate](https://github.com/Rari-Capital/solmate) - one of the best sources of base contracts for ERC20, ERC21, which will work with transparent proxy pattern out of the box +The AaveV3ConfigEngine ([Docs](https://github.com/bgd-labs/aave-helpers/tree/master/src/v3-config-engine#how-to-use-the-engine)) is a helper smart contract to abstract good practices when doing "admin" interactions with the Aave v3 protocol, but built on top, without touching the core contracts. -[OpenZeppelin/openzeppelin-contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) - another very reputable and well organized source of base contracts for tokens, access control and many others +A less comprehensive version of the engine also exists for [protocol v2](https://github.com/bgd-labs/aave-helpers/tree/master/src/v2-config-engine). ## Development @@ -30,27 +22,82 @@ The template ships with sensible default so you can use default `foundry` comman ```sh cp .env.example .env forge install +yarn +``` + +### Create an aip + +This repository includes a generator to help you bootstrap the required files for an `AIP`. +To generate a proposal you need to run: `yarn generate` + +To get a full list of available commands run `yarn generate --help` + +```sh +yarn generate --help +yarn run v1.22.19 +$ tsx generator/cli --help +Usage: proposal-generator [options] + +CLI to generate aave proposals + +Options: + -V, --version output the version number + -f, --force force creation (might overwrite existing files) + -p, --pools (choices: "AaveV2Ethereum", "AaveV2EthereumAMM", "AaveV2Polygon", "AaveV2Avalanche", + "AaveV3Ethereum", "AaveV3Polygon", "AaveV3Avalanche", "AaveV3Optimism", + "AaveV3Arbitrum", "AaveV3Metis", "AaveV3Base") + -t, --title aip title + -a, --author author + -d, --discussion forum link + -s, --snapshot snapshot link + -c, --configFile path to config file + -h, --help display help for command ``` +If you have any feedback regarding the generator (bugs, improvements, features), don't hesitate to create an issue. We'd `<3` to see contributions. + ### Test ```sh +# You can use vanilla forge to customize your test +# https://book.getfoundry.sh/reference/forge/forge-test forge test +# We also provide a script with sensible defaults to just test a single contract matching a filter +make test-contract filter=ENS ``` -## Advanced features +### Deploy + +The makefile contains some generic templates for proposal deployments. +To deploy a contract you can run `make deploy-ledger contract=pathToContract:Contract chain=chainAlias`. +The generator will inline exact instructions on the generated scripts. + +## Proposal creation + +To create a proposal you have to do three things: + +1. deploy the payload & register it on the payloadsController +2. create an aip +3. create the mainnet proposal + +While the first two steps can be performed in parallel, the final proposal creation relies on (1) and (2). +Every step can in theory be performed by a different entity. + +The address creating the mainnet proposal(3) requires 80k AAVE of proposition power. -### Diffing +### 1. Deploy payload -For contracts upgrading implementations it's quite important to diff the implementation code to spot potential issues and ensure only the intended changes are included. -Therefore the `Makefile` includes some commands to streamline the diffing process. +The payload is always deployed on the chain it affects. +Therefore you need to adjust the relevant script accordingly. +The generated scripts include exact instrauctions on what to execute. -#### Download +### 2. Create an aip -You can `download` the current contract code of a deployed contract via `make download chain=polygon address=0x00`. This will download the contract source for specified address to `src/etherscan/chain_address`. This command works for all chains with a etherscan compatible block explorer. +The aip can be co-located with the proposal code as a markdown file. +This repository will manage the upload to ipfs automatically once a pr is merged to `main`. -#### Git diff +### 3. Create proposal -You can `git-diff` a downloaded contract against your src via `make git-diff before=./etherscan/chain_address after=./src out=filename`. This command will diff the two folders via git patience algorithm and write the output to `diffs/filename.md`. +The proposal requires at least one `payload` and the `encodedHash`. -**Caveat**: If the onchain implementation was verified using flatten, for generating the diff you need to flatten the new contract via `forge flatten` and supply the flattened file instead fo the whole `./src` folder. +:tada: From 9c726b34d6ccf9aab30b0e4ef702035f619ef383 Mon Sep 17 00:00:00 2001 From: sakulstra Date: Tue, 24 Oct 2023 17:14:37 +0200 Subject: [PATCH 18/18] fix: remove test files --- .../AaveV3Ethereum_Test_20231024.sol | 26 ---------- .../AaveV3Ethereum_Test_20231024.t.sol | 28 ----------- src/20231024_AaveV3Ethereum_Test/Test.md | 22 --------- .../Test_20231024.s.sol | 48 ------------------- src/20231024_AaveV3Ethereum_Test/config.json | 29 ----------- 5 files changed, 153 deletions(-) delete mode 100644 src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol delete mode 100644 src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol delete mode 100644 src/20231024_AaveV3Ethereum_Test/Test.md delete mode 100644 src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol delete mode 100644 src/20231024_AaveV3Ethereum_Test/config.json diff --git a/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol b/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol deleted file mode 100644 index 6523e9bdd..000000000 --- a/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; -import {AaveV3PayloadEthereum} from 'aave-helpers/v3-config-engine/AaveV3PayloadEthereum.sol'; -import {IAaveV3ConfigEngine} from 'aave-helpers/v3-config-engine/IAaveV3ConfigEngine.sol'; - -/** - * @title Test - * @author BGD - * - Snapshot: link - * - Discussion: link - */ -contract AaveV3Ethereum_Test_20231024 is AaveV3PayloadEthereum { - function capsUpdates() public pure override returns (IAaveV3ConfigEngine.CapsUpdate[] memory) { - IAaveV3ConfigEngine.CapsUpdate[] memory capsUpdate = new IAaveV3ConfigEngine.CapsUpdate[](1); - - capsUpdate[0] = IAaveV3ConfigEngine.CapsUpdate({ - asset: AaveV3EthereumAssets.wstETH_UNDERLYING, - supplyCap: 10_000_000, - borrowCap: 100_000 - }); - - return capsUpdate; - } -} diff --git a/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol b/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol deleted file mode 100644 index 3267fcf13..000000000 --- a/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol'; - -import 'forge-std/Test.sol'; -import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol'; -import {AaveV3Ethereum_Test_20231024} from './AaveV3Ethereum_Test_20231024.sol'; - -/** - * @dev Test for AaveV3Ethereum_Test_20231024 - * command: make test-contract filter=AaveV3Ethereum_Test_20231024 - */ -contract AaveV3Ethereum_Test_20231024_Test is ProtocolV3TestBase { - AaveV3Ethereum_Test_20231024 internal proposal; - - function setUp() public { - vm.createSelectFork(vm.rpcUrl('mainnet'), 18420791); - proposal = new AaveV3Ethereum_Test_20231024(); - } - - /** - * @dev executes the generic test suite including e2e and config snapshots - */ - function test_defaultProposalExecution() public { - defaultTest('AaveV3Ethereum_Test_20231024', AaveV3Ethereum.POOL, address(proposal)); - } -} diff --git a/src/20231024_AaveV3Ethereum_Test/Test.md b/src/20231024_AaveV3Ethereum_Test/Test.md deleted file mode 100644 index a7a499cd4..000000000 --- a/src/20231024_AaveV3Ethereum_Test/Test.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: "Test" -author: "BGD" -discussions: "link" ---- - -## Simple Summary - -## Motivation - -## Specification - -## References - -- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.sol) -- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20231024_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231024.t.sol) -- [Snapshot](link) -- [Discussion](link) - -## Copyright - -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol b/src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol deleted file mode 100644 index 54774de98..000000000 --- a/src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from 'aave-helpers/GovV3Helpers.sol'; -import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; -import {AaveV3Ethereum_Test_20231024} from './AaveV3Ethereum_Test_20231024.sol'; - -/** - * @dev Deploy Ethereum - * command: make deploy-ledger contract=src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol:DeployEthereum chain=mainnet - */ -contract DeployEthereum is EthereumScript { - function run() external broadcast { - // deploy payloads - AaveV3Ethereum_Test_20231024 payload0 = new AaveV3Ethereum_Test_20231024(); - - // compose action - IPayloadsControllerCore.ExecutionAction[] - memory actions = new IPayloadsControllerCore.ExecutionAction[](1); - actions[0] = GovV3Helpers.buildAction(address(payload0)); - - // register action at payloadsController - GovV3Helpers.createPayload(actions); - } -} - -/** - * @dev Create Proposal - * command: make deploy-ledger contract=src/20231024_AaveV3Ethereum_Test/Test_20231024.s.sol:CreateProposal chain=mainnet - */ -contract CreateProposal is EthereumScript { - function run() external broadcast { - // create payloads - PayloadsControllerUtils.Payload[] memory payloads = new PayloadsControllerUtils.Payload[](1); - - // compose actions for validation - IPayloadsControllerCore.ExecutionAction[] - memory actionsEthereum = new IPayloadsControllerCore.ExecutionAction[](1); - actionsEthereum[0] = GovV3Helpers.buildAction(address(0)); - payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum); - - // create proposal - GovV3Helpers.createProposal2_5( - payloads, - GovV3Helpers.ipfsHashFile(vm, 'src/20231024_AaveV3Ethereum_Test/Test.md') - ); - } -} diff --git a/src/20231024_AaveV3Ethereum_Test/config.json b/src/20231024_AaveV3Ethereum_Test/config.json deleted file mode 100644 index 4bffb50dc..000000000 --- a/src/20231024_AaveV3Ethereum_Test/config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "rootOptions": { - "pools": [ - "AaveV3Ethereum" - ], - "title": "Test", - "shortName": "Test", - "date": "20231024", - "author": "BGD", - "discussion": "link", - "snapshot": "link" - }, - "poolOptions": { - "AaveV3Ethereum": { - "configs": { - "CAPS_UPDATE": [ - { - "asset": "AaveV3EthereumAssets.wstETH_UNDERLYING", - "supplyCap": "10_000_000", - "borrowCap": "100_000" - } - ] - }, - "features": [ - "CAPS_UPDATE" - ] - } - } -} \ No newline at end of file