[VPD-1036] add Safe EBrake TX generator and fork simulation tooling#63
Conversation
Adds a CLI tool to generate Gnosis Safe TX Builder JSON for EBrake emergency actions, and a Mocha fork test to simulate and verify the batch against an archive node. The simulation includes an ACM pre-flight check that rejects unauthorized callers before any execution attempt.
Replaces the single aggregated state test with dynamically generated individual it() blocks so each market/action check gets its own named ✔ / ✘ line in Mocha output, making failures immediately identifiable without digging into assertion messages.
- Generator now accepts multiple operations in one run (upfront multi-select like `1,2,5`) and emits a single Safe batch. Metadata schema upgraded to `operations: string[]`; simulator reads both new and legacy shapes. - Per-market value input (CF/caps) gets a 3-option UX: uniform, per-market CLI, or JSON file (auto-generates a template pre-filled with current on-chain values on first file-mode run). - Market selection redesigned: 2-option menu (manual CLI or pick-by-symbol from `helpers/data/markets.json`); markets file is refetched on every run so it always matches the active network. - Simulator relocated from `scripts/` to `tests/hardhat/Fork/` so it runs under the project's standard hardhat test path. - Terminal colorization in the generator: red (errors), yellow (warnings), green (success), cyan (section headers), bold (final CTA). Zero-dep, respects `NO_COLOR` and non-TTY. - Dead code removed: unused EBRAKE_ABI entries, duplicate OUTPUT JSDoc, unused `ExportResult.label`, dead `receipt.status === 1` assertion, incorrect `Unauthorized` error contract-address source. - Generated artifacts moved into a single gitignored `helpers/data/` folder; no per-network prefix, no history archive — operator-local only. - New `README-EBrake.md` — operator guide with quickstart, end-to-end walkthrough, operation cheatsheet, Safe UI signing steps, troubleshooting, and network support matrix.
…t glob - Relocate scripts/simulateSafeEBrakeTx.ts (was tests/hardhat/Fork/...) Reason: paths.tests: "./tests" means anything under that dir runs on `yarn test` / CI lint; the simulator needs operator-generated JSON artifacts (gitignored) and would always fail there - Fix path resolution: ../../../helpers/data → ../helpers/data - Update the generator's end-of-run "Simulate:" hint - Update README-EBrake.md (Quickstart + walkthrough + ASCII diagram)
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
|
||
| --- | ||
|
|
||
| ## 4. Install |
There was a problem hiding this comment.
no way we will need this to install it
…oling - Default Safe address (0xCCa5...) shown as prompt default; Enter accepts it - Remove broken ACM pre-flight check — isAllowedToCall requires msg.sender to be the protected contract, not an external caller; ACM_ABI cleaned up too - Clarify simulateSafeEBrakeTx.ts is optional vs Safe Wallet native simulation - Set both FORKED_NETWORK and HARDHAT_FORK_NETWORK when --fork flag is used so Hardhat's built-in forking config is also activated
- Production commands + prerequisites moved to top - Remove testnet quickstart, install, flow diagram, generate detail, simulate detail, sign detail, and operation cheatsheet sections - Move 'What is EBrake?' to bottom as reference - Remove stale ACM check failed troubleshooting entry - Align safety principle #1 with optional simulation stance
|
#63 (comment)
On point printing the name↔address list in-terminal: I tried this earlier and with 40+ markets the output got long and cluttered, which felt off to me. Opening Happy to revisit either if you still prefer — could do per-network filenames ( (edit) fixed: a992515 |
- Add marketsCache and bscPoolsCache on StepContext - Populate cache on first step that needs markets or pool layout - Subsequent steps reuse in-memory data, skipping chain calls - Scope is per-run: next invocation refetches, so new markets surface - No persisted state, so cross-network mix-ups remain impossible - Print "Available markets: ..." inline after fetch so operators don't open markets.json
| if (!ethers.utils.isAddress(entered)) { | ||
| console.error(red("Invalid address!")); | ||
| rl.close(); | ||
| process.exit(1); | ||
| } |
|
|
||
| // ─── Network helpers ───────────────────────────────────────────────────────── | ||
|
|
||
| const getEBrakeAddress = async (networkName: string): Promise<string> => { |
There was a problem hiding this comment.
I think the proxy contract address is unlikely to change. Would it be better to define it as a constant (or an array) in the config file and reference it from there?
There was a problem hiding this comment.
Both approaches work here. The deployment artifact (deployments/<network>/EBrake.json) is already the canonical source of truth in this repo — BSC mainnet and testnet auto-resolve today, and future networks will too without a code change. That said, adding a EBRAKE_ADDRESSES constant map at the top as the primary lookup (with artifact as fallback, manual prompt as last resort) has a real benefit: known addresses are visible at a glance without digging into files. Happy to go either way — what's your preference?
| const filePath = entered.length > 0 ? entered : defaultPath; | ||
|
|
||
| if (!fs.existsSync(filePath)) { | ||
| console.log(`\n${filePath} not found — generating template with current on-chain ${cfg.kind} values...`); |
There was a problem hiding this comment.
The user might provide an incorrect path by mistake. Should we re-prompt them to enter the path again in that case?
There was a problem hiding this comment.
Both approaches make sense. Most operators will use the default path — if they type a custom path, it's likely intentional, so auto-generating a template there is fine. But a quick y/n confirmation before generating adds a safety net for the rare typo case without much friction. 659af81
Co-authored-by: GitGuru7 <128375421+GitGuru7@users.noreply.github.com>
yeah, i am not saying caching it across session, i am saying in the same session we could reuse it instead of loading before every step |
decrease_cf_pool prompted once per market and fanned the same cf to every pool the market was listed in, producing the same end state as decrease_cf (all pools). a market in N pools now yields N prompts with independent cf values, so the per-pool option can express per-pool divergence.
markets.json was written on first fetch but never read back by the generator. the artifact only created a cross-session footgun (stale cache silently loaded into a new run) without providing any runtime benefit. in-session reuse via ctx.marketsCache / ctx.bscPoolsCache is untouched.
|
Good catch — root cause was Fixed across two commits:
So for vAAVE (pools |
Got it — misread the original comment, apologies. cddbb25 removes the |
Fixed in fa6a44b. |
Fixed in c9c21f2. Four changes to the file-mode flow:
Applies to both |
|
lgtm now |
|
will merge first, retrospective comment is welcomed |
## 1.2.0-dev.7 (2026-04-21) * Merge pull request #63 from VenusProtocol/feat/VPD-1036 ([cd360b3](cd360b3)), closes [#63](#63) * Update helpers/generateSafeEBrakeJson.ts ([df290e7](df290e7)) * refactor: cache markets and pool data, show market list inline ([a992515](a992515)) * refactor(ebrake): drop markets.json disk cache, keep in-session reuse ([cddbb25](cddbb25)) * refactor(ebrake): extract pure validators and export helpers for testing ([f7f6f91](f7f6f91)) * refactor(simulation): expand state checks into per-assertion it() blocks ([7b41669](7b41669)) * feat: add --fork task flag and Venus chain hardfork config to hardhat ([42a1789](42a1789)) * feat: add Safe EBrake TX generator and fork simulation script ([e9d91d6](e9d91d6)) * feat(ebrake): file-mode UX — format hint, sticky path, auto-regen stale ([c9c21f2](c9c21f2)) * feat(ebrake): multi-op batching, per-market value inputs, operator docs ([b72c764](b72c764)) * feat(generateSafeEBrakeJson): enhance pool and market selection ([abd2088](abd2088)) * fix: prompt user before generating template for missing file path ([659af81](659af81)) * fix: resolve yarn lint formatting ([6fe4067](6fe4067)) * fix(ebrake): address PR review comments on generator and simulator tooling ([5e2211e](5e2211e)) * fix(ebrake): collect per-pool cf for decrease_cf_pool ([c12f9cc](c12f9cc)) * fix(ebrake): move simulator back to scripts/ to keep it out of CI test glob ([d552c57](d552c57)) * fix(ebrake): pool picker + fan-out confirm for bsc fan-out ops ([fa6a44b](fa6a44b)) * fix(gatherPerMarketValues): improve file path validation and error handling ([d176750](d176750)) * fix(getEBrakeAddress): improve address validation loop for user input ([c26a769](c26a769)) * docs: rename README-EBrake.md to ReadMe_EBrake_Safe_TX Generator.m ([50d9bd8](50d9bd8)) * docs(ebrake): drop opbnb/op/unichain from network matrix ([2c3e795](2c3e795)) * docs(ebrake): restructure README for emergency-first use ([8b77fe0](8b77fe0)), closes [#1](#1)






Summary
--fork <network>task flag and hardfork history for all Venus Protocol chains to supporthardhat_reseton non-mainnet chainsChanges
helpers/generateSafeEBrakeJson.ts(new)safeEBrakeTxBuilder.json(import into Gnosis Safe UI) andsafeEBrakeTxMetadata.json(audit trail)scripts/simulateSafeEBrakeTx.ts(new)isAllowedToCallfor every function in the batch before impersonating the Safe — fails fast if unauthorizedUnauthorizederror decodingit()blocks per market/action/cap assertion for clear ✔ / ✘ outputhardhat.config.ts--fork <network>override onTASK_TESTsetsFORKED_NETWORKenv varchainsconfig withcancun: 0for BSC, opBNB, Arbitrum, OP, Base, Unichain (mainnet + testnet)Test plan
npx hardhat run helpers/generateSafeEBrakeJson.ts --network bsctestnetnpx hardhat test scripts/simulateSafeEBrakeTx.ts --fork bsctestnet