Skip to content

Issue 93 - #105

Merged
matteoettam09 merged 4 commits into
mainfrom
issue-93
Nov 19, 2025
Merged

Issue 93#105
matteoettam09 merged 4 commits into
mainfrom
issue-93

Conversation

@matteoettam09

@matteoettam09 matteoettam09 commented Nov 18, 2025

Copy link
Copy Markdown
Member

Summary by Sourcery

Introduce a protocol-wide emergency pause mechanism, integrate OpenZeppelin’s Pausable into core contracts, and simplify vault decommissioning logic

New Features:

  • Add guardian role and admin-controlled pauseAll/unpauseAll functions in OrionConfig for emergency protocol pausing
  • Expose pause and unpause methods on vaults and orchestrators to support global pause functionality

Enhancements:

  • Apply whenNotPaused guards to vault deposit/redeem functions and upkeep methods in orchestrators
  • Streamline vault decommissioning by using remove() return value instead of contains()+remove()

Documentation:

  • Define GuardianUpdated, ProtocolPaused, and ProtocolUnpaused events in EventsLib

Tests:

  • Add ProtocolPause.test.ts to verify emergency pause and unpause flows

Summary by CodeRabbit

  • New Features

    • Added protocol-wide pause/unpause mechanism enabling authorized parties to temporarily halt protocol operations.
    • Introduced guardian role management for emergency pause capabilities with admin-only controls.
    • Added pause/unpause functions to orchestrators with access controls.
  • Tests

    • Added comprehensive test suite validating pause/unpause functionality, role management, and access control enforcement.

Test Coverage:
1. Guardian Role Management (3 tests)
2. Pause All Functionality (4 tests)
3. Unpause All Functionality (4 tests)
4. Paused State Enforcement (7 tests)
5. Individual Contract Pause Access Control (6 tests)
6. Integration Scenarios (5 tests)
…vaultType variable and inefficient contains+remove pattern and Unnecessary Zero Assignments
@sourcery-ai

sourcery-ai Bot commented Nov 18, 2025

Copy link
Copy Markdown

Reviewer's Guide

This PR integrates an emergency pause/unpause framework led by a new guardian role (alongside admin) across OrionConfig, vaults, and orchestrators, refactors vault decommissioning cleanup to use boolean-returning remove(), and removes redundant state initializations in OrionVault.

Sequence diagram for protocol emergency pause flow

sequenceDiagram
    actor Admin
    participant OrionConfig
    participant InternalStatesOrchestrator
    participant LiquidityOrchestrator
    participant OrionVault
    Admin->>OrionConfig: setGuardian(address)
    Guardian->>OrionConfig: pauseAll()
    OrionConfig->>InternalStatesOrchestrator: pause()
    OrionConfig->>LiquidityOrchestrator: pause()
    OrionConfig->>OrionVault: pause() (for each vault)
    OrionConfig-->>Guardian: emit ProtocolPaused(guardian)
    Admin->>OrionConfig: unpauseAll()
    OrionConfig->>InternalStatesOrchestrator: unpause()
    OrionConfig->>LiquidityOrchestrator: unpause()
    OrionConfig->>OrionVault: unpause() (for each vault)
    OrionConfig-->>Admin: emit ProtocolUnpaused(admin)
Loading

Class diagram for emergency pause integration

classDiagram
    class OrionConfig {
        +address admin
        +address guardian
        +function setGuardian(address)
        +function pauseAll()
        +function unpauseAll()
    }
    class OrionVault {
        +function pause()
        +function unpause()
        +requestDeposit(uint256) whenNotPaused
        +cancelDepositRequest(uint256) whenNotPaused
        +requestRedeem(uint256) whenNotPaused
        +cancelRedeemRequest(uint256) whenNotPaused
    }
    class InternalStatesOrchestrator {
        +function pause()
        +function unpause()
        +performUpkeep(bytes) whenNotPaused
    }
    class LiquidityOrchestrator {
        +function pause()
        +function unpause()
        +performUpkeep(bytes) whenNotPaused
    }
    OrionConfig --> OrionVault : calls pause()/unpause()
    OrionConfig --> InternalStatesOrchestrator : calls pause()/unpause()
    OrionConfig --> LiquidityOrchestrator : calls pause()/unpause()
    OrionConfig <|-- Ownable2Step
    OrionVault <|-- ERC4626
    OrionVault <|-- ReentrancyGuard
    OrionVault <|-- Pausable
    InternalStatesOrchestrator <|-- Ownable2Step
    InternalStatesOrchestrator <|-- ReentrancyGuard
    InternalStatesOrchestrator <|-- Pausable
    LiquidityOrchestrator <|-- Ownable2Step
    LiquidityOrchestrator <|-- ReentrancyGuard
    LiquidityOrchestrator <|-- Pausable
Loading

File-Level Changes

Change Details Files
Introduce emergency pausing mechanism across protocol
  • Imported Pausable in OrionConfig, OrionVault, InternalStatesOrchestrator, LiquidityOrchestrator
  • Added guardian state, setGuardian, pauseAll and unpauseAll functions in OrionConfig
  • Added pause() and unpause() methods in vaults and orchestrators restricted to OrionConfig
  • Applied whenNotPaused modifiers to critical vault and upkeep functions
  • Emitted new events: GuardianUpdated, ProtocolPaused, ProtocolUnpaused in EventsLib
  • Added ProtocolPause.test.ts to cover pause/unpause workflows
contracts/OrionConfig.sol
contracts/vaults/OrionVault.sol
contracts/orchestrators/InternalStatesOrchestrator.sol
contracts/orchestrators/LiquidityOrchestrator.sol
contracts/libraries/EventsLib.sol
contracts/interfaces/IInternalStateOrchestrator.sol
contracts/interfaces/ILiquidityOrchestrator.sol
contracts/interfaces/IOrionVault.sol
test/ProtocolPause.test.ts
Refactor vault decommissioning cleanup logic
  • Replaced contains()+remove() pattern with single remove() call and result check
contracts/OrionConfig.sol
Remove redundant state initializations in OrionVault
  • Eliminated explicit zero assignments for _totalAssets, _pendingDeposit, and _pendingRedeem
contracts/vaults/OrionVault.sol

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@immunefi-magnus

Copy link
Copy Markdown

🛡️ Immunefi PR Reviews

We noticed that your project isn't set up for automatic code reviews. If you'd like this PR reviewed by the Immunefi team, you can request it manually using the link below:

🔗 Send this PR in for review

Once submitted, we'll take care of assigning a reviewer and follow up here.

@coderabbitai

coderabbitai Bot commented Nov 18, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This pull request adds emergency pause/unpause capabilities to the Orion protocol. It introduces a guardian role in OrionConfig, extends InternalStatesOrchestrator and LiquidityOrchestrator with Pausable inheritance, guards critical performUpkeep functions with whenNotPaused modifiers, and includes comprehensive test coverage for pause scenarios and access control validation.

Changes

Cohort / File(s) Summary
Core Protocol Pause Logic
contracts/OrionConfig.sol, contracts/orchestrators/InternalStatesOrchestrator.sol, contracts/orchestrators/LiquidityOrchestrator.sol
Added guardian state variable and setGuardian() function; introduced pauseAll()/unpauseAll() with role-based access control; integrated Pausable inheritance and pause()/unpause() external functions guarded by OrionConfig authorization; guarded performUpkeep() with whenNotPaused modifier.
Interface Definitions
contracts/interfaces/IInternalStateOrchestrator.sol, contracts/interfaces/ILiquidityOrchestrator.sol
Added pause() and unpause() external function declarations to both interfaces to expose emergency pause control.
Event Library
contracts/libraries/EventsLib.sol
Added three new indexed events: GuardianUpdated(address guardian), ProtocolPaused(address pauser), ProtocolUnpaused(address unpauser).
Vault Cleanup
contracts/vaults/OrionVault.sol
Removed redundant explicit 0-initializations of state variables, replaced with comment noting automatic initialization.
Test Suite
test/ProtocolPause.test.ts
Added comprehensive test coverage for guardian management, pauseAll/unpauseAll flows, access control enforcement, paused state verification, performUpkeep blocking, and integration scenarios across all orchestrators and vaults.
Contract Artifacts
artifacts/contracts/.../OrionConfig.json, artifacts/contracts/.../IInternalStateOrchestrator.json, artifacts/contracts/.../ILiquidityOrchestrator.json, artifacts/contracts/.../EventsLib.json, artifacts/contracts/.../LiquidityOrchestrator.json, artifacts/contracts/.../OrionAssetERC4626ExecutionAdapter.json, artifacts/contracts/.../OrionAssetERC4626PriceAdapter.json, artifacts/contracts/.../PriceAdapterRegistry.json, artifacts/contracts/.../KBestTvlWeightedAverage.json, artifacts/contracts/.../KBestTvlWeightedAverageInvalid.json
Updated bytecode and deployedBytecode fields reflecting compiled contract changes; ABI entries reflect new functions and events.

Sequence Diagram(s)

sequenceDiagram
    actor Admin
    participant OrionConfig
    participant InternalStatesOrch
    participant LiquidityOrch
    
    Admin->>OrionConfig: setGuardian(newGuardian)
    OrionConfig-->>Admin: GuardianUpdated event
    
    Note over Admin,LiquidityOrch: Pause Scenario
    Admin->>OrionConfig: pauseAll()
    OrionConfig->>InternalStatesOrch: pause()
    InternalStatesOrch-->>OrionConfig: ✓
    OrionConfig->>LiquidityOrch: pause()
    LiquidityOrch-->>OrionConfig: ✓
    OrionConfig-->>Admin: ProtocolPaused event
    
    Note over InternalStatesOrch,LiquidityOrch: While Paused
    Admin->>InternalStatesOrch: performUpkeep()
    InternalStatesOrch-->>Admin: ✗ EnforcedPause
    
    Note over Admin,LiquidityOrch: Unpause Scenario
    Admin->>OrionConfig: unpauseAll()
    OrionConfig->>InternalStatesOrch: unpause()
    InternalStatesOrch-->>OrionConfig: ✓
    OrionConfig->>LiquidityOrch: unpause()
    LiquidityOrch-->>OrionConfig: ✓
    OrionConfig-->>Admin: ProtocolUnpaused event
    
    Admin->>InternalStatesOrch: performUpkeep()
    InternalStatesOrch-->>Admin: ✓
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Access control verification in pause/unpause functions: Ensure that pause() and unpause() in both orchestrators correctly restrict calls to OrionConfig only, and that setGuardian() restricts to admin.
  • whenNotPaused guard placement: Verify that performUpkeep() guards are correctly placed and no other critical state-modifying functions are missing pause guards.
  • Test coverage comprehensiveness: The test suite is extensive; verify all pause/unpause scenarios, role transitions, and cross-contract interactions are properly validated and expectations match implementation.
  • Event emission consistency: Confirm GuardianUpdated, ProtocolPaused, and ProtocolUnpaused events are emitted at the correct points with correct parameters.
  • Artifact consistency: Verify that ABI and bytecode updates across multiple files are coherent and no conflicts exist in compiled output.

Possibly related PRs

  • PR #91: Modifies LiquidityOrchestrator.sol for internal transfer calls and deposit/redeem processing reordering; overlaps with this PR's changes to the same contract's inheritance and performUpkeep method.
  • PR #68: Adds ReentrancyGuard/nonReentrant guarding to InternalStatesOrchestrator and LiquidityOrchestrator; this PR layers Pausable/whenNotPaused on the same contracts, creating potential ordering and interaction concerns.

Poem

🐰 A guardian hops forth with pause in paw,
When danger looms, we freeze it all,
Orchestrators bow to the pause command,
Emergency control—now that's grand!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Issue 93' is too vague and generic; it provides no meaningful information about what the pull request accomplishes beyond referencing an issue number. Update the title to describe the actual change, such as 'Add protocol-wide emergency pause mechanism' or 'Implement guardian role and pause/unpause controls'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-93

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `contracts/OrionConfig.sol:426-435` </location>
<code_context>
+    function unpauseAll() external onlyAdmin {
</code_context>

<issue_to_address>
**suggestion (bug_risk):** UnpauseAll may revert if any orchestrator or vault is already unpaused.

Consider checking the paused state before calling _unpause(), or handling already-unpaused contracts with try/catch, if idempotent behavior is preferred.
</issue_to_address>

### Comment 2
<location> `contracts/vaults/OrionVault.sol:690-692` </location>
<code_context>
+
+    /// @notice Pauses the contract
+    /// @dev Can only be called by OrionConfig for emergency situations
+    function pause() external {
+        if (msg.sender != address(config)) revert ErrorsLib.UnauthorizedAccess();
+        _pause();
+    }
+
</code_context>

<issue_to_address>
**suggestion:** Pause and unpause functions do not restrict repeated calls.

Consider adding a check for the current paused state before calling _pause() or _unpause() to make these functions idempotent.

Suggested implementation:

```
    /// @notice Pauses the contract
    /// @dev Can only be called by OrionConfig for emergency situations
    function pause() external {
        if (msg.sender != address(config)) revert ErrorsLib.UnauthorizedAccess();
        if (paused()) revert ErrorsLib.AlreadyPaused();
        _pause();
    }

    /// @notice Unpauses the contract
    /// @dev Can only be called by OrionConfig for emergency situations
    function unpause() external {
        if (msg.sender != address(config)) revert ErrorsLib.UnauthorizedAccess();
        if (!paused()) revert ErrorsLib.NotPaused();
        _unpause();
    }

```

You will need to ensure that `ErrorsLib.AlreadyPaused()` and `ErrorsLib.NotPaused()` exist in your error library. If not, you should add these custom errors to `ErrorsLib`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread contracts/OrionConfig.sol Outdated
Comment thread contracts/vaults/OrionVault.sol Outdated
@codecov

codecov Bot commented Nov 18, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.66667% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
contracts/OrionConfig.sol 94.11% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
contracts/interfaces/ILiquidityOrchestrator.sol (1)

96-103: Pause/unpause interface additions look consistent, but note source-level breakage

The new pause() / unpause() surface is consistent with the protocol-wide emergency controls and the docs clearly scope authority to OrionConfig. This is a source-breaking change for any existing ILiquidityOrchestrator implementations (including older mocks), so make sure all implementers are updated accordingly.

If downstream consumers need to check paused state through the interface rather than concrete types, consider adding a function paused() external view returns (bool); in a follow-up.

contracts/interfaces/IInternalStateOrchestrator.sol (1)

109-115: Emergency pause controls added cleanly to internal state orchestrator interface

Adding pause() / unpause() here keeps InternalStateOrchestrator aligned with the protocol-wide emergency control pattern and the docs clearly state OrionConfig as the caller.

This does change the interface surface, so ensure the concrete orchestrator implementation and any test doubles/mocks are updated. As with the liquidity orchestrator, a paused() view in the interface could be useful if callers ever need to branch on paused state via the interface type.

contracts/interfaces/IOrionVault.sol (1)

214-220: Pause/unpause additions align with protocol design; consider grouping under config/emergency section

The new pause() / unpause() functions give OrionConfig a clear emergency control surface on each vault and match the ABI artifacts.

Two minor points to keep in mind:

  • This is a source-breaking change for any external IOrionVault implementers; ensure all concrete vaults and mocks are updated.
  • For readability, these OrionConfig-only controls might be clearer if grouped under a dedicated “config/emergency” section rather than immediately after the liquidity-orchestrator-related accrueCuratorFees, since they are not callable by the orchestrator.

Function signatures and docs themselves look good.

contracts/OrionConfig.sol (1)

5-5: Consider removing unused import.

The Pausable.sol import appears unnecessary since OrionConfig doesn't inherit from Pausable. The pause/unpause calls on orchestrators and vaults use their interface methods, which don't require this import.

Apply this diff to remove the unused import:

-import "@openzeppelin/contracts/utils/Pausable.sol";
test/ProtocolPause.test.ts (3)

570-586: Assert the initial performUpkeep succeeds to isolate the pause effect

In “should block epoch progression when paused”, the first call to internalStatesOrchestrator.performUpkeep("0x") is executed but not asserted. If that call ever reverts for unrelated reasons, the test will fail before even exercising the pause logic, and if it silently stops doing anything, the test still passes as long as the later paused call reverts.

Consider asserting the pre‑pause call explicitly so the test isolates the pause behavior:

-      // Start an epoch
-      await internalStatesOrchestrator.connect(automationRegistry).performUpkeep("0x");
+      // Start an epoch – should work before pause
+      await expect(
+        internalStatesOrchestrator.connect(automationRegistry).performUpkeep("0x"),
+      ).to.not.be.reverted;

This keeps the intent clear and makes the failure mode more informative if the non‑paused path regresses.


271-277: Drop the void operator on expect(...) chains for clarity

Several assertions use void expect(await contract.paused()).to.be.true/false;. The void operator is unnecessary here: the assertion side‑effects already happen when accessing the chained properties, and any failure will still throw.

For readability and to match common test style, you can simplify these to:

-      void expect(await internalStatesOrchestrator.paused()).to.be.true;
+      expect(await internalStatesOrchestrator.paused()).to.be.true;

-      void expect(await transparentVault.paused()).to.be.false;
+      expect(await transparentVault.paused()).to.be.false;

(and similarly for the other paused/unpaused checks). This removes noise without changing behavior.

Also applies to: 282-286, 292-295, 303-308, 321-327, 333-336, 342-345, 352-355, 532-543


302-303: Avoid hard‑coded vault type enum literal in tests

The tests rely on getAllOrionVaults(0) with an inline comment // VaultType.Transparent = 0. If the enum ordering in VaultType ever changes, this will silently become incorrect.

Consider at least centralizing this as a named constant in the test file:

-  const allTransparentVaults = await config.getAllOrionVaults(0); // VaultType.Transparent = 0
+  const VAULT_TYPE_TRANSPARENT = 0;
+  const allTransparentVaults = await config.getAllOrionVaults(VAULT_TYPE_TRANSPARENT);

This keeps usage self‑documenting and reduces the chance of mismatches if the enum evolves.

Also applies to: 350-351

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f63c126 and 9001dae.

📒 Files selected for processing (23)
  • artifacts/contracts/OrionConfig.sol/OrionConfig.json (7 hunks)
  • artifacts/contracts/execution/OrionAssetERC4626ExecutionAdapter.sol/OrionAssetERC4626ExecutionAdapter.json (1 hunks)
  • artifacts/contracts/interfaces/IInternalStateOrchestrator.sol/IInternalStateOrchestrator.json (2 hunks)
  • artifacts/contracts/interfaces/ILiquidityOrchestrator.sol/ILiquidityOrchestrator.json (2 hunks)
  • artifacts/contracts/interfaces/IOrionTransparentVault.sol/IOrionTransparentVault.json (2 hunks)
  • artifacts/contracts/interfaces/IOrionVault.sol/IOrionVault.json (2 hunks)
  • artifacts/contracts/libraries/EventsLib.sol/EventsLib.json (3 hunks)
  • artifacts/contracts/mocks/MockERC4626Asset.sol/MockERC4626Asset.json (1 hunks)
  • artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json (5 hunks)
  • artifacts/contracts/price/OrionAssetERC4626PriceAdapter.sol/OrionAssetERC4626PriceAdapter.json (1 hunks)
  • artifacts/contracts/price/PriceAdapterRegistry.sol/PriceAdapterRegistry.json (1 hunks)
  • artifacts/contracts/strategies/KBestTvlWeightedAverage.sol/KBestTvlWeightedAverage.json (1 hunks)
  • artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json (1 hunks)
  • artifacts/contracts/vaults/OrionVault.sol/OrionVault.json (5 hunks)
  • contracts/OrionConfig.sol (4 hunks)
  • contracts/interfaces/IInternalStateOrchestrator.sol (1 hunks)
  • contracts/interfaces/ILiquidityOrchestrator.sol (1 hunks)
  • contracts/interfaces/IOrionVault.sol (1 hunks)
  • contracts/libraries/EventsLib.sol (1 hunks)
  • contracts/orchestrators/InternalStatesOrchestrator.sol (4 hunks)
  • contracts/orchestrators/LiquidityOrchestrator.sol (4 hunks)
  • contracts/vaults/OrionVault.sol (8 hunks)
  • test/ProtocolPause.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
contracts/orchestrators/InternalStatesOrchestrator.sol (2)
test/orchestrator/OrchestratorPerformUpkeep.test.ts (3)
  • it (635-744)
  • it (746-2549)
  • upkeepNeeded (2245-2250)
test/orchestrator/Orchestrators.test.ts (5)
  • epochDuration (2180-2190)
  • internalStatesOrchestrator (2467-2476)
  • it (2456-2540)
  • expect (2498-2502)
  • upkeepNeeded (2150-2155)
test/ProtocolPause.test.ts (2)
test/orchestrator/Orchestrators.test.ts (1)
  • it (2456-2540)
test/orchestrator/OrchestratorPerformUpkeep.test.ts (2)
  • it (746-2549)
  • it (635-744)
contracts/vaults/OrionVault.sol (2)
test/orchestrator/OrchestratorPerformUpkeep.test.ts (1)
  • ABSOLUTE_VAULT_DEPOSIT (90-2550)
test/OrionConfigVault.test.ts (2)
  • it (556-566)
  • it (337-373)
contracts/orchestrators/LiquidityOrchestrator.sol (2)
test/orchestrator/OrchestratorPerformUpkeep.test.ts (6)
  • liquidityUpkeepNeeded (2323-2332)
  • liquidityUpkeepNeeded (2313-2321)
  • _liquidityUpkeepNeeded (2334-2342)
  • it (635-744)
  • liquidityUpkeepNeeded (2301-2311)
  • it (746-2549)
test/orchestrator/Orchestrators.test.ts (3)
  • liquidityUpkeepNeeded (2218-2226)
  • liquidityUpkeepNeeded (2228-2237)
  • _liquidityUpkeepNeeded (2239-2247)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Sourcery review
  • GitHub Check: Build, Lint and Test
🔇 Additional comments (27)
artifacts/contracts/price/PriceAdapterRegistry.sol/PriceAdapterRegistry.json (1)

252-253: Expected artifact recompilation with maintained backward compatibility.

The bytecode and deployedBytecode have been updated, which is expected when contracts are recompiled. The ABI (lines 5–251) remains unchanged, confirming that the public interface is unaffected. This maintains backward compatibility for all contract callers and existing integrations.

artifacts/contracts/execution/OrionAssetERC4626ExecutionAdapter.sol/OrionAssetERC4626ExecutionAdapter.json (1)

172-173: Artifact bytecode changes expected from source recompilation.

The bytecode and deployedBytecode have been updated (lines 172–173), which is the expected result of recompiling the contract after source-level changes elsewhere in the codebase (e.g., OrionConfig guardian role integration for pause controls). The ABI definition (lines 5–171) remains unchanged, preserving the contract's public interface and ensuring backward compatibility.

artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json (1)

178-179: Bytecode regeneration expected; ABI remains stable.

The bytecode has been regenerated (lines 178–179), which is expected when the Solidity compiler processes the contract following dependency updates (pause/unpause functionality additions mentioned in the PR objectives). Importantly, the contract's ABI remains unchanged across all function signatures, events, and error types, confirming that the contract's public interface is stable and backward compatible.

To confirm the recompilation is intentional and the contract behaves as expected, please verify:

  • That the underlying Solidity source for KBestTvlWeightedAverageInvalid remains functionally unchanged
  • That test coverage for this contract passes with the updated bytecode
artifacts/contracts/mocks/MockERC4626Asset.sol/MockERC4626Asset.json (1)

852-853: Bytecode regeneration is expected and requires no action.

The source file contracts/mocks/MockERC4626Asset.sol was not modified in this PR commit. The bytecode regeneration in the artifact is a normal byproduct of the project's full recompilation when other contracts were updated (specifically when Pausable was added to core protocol contracts in commit 93ca4b8).

Since MockERC4626Asset is a test helper mock with no pause functionality required, no source code changes are needed. The artifact update is consistent with standard build behavior.

artifacts/contracts/strategies/KBestTvlWeightedAverage.sol/KBestTvlWeightedAverage.json (1)

222-223: Artifact-only bytecode update; ABI remains stable

Only bytecode and deployedBytecode changed; ABI and link references are untouched, so interface-level behavior for KBestTvlWeightedAverage stays the same. Assuming this was regenerated from the updated sources with the project’s standard build, this looks good.

artifacts/contracts/price/OrionAssetERC4626PriceAdapter.sol/OrionAssetERC4626PriceAdapter.json (1)

110-111: Recompiled artifact with unchanged ABI

The diff only updates bytecode and deployedBytecode; the ABI and structure are identical. This is consistent with recompiling OrionAssetERC4626PriceAdapter after upstream contract/library changes and is safe from an integration standpoint.

contracts/libraries/EventsLib.sol (1)

49-59: New guardian/protocol pause events are well-scoped

GuardianUpdated, ProtocolPaused, and ProtocolUnpaused are clearly documented and give a clean, centralized event surface for monitoring protocol-wide emergency actions. Signatures (single indexed address) are reasonable and align with the new OrionConfig pause/guardian controls.

artifacts/contracts/interfaces/IOrionVault.sol/IOrionVault.json (1)

787-793: Vault ABI updated with pause/unpause; matches interface changes

The ABI additions for pause and unpause are additive and align with the new functions in contracts/interfaces/IOrionVault.sol (no params, nonpayable). This is safe for integrators at the ABI level, but make sure all deployed/compiled vault implementations and test mocks now implement these functions.

Also applies to: 1069-1075

artifacts/contracts/interfaces/IOrionTransparentVault.sol/IOrionTransparentVault.json (1)

823-829: Transparent vault ABI gains pause/unpause in line with protocol controls

The new pause / unpause entries are additive ABI changes and align with the emergency controls you’re rolling out across vaults. As with IOrionVault, this is fine for callers but requires all IOrionTransparentVault implementations/mocks to include these functions.

Also applies to: 1130-1136

artifacts/contracts/interfaces/ILiquidityOrchestrator.sol/ILiquidityOrchestrator.json (1)

69-75: LGTM! Interface additions align with emergency pause pattern.

The pause() and unpause() function signatures are correctly defined in the ABI, enabling external callers to invoke emergency pause controls on the LiquidityOrchestrator.

Also applies to: 195-201

artifacts/contracts/interfaces/IInternalStateOrchestrator.sol/IInternalStateOrchestrator.json (1)

203-209: LGTM! Interface additions align with emergency pause pattern.

The pause() and unpause() function signatures are correctly defined in the ABI, enabling external callers to invoke emergency pause controls on the InternalStateOrchestrator.

Also applies to: 249-255

artifacts/contracts/libraries/EventsLib.sol/EventsLib.json (1)

51-63: LGTM! Event definitions support protocol pause observability.

The three new events (GuardianUpdated, ProtocolPaused, ProtocolUnpaused) provide proper observability for protocol-wide pause operations. The indexed parameters enable efficient filtering by guardian/pauser address.

Also applies to: 234-259

contracts/vaults/OrionVault.sol (3)

8-8: LGTM! Pausable inheritance follows OpenZeppelin patterns.

The Pausable contract is correctly imported and added to the inheritance chain, enabling emergency pause controls for the vault.

Also applies to: 41-41


347-347: LGTM! User-facing LP functions are properly protected.

The whenNotPaused modifier is correctly applied to all user-facing deposit and redemption request functions (requestDeposit, cancelDepositRequest, requestRedeem, cancelRedeemRequest). This prevents users from initiating or canceling requests during an emergency pause while preserving the system's ability to complete existing requests via orchestrator operations.

Also applies to: 370-370, 396-396, 419-419


688-700: LGTM! Pause/unpause access control is correctly restricted.

The pause() and unpause() functions correctly restrict access to the OrionConfig contract (via msg.sender != address(config) check), establishing a centralized emergency control point. The revert with ErrorsLib.UnauthorizedAccess() provides clear error messaging.

contracts/orchestrators/InternalStatesOrchestrator.sol (3)

6-6: LGTM! Pausable inheritance follows OpenZeppelin patterns.

The Pausable contract is correctly imported and added to the inheritance chain, enabling emergency pause controls for the orchestrator.

Also applies to: 30-30


273-273: LGTM! performUpkeep correctly protected with whenNotPaused.

The whenNotPaused modifier is appropriately added to performUpkeep, preventing state processing operations during an emergency pause. The modifier is correctly combined with existing access control (onlyAuthorizedTrigger) and reentrancy protection (nonReentrant).


730-742: LGTM! Pause/unpause access control is correctly restricted.

The pause() and unpause() functions correctly restrict access to the OrionConfig contract (via msg.sender != address(config) check), establishing a centralized emergency control point consistent with the vault implementation.

contracts/orchestrators/LiquidityOrchestrator.sol (3)

6-6: LGTM! Pausable inheritance follows OpenZeppelin patterns.

The Pausable contract is correctly imported and added to the inheritance chain, enabling emergency pause controls for the liquidity orchestrator.

Also applies to: 29-29


327-327: LGTM! performUpkeep correctly protected with whenNotPaused.

The whenNotPaused modifier is appropriately added to performUpkeep, preventing liquidity operations (buy/sell orders, deposit/redeem fulfillment) during an emergency pause. The modifier is correctly combined with existing access control (onlyAuthorizedTrigger) and reentrancy protection (nonReentrant).


514-526: LGTM! Pause/unpause access control is correctly restricted.

The pause() and unpause() functions correctly restrict access to the OrionConfig contract (via msg.sender != address(config) check), establishing a centralized emergency control point consistent with other orchestrator and vault implementations.

contracts/OrionConfig.sol (3)

36-37: LGTM! Guardian role properly implemented.

The guardian address state variable and setGuardian function are correctly implemented with admin-only access control. The GuardianUpdated event provides proper observability for guardian changes.

Also applies to: 393-396


356-363: LGTM! Improved decommissioning logic.

The refactored logic uses the return value from remove() directly instead of calling contains() followed by remove(), improving gas efficiency. The logic correctly handles cases where the vault is in either the encrypted or transparent vault list.


401-402: Access control asymmetry is intentional and aligns with security best practices.

Verification confirms the pauseAll/unpauseAll asymmetry is correct: guardian and admin roles have narrowly-scoped pause/freeze rights with no unilateral unpause ability, while admin holds full-power recovery actions gated by governance oversight. The implementation matches established DeFi security patterns (Aave, Compound) where emergency actors retain only the minimal abilities needed to stop loss, without recovery authority.

artifacts/contracts/vaults/OrionVault.sol/OrionVault.json (1)

224-233: LGTM! Artifact correctly reflects Pausable integration.

The OrionVault artifact correctly includes:

  • EnforcedPause and ExpectedPause error types from OpenZeppelin Pausable
  • Paused and Unpaused events
  • pause(), unpause(), and paused() function signatures

These additions align with the implementation changes in OrionVault.sol.

Also applies to: 489-501, 602-614, 1281-1300

artifacts/contracts/OrionConfig.sol/OrionConfig.json (1)

108-120: Guardian + global pause/unpause ABI looks consistent with intended design

The added events (GuardianUpdated, ProtocolPaused, ProtocolUnpaused), guardian() accessor, and setGuardian, pauseAll, unpauseAll functions are coherently wired in the ABI and line up with how the tests use them (event args and call signatures). I don’t see ABI‑level issues here; assuming these artifacts are compiler‑generated, they look good to ship.

Also applies to: 198-223, 453-465, 658-664, 789-801, 951-957

artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json (1)

48-57: Pause/unpause ABI and errors align with Pausable semantics and tests

The additions of EnforcedPause / ExpectedPause errors, Paused/Unpaused events, and pause(), paused(), unpause() functions give LiquidityOrchestrator a clean Pausable surface. These match how the new tests interact with the contract (checking paused() and expecting EnforcedPause on upkeep when paused), so from an ABI perspective this looks correct and consistent.

Also applies to: 196-208, 215-227, 556-575, 798-804

Comment thread contracts/OrionConfig.sol
@matteoettam09
matteoettam09 merged commit 0321cce into main Nov 19, 2025
3 of 5 checks passed
@matteoettam09
matteoettam09 deleted the issue-93 branch November 19, 2025 10:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
contracts/OrionConfig.sol (1)

35-37: Guardian + pauseAll/unpauseAll wiring is coherent; consider idempotency and setup guards

Access control is consistent with the intended model (admin sets guardian; guardian or admin can pause; only admin can unpause; orchestrators restrict pause/unpause to OrionConfig via onlyConfig). Two follow‑ups to consider:

  • pauseAll / unpauseAll will revert once orchestrators are already in the target state because OpenZeppelin’s Pausable reverts on redundant _pause()/_unpause(). If you expect scripts or operators to call these functions idempotently, consider tracking a protocol‑level paused flag in OrionConfig, or checking orchestrator state (and skipping calls) instead of always invoking pause/unpause.
  • If pauseAll/unpauseAll are called before internalStatesOrchestrator or liquidityOrchestrator are configured, the external calls will revert against address(0). A simple require(internalStatesOrchestrator != address(0) && liquidityOrchestrator != address(0), ...) would make the failure mode clearer.

Also applies to: 386-414

🧹 Nitpick comments (3)
contracts/orchestrators/LiquidityOrchestrator.sol (1)

6-7: Pausable integration is sound; consider making checkUpkeep pause‑aware

The LiquidityOrchestrator side of the pause mechanism is wired cleanly:

  • Inheriting Pausable, guarding performUpkeep with whenNotPaused, and restricting pause()/unpause() to onlyConfig aligns with the OrionConfig.pauseAll/unpauseAll entry points and prevents EOAs from pausing directly.

One behavioral refinement to consider:

  • checkUpkeep ignores the paused state, so while the protocol is paused it can still return upkeepNeeded = true, but any subsequent performUpkeep from an authorized caller will revert with EnforcedPause. For smoother Chainlink Automation behavior and less wasted gas during an emergency pause, you could short‑circuit at the top of checkUpkeep with a paused() check (e.g., return (false, "") when paused).

Also decide explicitly whether admin‑only operations like depositLiquidity, withdrawLiquidity, and claimProtocolFees should remain callable during a protocol pause (current behavior) or also be gated by whenNotPaused.

Also applies to: 29-30, 324-337, 512-520

contracts/orchestrators/InternalStatesOrchestrator.sol (1)

6-7: Pause wiring matches LiquidityOrchestrator; consider aligning checkUpkeep with paused state

The InternalStatesOrchestrator’s pause integration looks consistent:

  • Inheriting Pausable, adding pause()/unpause() restricted to onlyConfig, and gating performUpkeep with whenNotPaused all align with the protocol‑wide pauseAll/unpauseAll flow and centralize control in OrionConfig.

As with the liquidity side, checkUpkeep does not consider the paused state, so while paused it can still report upkeepNeeded = true (based on timing or phase), but any performUpkeep attempt by an authorized trigger will revert with EnforcedPause. If you want Chainlink Automation to back off cleanly while the protocol is paused, consider an early:

if (paused()) {
    return (false, "");
}

in checkUpkeep.

You may also want to document how paused() interacts with currentPhase and config.isSystemIdle() so operators understand that pausing mid‑epoch freezes the phase without resetting it.

Also applies to: 30-31, 151-155, 271-284, 729-737

test/ProtocolPause.test.ts (1)

302-334: Consider adding explicit vault behavior checks while paused

These tests thoroughly verify:

  • Guardian/admin access to pauseAll/unpauseAll
  • Orchestrators’ paused() flags
  • performUpkeep reverting under pause and resuming after unpause
  • Access control on orchestrators’ direct pause/unpause calls
  • Basic integration flows across multiple pause/unpause cycles

Given the PR’s goal of enforcing the pause across vault deposit/redeem flows as well, it would be useful to add a couple of cases that:

  • Assert user‑facing vault operations such as requestDeposit / requestRedeem (and possibly fulfill paths) revert while the protocol is paused, and
  • Verify that the same operations succeed again after unpauseAll.

That will catch any regressions in how vault‑level pause hooks are wired into the global emergency pause.

Also applies to: 382-461

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9001dae and e5cd7f7.

📒 Files selected for processing (9)
  • artifacts/contracts/OrionConfig.sol/OrionConfig.json (7 hunks)
  • artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json (5 hunks)
  • artifacts/contracts/strategies/KBestTvlWeightedAverage.sol/KBestTvlWeightedAverage.json (1 hunks)
  • artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json (1 hunks)
  • contracts/OrionConfig.sol (3 hunks)
  • contracts/orchestrators/InternalStatesOrchestrator.sol (5 hunks)
  • contracts/orchestrators/LiquidityOrchestrator.sol (4 hunks)
  • contracts/vaults/OrionVault.sol (1 hunks)
  • test/ProtocolPause.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • contracts/vaults/OrionVault.sol
  • artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json
  • artifacts/contracts/OrionConfig.sol/OrionConfig.json
🧰 Additional context used
🧬 Code graph analysis (2)
test/ProtocolPause.test.ts (2)
test/orchestrator/Orchestrators.test.ts (1)
  • it (2456-2540)
test/orchestrator/OrchestratorPerformUpkeep.test.ts (2)
  • it (746-2549)
  • it (635-744)
contracts/orchestrators/LiquidityOrchestrator.sol (2)
test/orchestrator/OrchestratorPerformUpkeep.test.ts (5)
  • liquidityUpkeepNeeded (2323-2332)
  • liquidityUpkeepNeeded (2313-2321)
  • _liquidityUpkeepNeeded (2334-2342)
  • it (635-744)
  • liquidityUpkeepNeeded (2301-2311)
test/orchestrator/Orchestrators.test.ts (3)
  • liquidityUpkeepNeeded (2218-2226)
  • liquidityUpkeepNeeded (2228-2237)
  • _liquidityUpkeepNeeded (2239-2247)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Sourcery review
  • GitHub Check: Build, Lint and Test
🔇 Additional comments (4)
artifacts/contracts/strategies/KBestTvlWeightedAverage.sol/KBestTvlWeightedAverage.json (1)

222-223: Artifact ABI unchanged; bytecode refresh looks fine

Only bytecode and deployedBytecode changed while the ABI and metadata stayed the same, which is consistent with a normal recompile. No interface-level concerns here.

contracts/OrionConfig.sol (1)

352-370: Simplified vault decommissioning removal logic looks correct

Switching to encryptedVaults.remove(vault) and falling back to transparentVaults.remove(vault) (reverting if both return false) preserves the previous behavior while being simpler and slightly cheaper. Given removeOrionVault only queues vaults that are already recognized as Orion vaults, the invariants still hold.

test/ProtocolPause.test.ts (1)

85-218: Realistic protocol fixture in beforeEach looks solid

The test setup builds a full environment (config, both orchestrators, price adapter registry, ERC4626 asset, adapters, vault factory + vault, and seeded liquidity) in the intended wiring order (config → liquidity orchestrator → internal states orchestrator), which is exactly what you want for exercising protocol‑level pause flows. This should give good confidence that the pause behavior matches real deployments.

artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json (1)

1-892: Focus code review on source files rather than compiled artifacts.

This is a compiled contract artifact—the ABI, bytecode, and deployedBytecode are auto-generated outputs. While the additions (EnforcedPause/ExpectedPause errors, Paused/Unpaused events, pause/paused/unpause functions) correctly reflect the emergency pause mechanism, the substantive review should focus on the source Solidity files: LiquidityOrchestrator.sol, InternalStatesOrchestrator.sol, and OrionConfig.sol.

The artifact itself is valid; the real concerns are in the implementation: access control validation, whenNotPaused modifier placement, orchestrator coordination, and integration with the guardian role. These can only be assessed in the source code.

@coderabbitai coderabbitai Bot mentioned this pull request Nov 19, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Dec 19, 2025
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