Skip to content

Release: Emergency Shutdown Config, Dependency Hardening, Cooler Drip Proposal - #228

Merged
0xJem merged 67 commits into
masterfrom
develop
Jun 12, 2026
Merged

0xJem merged 67 commits into
masterfrom
develop

Conversation

@0xJem

@0xJem 0xJem commented Apr 9, 2026 •

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Emergency configs now support independent status-checks for shutdown verification.
    • New governance proposal to schedule and validate Cooler V2 LTV changes.
    • New operational scripts: change kernel executor, update Cooler LTV, and multisig batching ownership helpers.
  • Documentation

    • Added prerequisites: Node.js >=24 and pnpm 10.33.0.
    • Emergency ABI/config and schema extended for status checks.
  • Chores

    • CI bootstrapping consolidated into a reusable action; workflows simplified/renamed and dependency audit added.
  • Tests

    • Added proposal simulation test for the new governance proposal.

@coderabbitai

coderabbitai Bot commented Apr 9, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces an emergency statusCheck concept (schema, ABI, config, validator, docs); consolidates CI bootstrapping into a reusable composite action and updates workflows; pins Node/pnpm and enforces pnpm installs; adds OIP-194A proposal + test; adds ChangeKernelExecutor script and env entries; improves batch/script tooling and adds several operational scripts.

Changes

Emergency Configuration System

Layer / File(s) Summary
Schema / Data Shape
documentation/emergency/emergency-config.schema.json
Adds $defs/statusCheck and wires component.statusCheck with required fields contractKey, abi, functionName, trueIsShutdown.
ABI Registry
documentation/emergency/emergency-abis.json
Registers mintr.active() and trsry.active() view functions returning bool.
Config Data
documentation/emergency/emergency-config.json
Adds OlympusMinter/OlympusTreasury addresses and per-component statusCheck entries for treasury and minter; bumps version and lastUpdated.
Validation Logic
shell/validate-emergency-config.js
Validates statusCheck.abi presence, verifies statusCheck.functionName exists in ABI, and ensures statusCheck.contractKey maps to addresses for all availableOn chains.
Docs / Example
/.claude/commands/update-emergency-config.md
Documents statusCheck concept, generation guidance, example JSON, and ABI lookup updates.

CI Bootstrap Consolidation

Layer / File(s) Summary
New Composite Action
.github/actions/bootstrap/action.yml
Adds a composite action: reads Node from .nvmrc, installs pnpm, optionally installs Foundry (install-foundry input, default "true", pinned 1.5.1), runs pnpm install --frozen-lockfile.
Workflows Wiring
.github/workflows/*.yml
Replaces per-workflow explicit setup with a Bootstrap step invoking the local composite action; renames jobs (e.g., run-ci → descriptive names) and pins some action refs.
Audit Workflow
.github/workflows/audit.yml
Adds a dependency security audit using JamesRobertWiseman/pnpm-audit, failing on moderate+ severities and posting/updating a PR comment.

Node / Package Manager & Developer Tooling

Layer / File(s) Summary
Runtime / Engine Pins
.nvmrc, .node-version, package.json
Pins Node to v24 and packageManager: "pnpm@10.33.0"; adds engines.node >=24 and engines.pnpm.
Install Enforcement
package.json, .npmrc
Adds preinstall: "npx only-allow@1.2.2 pnpm" and .npmrc keys (engine-strict=true, prefer-frozen-lockfile=true, frozen-lockfile=true).
Dependency Overrides
package.json
Adds pnpm.overrides to pin selected transitive dependency versions.
Docs / Local Dev
README.md, AGENTS.md
Adds Node/pnpm prerequisites and small doc edits.
Dev Environment Metadata
.codex/environments/environment.toml
Adds autogenerated env metadata and action entries (lint/format/unit tests).

Governance Proposal: OIP-194A

Layer / File(s) Summary
New Proposal Contract
src/proposals/OIP_194A.sol
Adds OIP_194A GovernorBravoProposal that caches Kernel, builds three timed actions (increase guard, set target LTV/timestamp, restore guard) and includes validation assertions for schedule, slope, and guard restoration.
Test Harness
src/test/proposals/OIP_194A.t.sol
Adds OIP194ATest: mainnet fork at block 24_876_700, deploys proposal, initializes suite, simulates proposal execution.
Proposal Script Wiring
src/proposals/*
Adds OIP_194AProposalScript to wire the proposal into the ProposalScript framework.

Scripts / Environment & Batch Tooling

Layer / File(s) Summary
Env Data
src/scripts/env.json
Adds olympus.config entries (KernelExecutor, RoleAdmin) for multiple networks and treasuryWorkingGroup to mainnet.olympus.multisig.
Operational Script
src/scripts/ops/ChangeKernelExecutor.s.sol
Adds ChangeKernelExecutorScript with run() and changeExecutorToDaoMs() to compare and set Kernel executor to DAO multisig; includes ChangeKernelExecutor_UnexpectedExecutor error and logging.
Batch Script Enhancements
src/scripts/ops/lib/BatchScriptV2.sol
Adds _skipHeartbeatValidation flag and conditional heartbeat skip, setUpWithTreasuryWorkingGroupMS modifier, _logSafeTxDetails helper and integrated logs in multisig propose/send flows, and adjusts Tenderly callArgs formatting.
Operational Scripts
src/scripts/ops/CalculateCoolerLtvUpdate.s.sol, src/scripts/ops/batches/CCIPTokenPool.sol
Adds UpdateCoolerLtv script for CoolerV2 LTV updates; adds transferTokenPoolOwnershipToDaoMS and acceptTokenPoolOwnership batch entrypoints using Ownable2Step.
Ignore / Misc
.gitignore, .pnpm-store/
Adds .pnpm-store/ to .gitignore.
Review Guidance
.coderabbit.yaml
Marks src/scripts/**/*.sol as operational scripts and provides path-specific review exemptions.

Sequence Diagram(s)

sequenceDiagram
    actor Governor
    participant OIP as OIP_194A
    participant Kernel
    participant Oracle as CoolerV2_LTV_Oracle

    Governor->>OIP: _deploy()
    OIP->>Kernel: cache Kernel address

    Governor->>OIP: _build()
    OIP->>Oracle: read maxOriginationLtvRateOfChange
    Oracle-->>OIP: currentRate
    OIP->>Kernel: queue Action 1 (increase guard)
    OIP->>Kernel: queue Action 2 (set target LTV/timestamp)
    OIP->>Kernel: queue Action 3 (restore guard)

    Governor->>OIP: _run()
    OIP->>Kernel: execute queued actions
    Kernel->>Oracle: apply timed actions

    Governor->>OIP: _validate()
    OIP->>Oracle: verify scheduled LTV, monotonicity, slope, guard restored
    Oracle-->>OIP: validation data
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • 0xNooodle
  • pbendus
  • zeroxnoodle

"🐇
I hopped through configs, CI, and script,
added status checks and a bootstrap to commit.
Proposals queued, LTV set with care,
multisig logs and envs now all there.
A rabbit’s tiny hop — changes bundled fair."

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three major change categories in the PR: emergency shutdown config enhancements, dependency hardening measures, and the new Cooler Drip proposal.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Comment @coderabbitai help to get the list of available commands and usage tips.

0xJem and others added 16 commits April 13, 2026 13:33
…26-04-02

chore: hardening baseline before Dependabot remediation
Implement the fork-simulated proposal and validation needed to raise the Cooler V2 origination LTV while temporarily increasing the oracle rate guard so the schedule can execute.
Keep the established OIP proposal naming and single-file script pattern while silencing the targeted solhint warnings for this proposal file.
Update the proposal description to state that the required schedule rate is measured at submission time and add a Markdown copy for previewing the rendered text.
Drop the temporary Markdown extraction file before opening the proposal PR so the branch only carries the proposal and test changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/scripts/ops/lib/BatchScriptV2.sol (1)

104-117: ⚡ Quick win

Make the ignored compatibility parameter explicit at runtime.

useDaoMS_ is intentionally ignored, but it is currently silent. Adding an explicit no-op/log when true reduces operator confusion in script invocations.

Proposed minimal patch
 modifier setUpWithTreasuryWorkingGroupMS(
     bool useDaoMS_,
     bool signOnly_,
     string memory argsFilePath_,
     string memory ledgerDerivationPath_,
     bytes memory signature_
 ) {
+    if (useDaoMS_) {
+        console2.log("setUpWithTreasuryWorkingGroupMS: useDaoMS_ is ignored");
+    }
     string memory chainName = ChainUtils._getChainName(block.chainid);
     _loadEnv(chainName);
     _loadArgs(argsFilePath_);

     address owner = _envAddressNotZero("olympus.multisig.treasuryWorkingGroup");
     _setUpBatchScript(signOnly_, owner, ledgerDerivationPath_, signature_);
     _;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/scripts/ops/lib/BatchScriptV2.sol` around lines 104 - 117, In the
modifier setUpWithTreasuryWorkingGroupMS, make the currently ignored parameter
useDaoMS_ explicit at runtime by adding a small conditional that detects if
useDaoMS_ is true and emits a clear warning (e.g., using
console.log/console.warn from Hardhat's console or another project logging
facility) so operators see the parameter was intentionally ignored; ensure you
also reference/consume useDaoMS_ to avoid “unused variable” warnings and add an
import for console (if using Hardhat) or call the existing logger used elsewhere
in this file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/scripts/ops/lib/BatchScriptV2.sol`:
- Around line 104-117: In the modifier setUpWithTreasuryWorkingGroupMS, make the
currently ignored parameter useDaoMS_ explicit at runtime by adding a small
conditional that detects if useDaoMS_ is true and emits a clear warning (e.g.,
using console.log/console.warn from Hardhat's console or another project logging
facility) so operators see the parameter was intentionally ignored; ensure you
also reference/consume useDaoMS_ to avoid “unused variable” warnings and add an
import for console (if using Hardhat) or call the existing logger used elsewhere
in this file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 487660f3-b812-4a62-981f-7233d04e6aef

📥 Commits

Reviewing files that changed from the base of the PR and between ae73419 and a385067.

📒 Files selected for processing (5)
  • .gitignore
  • src/scripts/env.json
  • src/scripts/ops/ChangeKernelExecutor.s.sol
  • src/scripts/ops/lib/BatchScriptV2.sol
  • src/test/proposals/OIP_194A.t.sol
✅ Files skipped from review due to trivial changes (3)
  • .gitignore
  • src/test/proposals/OIP_194A.t.sol
  • src/scripts/ops/ChangeKernelExecutor.s.sol
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/scripts/env.json

zeroxnoodle
zeroxnoodle previously approved these changes May 5, 2026
0xJem added 3 commits May 5, 2026 17:38
chore(lint): exclude irrelevant forge lint rules
Add Sepolia Cooler OLTV update script

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/scripts/ops/batches/CCIPTokenPool.sol`:
- Line 245: acceptTokenPoolOwnership currently runs under
setUpWithChainId(false) which executes as the deployer/team multisig and
therefore cannot call Ownable2Step.acceptOwnership (only daoMS, the pending
owner set by transferTokenPoolOwnershipToDaoMS, can). Change the modifier on
acceptTokenPoolOwnership to run as the daoMS caller (e.g. use
setUpWithChainId(true) or another helper that impersonates daoMS) so the call to
acceptOwnership will be made by daoMS; ensure acceptTokenPoolOwnership invokes
Ownable2Step.acceptOwnership while msg.sender is daoMS and keep
transferTokenPoolOwnershipToDaoMS unchanged.

In `@src/scripts/ops/CalculateCoolerLtvUpdate.s.sol`:
- Around line 18-31: The README/example values for TARGET_OLTV are far too large
for uint96 and must be replaced with realistic 18-decimal OLTV values; update
the usage examples in the CalculateCoolerLtvUpdate.s.sol comment (references:
contract/script name UpdateCoolerLtv, function signatures updateOltv(uint96) and
updateOltvFromEnv()) to use values that fit uint96 and represent 18-decimal LTVs
(e.g. replace the 39‑digit examples with 1050000000000000000 for 105% LTV or
similar valid uint96 values) and ensure the note recommends using the env
variant for large-but-valid values.
- Around line 163-166: The env value read in updateOltvFromEnv uses
vm.envUint("TARGET_OLTV") which returns a uint256 and is directly cast to uint96
causing silent truncation; fix by keeping the value as uint256 first, validate
that it is <= type(uint96).max (and optionally >= 0 if needed), and only then
cast to uint96 and call updateOltv(targetOltv); if the check fails, revert or
vm.stop with a clear error mentioning TARGET_OLTV to avoid accidental
truncation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 42d2258f-bc46-4bc1-9207-1777d2687108

📥 Commits

Reviewing files that changed from the base of the PR and between a385067 and e2ab2e6.

📒 Files selected for processing (5)
  • .coderabbit.yaml
  • .github/workflows/lint.yml
  • foundry.toml
  • src/scripts/ops/CalculateCoolerLtvUpdate.s.sol
  • src/scripts/ops/batches/CCIPTokenPool.sol
✅ Files skipped from review due to trivial changes (1)
  • foundry.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/lint.yml

}

/// @notice Accepts the ownership of the TokenPool
function acceptTokenPoolOwnership() external setUpWithChainId(false) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

setUpWithChainId(false) will cause acceptOwnership() to fail.

Ownable2Step.acceptOwnership() requires the pending owner (daoMS) to be the caller. After transferTokenPoolOwnershipToDaoMS() sets daoMS as the pending owner, only daoMS can call acceptOwnership(). Using setUpWithChainId(false) executes from the team/deployer multisig, which will revert with OwnableUnauthorizedAccount.

🐛 Proposed fix
-    function acceptTokenPoolOwnership() external setUpWithChainId(false) {
+    function acceptTokenPoolOwnership() external setUpWithChainId(true) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function acceptTokenPoolOwnership() external setUpWithChainId(false) {
function acceptTokenPoolOwnership() external setUpWithChainId(true) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/scripts/ops/batches/CCIPTokenPool.sol` at line 245,
acceptTokenPoolOwnership currently runs under setUpWithChainId(false) which
executes as the deployer/team multisig and therefore cannot call
Ownable2Step.acceptOwnership (only daoMS, the pending owner set by
transferTokenPoolOwnershipToDaoMS, can). Change the modifier on
acceptTokenPoolOwnership to run as the daoMS caller (e.g. use
setUpWithChainId(true) or another helper that impersonates daoMS) so the call to
acceptOwnership will be made by daoMS; ensure acceptTokenPoolOwnership invokes
Ownable2Step.acceptOwnership while msg.sender is daoMS and keep
transferTokenPoolOwnershipToDaoMS unchanged.

Comment on lines +18 to +31
* Usage (direct value - may fail with very large numbers):
* forge script src/scripts/ops/CalculateCoolerLtvUpdate.s.sol:UpdateCoolerLtv \
* --rpc-url sepolia \
* --account <your-wallet> \
* --broadcast \
* --sig "updateOltv(uint96)" 872636398584498440592620626480000000000
*
* Usage (via environment variable - recommended for large numbers):
* TARGET_OLTV=872636398584498440592620626480000000000 \
* forge script src/scripts/ops/CalculateCoolerLtvUpdate.s.sol:UpdateCoolerLtv \
* --rpc-url sepolia \
* --account <your-wallet> \
* --broadcast \
* --sig "updateOltvFromEnv()"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Example values exceed uint96 capacity.

The example TARGET_OLTV values (39 digits) vastly exceed uint96.max (~7.9e28, 29 digits). Per the interface, OLTV uses 18 decimals, so reasonable values like 1.05e18 ($1.05 LTV) fit within uint96. These examples appear incorrect and would cause silent truncation if used with updateOltvFromEnv().

Consider updating to realistic values, e.g., 1050000000000000000 for 105% LTV.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/scripts/ops/CalculateCoolerLtvUpdate.s.sol` around lines 18 - 31, The
README/example values for TARGET_OLTV are far too large for uint96 and must be
replaced with realistic 18-decimal OLTV values; update the usage examples in the
CalculateCoolerLtvUpdate.s.sol comment (references: contract/script name
UpdateCoolerLtv, function signatures updateOltv(uint96) and updateOltvFromEnv())
to use values that fit uint96 and represent 18-decimal LTVs (e.g. replace the
39‑digit examples with 1050000000000000000 for 105% LTV or similar valid uint96
values) and ensure the note recommends using the env variant for large-but-valid
values.

Comment on lines +163 to +166
function updateOltvFromEnv() public {
uint96 targetOltv = uint96(vm.envUint("TARGET_OLTV"));
updateOltv(targetOltv);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Unsafe cast from uint256 to uint96 silently truncates large values.

vm.envUint() returns uint256, and the direct cast to uint96 will silently truncate values exceeding uint96.max (~7.9e28). For an operational script, this could result in setting an unintended LTV.

🛡️ Proposed fix to add bounds validation
 function updateOltvFromEnv() public {
-    uint96 targetOltv = uint96(vm.envUint("TARGET_OLTV"));
+    uint256 rawValue = vm.envUint("TARGET_OLTV");
+    require(rawValue <= type(uint96).max, "TARGET_OLTV exceeds uint96 max");
+    uint96 targetOltv = uint96(rawValue);
     updateOltv(targetOltv);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/scripts/ops/CalculateCoolerLtvUpdate.s.sol` around lines 163 - 166, The
env value read in updateOltvFromEnv uses vm.envUint("TARGET_OLTV") which returns
a uint256 and is directly cast to uint96 causing silent truncation; fix by
keeping the value as uint256 first, validate that it is <= type(uint96).max (and
optionally >= 0 if needed), and only then cast to uint96 and call
updateOltv(targetOltv); if the check fails, revert or vm.stop with a clear error
mentioning TARGET_OLTV to avoid accidental truncation.

@0xJem
0xJem merged commit b1015ea into master Jun 12, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants