Skip to content

Passive curator - #101

Merged
matteoettam09 merged 5 commits into
mainfrom
passive-curator
Nov 17, 2025
Merged

Passive curator#101
matteoettam09 merged 5 commits into
mainfrom
passive-curator

Conversation

@matteoettam09

@matteoettam09 matteoettam09 commented Nov 17, 2025

Copy link
Copy Markdown
Member

Summary by Sourcery

Refactor passive curation to a push-based intent submission model and enforce explicit curator whitelisting across vault and config modules.

New Features:

  • Add curator whitelist management in OrionConfig and enforce whitelisted curators for vault creation and updates
  • Define IOrionStrategy#submitIntent to replace pull-based computeIntent/validateStrategy/getStatefulIntent
  • Implement push-based intent submission in KBestTvlWeightedAverage strategy and introduce KBestTvlWeightedAverageInvalid for negative testing
  • Update TransparentVaultFactory and TransparentVault to drop passive-curator detection and rely on explicit intent submissions

Enhancements:

  • Simplify strategy interface by removing stateful fallback logic and ERC-165 detection in vaults
  • Handle non-ERC4626 assets gracefully in TVL calculations by treating failures as dust amounts
  • Adjust weight correction logic in the strategy to allocate residual intent scale to the first asset

Tests:

  • Update PassiveCuratorStrategy and orchestrator tests to whitelist curators and invoke submitIntent
  • Add test case to verify failure when strategy weights do not sum to required intentScale
  • Extend configuration tests for adding, removing, and enforcing curator whitelist

Chores:

  • Remove deprecated computeIntent, validateStrategy, getStatefulIntent, and passive curator flag from vault contracts

Summary by CodeRabbit

  • New Features

    • Curator whitelisting: curators must be registered before assignment.
    • Strategy intent submission: strategies can submit intents directly to vaults.
  • Changes

    • Passive-curator mode removed; active curator flow now standard.
    • Vault whitelist and curator update flows simplified to ensure underlying-asset consistency.
    • Strategy flow streamlined to on-demand intent computation and submission.

@matteoettam09
matteoettam09 marked this pull request as ready for review November 17, 2025 20:54
@sourcery-ai

sourcery-ai Bot commented Nov 17, 2025

Copy link
Copy Markdown

Reviewer's Guide

This PR transitions the passive curator architecture from a pull-based to a push-based model by replacing computeIntent/validateStrategy with a submitIntent API, removing on-vault passive detection and fallback, enforcing curator whitelisting in config and factory, refactoring the KBestTvlWeightedAverage strategy and vault contracts accordingly, updating orchestrator logic, and harmonizing all tests (including a new invalid strategy test case).

Sequence diagram for push-based passive curator intent submission

sequenceDiagram
    participant VaultFactory
    participant OrionConfig
    participant Curator (Smart Contract)
    participant Vault
    actor VaultOwner
    VaultOwner->>VaultFactory: createVault(curator)
    VaultFactory->>OrionConfig: isWhitelistedCurator(curator)
    alt curator is whitelisted
        VaultFactory->>Vault: deploy with curator
        Curator->>Vault: submitIntent(vault)
        Vault->>Vault: update _portfolioIntent
    else curator not whitelisted
        VaultFactory-->>VaultOwner: revert UnauthorizedAccess
    end
Loading

Entity relationship diagram for curator whitelisting in OrionConfig

erDiagram
    ORIONCONFIG {
        address id
        address[] whitelistedAssets
        address[] whitelistedVaultOwners
        address[] whitelistedCurators
    }
    CURATOR {
        address id
    }
    ORIONCONFIG ||--o{ CURATOR : "whitelistedCurators"
    VAULTOWNER {
        address id
    }
    ORIONCONFIG ||--o{ VAULTOWNER : "whitelistedVaultOwners"
Loading

Class diagram for updated passive curator architecture

classDiagram
    class OrionTransparentVault {
        - EnumerableMap.AddressToUintMap _portfolioIntent
        + updateCurator(address newCurator)
        + getIntent()
        // Removed: _isPassiveCurator, _updateCuratorType(), isPassiveCurator(), _computePassiveIntent()
    }
    class IOrionStrategy {
        + submitIntent(IOrionTransparentVault vault)
        // Removed: computeIntent(), validateStrategy(), getStatefulIntent()
    }
    class KBestTvlWeightedAverage {
        + k: uint16
        + config: IOrionConfig
        + submitIntent(IOrionTransparentVault vault)
        - _getAssetTVLs(address[] vaultWhitelistedAssets, uint16 n)
        - _selectTopKAssets(address[] vaultWhitelistedAssets, uint256[] tvls, uint16 n, uint16 kActual)
        - _calculatePositions(address[] tokens, uint256[] topTvls, uint16 kActual)
        // Removed: kMax, _statefulIntent, computeIntent(), validateStrategy(), getStatefulIntent()
    }
    class OrionConfig {
        + whitelistedCurators: EnumerableSet.AddressSet
        + addWhitelistedCurator(address curator)
        + removeWhitelistedCurator(address curator)
        + isWhitelistedCurator(address curator) : bool
    }
    OrionTransparentVault --> IOrionStrategy
    KBestTvlWeightedAverage ..|> IOrionStrategy
    OrionTransparentVault --> OrionConfig
    KBestTvlWeightedAverage --> OrionConfig
Loading

File-Level Changes

Change Details Files
Refactor IOrionStrategy and KBestTvlWeightedAverage to a push-based submitIntent API
  • Remove computeIntent, validateStrategy, getStatefulIntent from IOrionStrategy
  • Add submitIntent(IOrionTransparentVault) signature
  • Implement submitIntent in KBestTvlWeightedAverage and invoke vault.submitIntent(intent)
  • Remove stateful intent storage and fallback paths
contracts/interfaces/IOrionStrategy.sol
contracts/strategies/KBestTvlWeightedAverage.sol
Eliminate passive-curator detection and enforce whitelist in vault and factory
  • Remove _isPassiveCurator flag, isPassiveCurator(), and computePassiveIntent pathways
  • Require config.isWhitelistedCurator in updateCurator and TransparentVaultFactory
  • Strip curator type checks and vault-side validation logic
  • Update IOrionConfig with add/remove/isWhitelistedCurator
contracts/vaults/OrionTransparentVault.sol
contracts/factories/TransparentVaultFactory.sol
contracts/OrionConfig.sol
contracts/interfaces/IOrionConfig.sol
Adjust weight calculation and ERC4626 handling in KBestTvlWeightedAverage
  • Assign residual intentScale delta to first token instead of last
  • Catch totalAssets() failures and treat non-ERC4626 assets as minimal TVL
  • Remove unused kMax limit
contracts/strategies/KBestTvlWeightedAverage.sol
Update InternalStatesOrchestrator logic and orchestrator tests
  • Remove skip of vaults with empty intent in upkeep selection
  • Whiten passiveVault pipelines to always include submitIntent
  • Add whitelistedCurator setup in orchestrator tests
contracts/orchestrators/InternalStatesOrchestrator.sol
test/orchestrator/OrchestratorsZeroState.test.ts
test/orchestrator/Orchestrators.test.ts
test/orchestrator/OrchestratorConfiguration.test.ts
test/orchestrator/OrchestratorPerformUpkeep.test.ts
test/orchestrator/OrchestratorSecurity.test.ts
Revise and consolidate tests for passive curator model
  • Add addWhitelistedCurator calls in all relevant tests
  • Replace computeIntent/validateStrategy calls with submitIntent
  • Update vault whitelist length expectations and remove deprecated assertions
  • Introduce new KBestTvlWeightedAverageInvalid contract and test scenario
test/PassiveCuratorStrategy.test.ts
test/OrionConfigVault.test.ts
test/TransparentVault.test.ts
test/MinimumAmountDOS.test.ts
test/RedeemBeforeDepositOrder.test.ts
test/Removal.test.ts
contracts/test/KBestTvlWeightedAverageInvalid.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 17, 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

Adds curator whitelisting APIs to OrionConfig, replaces pull-based strategy interface with a push-based submitIntent flow, removes passive-curator logic from OrionTransparentVault, updates vault creation/validation and orchestrator epoch filtering, and updates artifacts and tests to match these changes.

Changes

Cohort / File(s) Summary
Curator Whitelist Management
contracts/OrionConfig.sol, contracts/interfaces/IOrionConfig.sol, artifacts/contracts/OrionConfig.sol/OrionConfig.json, artifacts/contracts/interfaces/IOrionConfig.sol/IOrionConfig.json
Add private EnumerableSet for whitelistedCurators; add addWhitelistedCurator, removeWhitelistedCurator, and isWhitelistedCurator; initialize whitelist with initialOwner.
Strategy Interface & Artifacts
contracts/interfaces/IOrionStrategy.sol, artifacts/contracts/interfaces/IOrionStrategy.sol/IOrionStrategy.json, artifacts/contracts/strategies/KBestTvlWeightedAverage.sol/KBestTvlWeightedAverage.json
Replace computeIntent, getStatefulIntent, validateStrategy with single submitIntent(IOrionTransparentVault vault) entry point; ABI and artifact updates reflect the new signature and removed functions.
KBest Strategy Implementation & Test Variant
contracts/strategies/KBestTvlWeightedAverage.sol, contracts/test/KBestTvlWeightedAverageInvalid.sol, artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json
Convert from stateful multi-call model to push-based submitIntent(vault); remove kMax and _statefulIntent; make TVL fetch fault-tolerant; add invalid test strategy contract that omits weight normalization for negative tests.
OrionTransparentVault (vault behavior)
contracts/vaults/OrionTransparentVault.sol
Remove passive-curator state and related methods (_isPassiveCurator, _updateCuratorType, _computePassiveIntent, isPassiveCurator); simplify getIntent, tighten updateCurator to require curator whitelist, and adjust whitelist removal/update logic.
Vault Factory & Orchestrator
contracts/factories/TransparentVaultFactory.sol, contracts/orchestrators/InternalStatesOrchestrator.sol
Validate curator via config.isWhitelistedCurator(curator) in vault factory; in orchestrator, include vaults in epoch based on pendingDeposit + totalAssets > 0 without skipping for empty intent tokens.
Artifacts Bytecode Only
artifacts/contracts/execution/OrionAssetERC4626ExecutionAdapter.sol/OrionAssetERC4626ExecutionAdapter.json, artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json, artifacts/contracts/price/OrionAssetERC4626PriceAdapter.sol/OrionAssetERC4626PriceAdapter.json, artifacts/contracts/price/PriceAdapterRegistry.sol/PriceAdapterRegistry.json
Replace/update bytecode/deployedBytecode fields in artifacts; no ABI/signature changes.
Tests Updated
test/*, test/orchestrator/* (e.g., test/MinimumAmountDOS.test.ts, test/OrionConfigVault.test.ts, test/PassiveCuratorStrategy.test.ts, test/TransparentVault.test.ts, test/orchestrator/Orchestrators.test.ts, etc.)
Add curator whitelisting calls in setups; switch tests to use new submitIntent flow; remove/passive-curator-specific expectations; add tests for removeWhitelistedCurator and invalid-strategy scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant Owner as Owner
    participant Config as OrionConfig
    participant Vault as OrionTransparentVault
    participant Strat as Strategy

    Note over Config,Vault: Curator whitelisting and update flow
    Owner->>Config: addWhitelistedCurator(curator)
    Config-->>Owner: ack
    Owner->>Vault: updateCurator(curator)
    Vault->>Config: isWhitelistedCurator(curator)
    Config-->>Vault: true
    Vault-->>Owner: CuratorUpdated event
Loading
sequenceDiagram
    participant Vault as OrionTransparentVault
    participant Strat as KBestTvlWeightedAverage
    participant Config as OrionConfig

    Note over Vault,Strat: New push-based intent submission
    Strat->>Config: isWhitelistedCurator(strat)
    Config-->>Strat: true
    Strat->>Vault: vault.vaultWhitelist()
    Vault-->>Strat: address[] assets
    Strat->>Strat: compute TVLs, select top-k, build Intent[]
    Strat->>Vault: submitIntent(Intent[])
    Vault-->>Vault: store intent
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Files needing extra attention:
    • contracts/strategies/KBestTvlWeightedAverage.sol — refactor from multi-call to submit flow, TVL fault tolerance, weight distribution.
    • contracts/vaults/OrionTransparentVault.sol — removal of passive-curator logic and intent-handling simplification.
    • contracts/orchestrators/InternalStatesOrchestrator.sol — epoch vault selection change and downstream effects.
    • test/PassiveCuratorStrategy.test.ts and related tests — ensure test expectations align with new submitIntent semantics and invalid-strategy behaviors.

Possibly related PRs

  • PR #82 — Overlaps on vault intent/position types and interfaces (IOrionStrategy, KBest, OrionTransparentVault, OrionConfig).
  • PR #75 — Directly related: introduces/retains passive/pull-based strategy interfaces that this PR removes; opposite design decisions on intent flow.
  • PR #76 — Modifies InternalStatesOrchestrator vault-selection logic; touches the same epoch-building area adjusted here.

Poem

🐰 I nibble on code, add a curator key,
Push intents now — faster as can be.
Passive paths hopped out, active ones hop in,
Whitelisted keepers let the updates begin. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Passive curator' is vague and generic, using non-descriptive terms that don't convey meaningful information about the specific changes in the changeset. Consider using a more specific title that captures the key refactoring, such as 'Refactor passive curator to push-based intent submission' or 'Add curator whitelisting and submitIntent pattern'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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 passive-curator

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13d9a58 and bd03519.

📒 Files selected for processing (7)
  • artifacts/contracts/strategies/KBestTvlWeightedAverage.sol/KBestTvlWeightedAverage.json (3 hunks)
  • artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json (1 hunks)
  • contracts/interfaces/IOrionStrategy.sol (1 hunks)
  • contracts/strategies/KBestTvlWeightedAverage.sol (4 hunks)
  • contracts/vaults/OrionTransparentVault.sol (5 hunks)
  • test/OrionConfigVault.test.ts (5 hunks)
  • test/PassiveCuratorStrategy.test.ts (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json
🧰 Additional context used
🧬 Code graph analysis (5)
artifacts/contracts/strategies/KBestTvlWeightedAverage.sol/KBestTvlWeightedAverage.json (2)
test/Removal.test.ts (3)
  • intent (440-614)
  • intent (312-438)
  • intent (180-310)
test/TransparentVault.test.ts (4)
  • whitelist (361-376)
  • whitelist (292-314)
  • whitelist (403-423)
  • whitelist (316-336)
contracts/vaults/OrionTransparentVault.sol (2)
test/Removal.test.ts (2)
  • intent (440-614)
  • intent (312-438)
test/TransparentVault.test.ts (1)
  • whitelist (292-314)
contracts/strategies/KBestTvlWeightedAverage.sol (2)
test/Removal.test.ts (3)
  • intent (440-614)
  • intent (312-438)
  • intent (180-310)
test/TransparentVault.test.ts (5)
  • whitelist (361-376)
  • whitelist (292-314)
  • whitelist (403-423)
  • whitelist (378-401)
  • whitelist (316-336)
test/PassiveCuratorStrategy.test.ts (1)
test/TransparentVault.test.ts (3)
  • whitelist (403-423)
  • whitelist (292-314)
  • whitelist (316-336)
contracts/interfaces/IOrionStrategy.sol (2)
test/Removal.test.ts (3)
  • intent (440-614)
  • intent (312-438)
  • intent (180-310)
test/TransparentVault.test.ts (5)
  • whitelist (361-376)
  • whitelist (292-314)
  • whitelist (378-401)
  • whitelist (403-423)
  • whitelist (316-336)
⏰ 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 (19)
contracts/interfaces/IOrionStrategy.sol (1)

7-14: LGTM! Clean push-based interface simplification.

The interface refactor from pull-based methods (computeIntent, validateStrategy, getStatefulIntent) to a single push-based submitIntent method aligns well with the PR's goal of explicit curator whitelisting and direct intent submission.

contracts/vaults/OrionTransparentVault.sol (4)

52-53: LGTM! Safe default initialization.

Initializing the portfolio intent with 100% allocation to the underlying asset is a sensible default for new vaults.


152-152: LGTM! Curator whitelisting properly enforced.

The validation ensures only whitelisted curators can be assigned to vaults, aligning with the PR's security model.


172-175: LGTM! Underlying asset inclusion is a good safety measure.

Automatically adding the underlying asset to the vault whitelist ensures redemption flows and fallback allocations always work correctly.


186-201: LGTM! Weight reallocation logic is sound.

When removing an asset from the vault whitelist, transferring its allocation weight to the underlying asset is a safe and reasonable fallback strategy.

test/OrionConfigVault.test.ts (4)

131-131: LGTM! Proper test setup for curator whitelisting.

Adding curator whitelisting in the beforeEach hook ensures all tests operate under the new security model.


305-333: LGTM! Comprehensive test coverage for curator removal.

The test suite properly validates successful removal, rejection of non-whitelisted curator removal, and access control enforcement.


459-478: LGTM! Curator update tests properly validate whitelisting.

Tests correctly verify that curators must be whitelisted before they can be assigned to vaults, and that non-whitelisted curator updates are rejected.


489-493: LGTM! Error expectation correctly updated.

Expecting UnauthorizedAccess for zero address curator updates is consistent with the whitelist-based validation model.

test/PassiveCuratorStrategy.test.ts (5)

18-18: LGTM! Proper setup for curator and strategy whitelisting.

The test correctly whitelists both the curator address and the strategy contract address, enabling the strategy to act as a curator under the new security model.

Also applies to: 198-199, 249-250


252-252: LGTM! Correct usage of push-based submitIntent.

The test correctly invokes submitIntent on the strategy with the vault parameter, aligning with the new push-based architecture.


263-267: LGTM! Interface detection correctly updated.

The ERC165 interface detection now correctly reflects the simplified IOrionStrategy interface containing only the submitIntent method.


375-383: LGTM! Edge case properly covered.

This test validates that k=0 is rejected with an explicit error, addressing the edge case identified in previous reviews.


505-564: LGTM! Comprehensive negative test for invalid weights.

This test properly validates that intents with incorrect weight sums are rejected by the vault with InvalidTotalWeight error, ensuring weight validation is enforced.

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

29-29: LGTM! ABI correctly reflects interface changes.

The artifact's ABI properly reflects the simplified interface with submitIntent and the more descriptive OrderIntentCannotBeEmpty error.

Also applies to: 124-136

contracts/strategies/KBestTvlWeightedAverage.sol (4)

38-38: LGTM! k=0 edge case properly guarded.

The explicit validation for k=0 addresses the edge case identified in previous reviews, preventing potential array out-of-bounds issues.


40-53: LGTM! Clean push-based implementation.

The submitIntent method cleanly implements the push-based model: fetch vault whitelist, compute top-K assets, calculate allocations, and submit directly to the vault.


67-75: LGTM! Good resilience improvement.

The try/catch fallback to dust (1) when totalAssets() fails is a sensible defensive measure that prevents a single misbehaving asset from blocking the entire strategy.


136-136: LGTM! Improved rounding error allocation.

Allocating the weight remainder to the first (highest TVL) asset is more sensible than the previous approach of allocating to the last (lowest TVL) asset, as the larger asset can better absorb rounding errors.


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 - here's some feedback:

  • Ensure the new submitIntent entry point on OrionTransparentVault includes an explicit access check (e.g. only the current curator contract may call it) to prevent unauthorized contracts from pushing arbitrary intents.
  • In KBestTvlWeightedAverage, the residual weight correction is always applied to the first token; consider applying it to the asset with the largest raw allocation (or the last index) to avoid biasing your final distribution.
  • updateCurator now lumps zero‐address and non‐whitelisted failures under UnauthorizedAccess; introducing a distinct ZeroAddress error when passing the zero address would make error handling more precise.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Ensure the new `submitIntent` entry point on `OrionTransparentVault` includes an explicit access check (e.g. only the current curator contract may call it) to prevent unauthorized contracts from pushing arbitrary intents.
- In `KBestTvlWeightedAverage`, the residual weight correction is always applied to the first token; consider applying it to the asset with the largest raw allocation (or the last index) to avoid biasing your final distribution.
- `updateCurator` now lumps zero‐address and non‐whitelisted failures under `UnauthorizedAccess`; introducing a distinct `ZeroAddress` error when passing the zero address would make error handling more precise.

## Individual Comments

### Comment 1
<location> `test/PassiveCuratorStrategy.test.ts:336-345` </location>
<code_context>
+    it("should handle case when k > number of available assets", async function () {
</code_context>

<issue_to_address>
**suggestion (testing):** Edge case for k > assets is covered, but does not test for k = 0.

Please add a test for k = 0 to verify correct handling of this edge case.
</issue_to_address>

### Comment 2
<location> `test/PassiveCuratorStrategy.test.ts:465-462` </location>
<code_context>
-      ).to.be.revertedWithCustomError(strategy, "InvalidStrategy");
-    });
-
     it("should allow whitelist updates when curator is not a strategy", async function () {
       await transparentVault.connect(owner).updateCurator(owner.address);

</code_context>

<issue_to_address>
**suggestion (testing):** Test for whitelist update when curator is not a strategy may miss edge cases.

Add tests for updating the whitelist to an empty array and to a set with only non-ERC4626 assets to verify correct contract behavior in these scenarios.

Suggested implementation:

```typescript
     it("should allow whitelist updates when curator is not a strategy", async function () {
       await transparentVault.connect(owner).updateCurator(owner.address);
     });

     it("should handle whitelist update to an empty array", async function () {
       await transparentVault.connect(owner).updateCurator(owner.address);
       await expect(
         transparentVault.connect(owner).updateWhitelist([])
       ).to.not.be.reverted;

       const whitelist = await transparentVault.getWhitelist();
       expect(whitelist).to.be.an("array").that.is.empty;
     });

     it("should handle whitelist update to only non-ERC4626 assets", async function () {
       await transparentVault.connect(owner).updateCurator(owner.address);

       // Assume nonErc4626Asset is a valid address but not an ERC4626 asset
       const nonErc4626Asset = owner.address; // Replace with actual non-ERC4626 asset address if available

       await expect(
         transparentVault.connect(owner).updateWhitelist([nonErc4626Asset])
       ).to.not.be.reverted;

       const whitelist = await transparentVault.getWhitelist();
       expect(whitelist).to.deep.equal([nonErc4626Asset]);
       // Optionally, add more assertions to check contract behavior with non-ERC4626 assets
     });

```

- If you have a specific non-ERC4626 asset address, replace `owner.address` with that address in the test.
- Ensure that `updateWhitelist` and `getWhitelist` are the correct contract methods for updating and reading the whitelist.
- Add any additional assertions relevant to your contract's expected behavior when the whitelist contains only non-ERC4626 assets.
</issue_to_address>

### Comment 3
<location> `test/orchestrator/Orchestrators.test.ts:692-689` </location>
<code_context>
   });

   describe("performUpkeep", function () {
-    it("should complete full upkeep cycles without intent decryption", async function () {
+    it("", async function () {
       // Fast forward time to trigger upkeep
       expect(await internalStatesOrchestrator.currentPhase()).to.equal(0); // Idle
</code_context>

<issue_to_address>
**nitpick:** Test name was removed, now empty string.

A meaningful test name will make it easier to understand and maintain the test suite.
</issue_to_address>

### Comment 4
<location> `test/MinimumAmountDOS.test.ts:59-66` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</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 test/PassiveCuratorStrategy.test.ts
Comment thread test/PassiveCuratorStrategy.test.ts
Comment thread test/orchestrator/Orchestrators.test.ts
@codecov

codecov Bot commented Nov 17, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
test/orchestrator/OrchestratorsZeroState.test.ts (1)

431-432: Add missing access control to strategy's submitIntent() function.

KBestTvlWeightedAverage.submitIntent() is called by test code with explicit owner/curator signers, indicating the design intent was to restrict access, but the function lacks the access control modifier. Currently, any external caller can invoke submitIntent() directly on the strategy contract, which then submits intents to the vault. This bypasses the authorization model.

Since the contract is Ownable and updateParameters() correctly uses onlyOwner, submitIntent() should enforce the same access control:

contracts/strategies/KBestTvlWeightedAverage.sol line 37: Add onlyOwner modifier to submitIntent() function declaration.

contracts/vaults/OrionTransparentVault.sol (1)

14-25: Active-only intent model is consistent, but docs and whitelist signaling need a refresh

  • Seeding _portfolioIntent to 100% underlying in the constructor and reassigning removed-asset weight to this.asset() both preserve the “weights sum to curatorIntentDecimals” invariant, which fits the new push‑only intent model.
  • Requiring config.isWhitelistedCurator(newCurator) in updateCurator is a good hardening step around curator ACLs.
  • Ensuring the underlying asset is always present in _vaultWhitelistedAssets keeps intents and portfolio logic consistent even if callers omit it from assets.

Two follow‑ups worth addressing:

  • The header comment still describes passive management via IOrionStrategy and automatic curator‑type detection, but the implementation is now active‑only. That’s likely to confuse integrators and should be updated to reflect the current behavior.
  • VaultWhitelistUpdated(assets) does not include the implicitly-added underlying asset when it wasn’t in assets. If off‑chain consumers rely on that event to reconstruct the whitelist, consider either appending the underlying to the emitted list or documenting that the on-chain whitelist may be a strict superset of the event payload.

Also applies to: 56-58, 155-159, 176-179, 196-205

contracts/strategies/KBestTvlWeightedAverage.sol (2)

114-136: Guard against kActual == 0 and totalTVL == 0 edge cases in _calculatePositions

In _calculatePositions:

uint16 kActual = ...; // passed in
// ...
for (uint16 i = 0; i < kActual; ++i) {
    totalTVL += topTvls[i];
}
// ...
for (uint16 i = 0; i < kActual; ++i) {
    uint32 weight = uint32((topTvls[i] * intentScale) / totalTVL);
    // ...
}
if (sumWeights < intentScale) {
    intent[0].weight += intentScale - sumWeights;
}

Two edge cases can cause hard-to-diagnose reverts:

  1. kActual == 0 (e.g., k == 0 via updateParameters or an empty whitelist):

    • intent is a zero-length array, but you still execute intent[0].weight += ..., which will underflow with an out-of-bounds read/write.
  2. totalTVL == 0 (e.g., all selected assets have totalAssets() == 0 and no fallback kicks in):

    • The weight computation divides by totalTVL, causing a division-by-zero revert.

Recommend explicitly handling these cases, for example:

function _calculatePositions(
    address[] memory tokens,
    uint256[] memory topTvls,
    uint16 kActual
) internal view returns (IOrionTransparentVault.IntentPosition[] memory intent) {
-    uint256 totalTVL = 0;
+    uint256 totalTVL = 0;
     for (uint16 i = 0; i < kActual; ++i) {
         totalTVL += topTvls[i];
     }

+    if (kActual == 0 || totalTVL == 0) {
+        revert ErrorsLib.InvalidTotalTVL();
+    }
+
    uint32 intentScale = uint32(10 ** config.curatorIntentDecimals());
    intent = new IOrionTransparentVault.IntentPosition[](kActual);
    // ...
    if (sumWeights < intentScale) {
        intent[0].weight += intentScale - sumWeights;
    }
}

(or any equivalent policy you prefer).

This keeps misconfiguration or pathological-TVL states from surfacing as generic arithmetic/oob errors deeper in the call stack.


138-142: Prevent misconfiguration by rejecting kNew == 0 in updateParameters

updateParameters currently allows setting k to 0:

function updateParameters(uint16 kNew) external onlyOwner {
    k = kNew;
}

Given the logic in submitIntent / _calculatePositions, a zero k leads to kActual == 0 and the edge case noted above. Even if you add guards in _calculatePositions, it’s clearer to simply disallow k == 0 at the config level:

function updateParameters(uint16 kNew) external onlyOwner {
-    k = kNew;
+    if (kNew == 0) revert ErrorsLib.InvalidParameter();
+    k = kNew;
}

This avoids a class of invalid configurations and makes the strategy’s expected domain explicit.

🧹 Nitpick comments (11)
test/orchestrator/Orchestrators.test.ts (1)

689-689: Give the long performUpkeep scenario test a descriptive name

it("") makes this very large, end‑to‑end test hard to identify in output and when it fails. Consider renaming to something like "should run full multi-epoch upkeep with passive strategy and fee accounting" or similar to improve maintainability.

contracts/test/KBestTvlWeightedAverageInvalid.sol (1)

1-151: Invalid strategy matches test goal; guard against totalTVL == 0

This helper is well‑structured for negative‑path testing: it picks top‑K by TVL and deliberately avoids weight normalization so submitIntent can fail on InvalidTotalWeight. One edge case: if all selected assets have totalAssets() == 0, totalTVL stays 0 and _calculatePositions will divide by zero.

Since this is test‑only, it’s not critical, but you may want to short‑circuit when totalTVL == 0 (e.g., revert with a clearer error or return an empty intent) to keep the failure mode aligned with the “invalid weights” semantics rather than a generic arithmetic fault.

contracts/interfaces/IOrionStrategy.sol (1)

6-14: Align interface docs with new push-based submitIntent model

The interface definition is now a single submitIntent(IOrionTransparentVault vault) entrypoint, but the header comments still talk about “passive curators” and “compute portfolio intents on-demand”. Consider rewording @notice/@dev to describe curator strategies that submit intents to vaults (push model) rather than on-demand computation, to avoid confusion for integrators.

test/PassiveCuratorStrategy.test.ts (6)

17-19: Negative-path invalid-strategy test is well structured; minor naming / reuse nits

The addition of KBestTvlWeightedAverageInvalid and the dedicated "should fail when strategy does not adjust weights to sum to intentScale" test give good coverage of the vault-side invariant. You:

  • Deploy an invalid strategy.
  • Create a separate vault, configure whitelist, and set the invalid strategy as curator.
  • Assert revert with InvalidTotalWeight on submitIntent.

This is solid. If you want to tighten things further, consider:

  • Reusing the vault-creation helper logic from the main setup (to avoid duplicating event parsing).
  • Explicitly asserting that weights returned by the invalid strategy do not sum to intentScale (if you ever expose them) to make the test intent even clearer.

Also applies to: 495-554


297-318: Explicitly document reliance on implicit inclusion of underlyingAsset in vaultWhitelist

The expectations:

const vaultWhitelist = await transparentVault.vaultWhitelist();
expect(vaultWhitelist.length).to.equal(5);
// ...
// mockAsset1: 3000, mockAsset2: 2000, mockAsset3: 1500, mockAsset4: 1000, underlyingAsset: 0
// ...
expect(tokens).to.not.include(await underlyingAsset.getAddress());

encode the assumption that vaultWhitelist() returns the 4 ERC4626 assets plus underlyingAsset, and that the strategy’s top‑K selection excludes underlyingAsset for k = 3.

That coupling is fine, but it’s fairly protocol-specific. To avoid future confusion if the vault implementation ever changes its internal whitelist representation, I’d either:

  • Expand the comment to clearly state that the vault automatically includes underlyingAsset in its whitelist, or
  • Add an assertion that vaultWhitelist actually contains underlyingAsset (in addition to the length check) to make the implicit behavior explicit.

336-354: Good coverage for k > n and k = 1; consider adding a weight-sum assertion

These tests correctly:

  • Update k to 6 when there are only 5 whitelisted assets (including the underlying), call submitIntent, and assert that all 5 assets are selected.
  • Update k to 1, call submitIntent, and assert that only the highest‑TVL asset is selected with 100% allocation.

To further lock in the invariant that weights always sum to 10^curatorIntentDecimals across these corner cases (not just in the separate weight-distribution test), you might also add an explicit totalWeight sum check here, similar to the “correct weight distribution” test.

Also applies to: 359-373


428-447: Push-model semantics: ensure tests always call submitIntent when asserting behavior after parameter changes

You correctly added submitIntent(transparentVault) calls after updateParameters in the "Strategy Parameter Updates" test, which is necessary under the push-based model.

However, in "should maintain valid intent weights after parameter changes" you still:

for (let k = 1; k <= 4; k++) {
  await strategy.connect(curator).updateParameters(k);
  const [_tokens, weights] = await transparentVault.getIntent();
  // ...
}

without re-submitting an intent. Under the new model, this loop is only checking whatever intent was last pushed, not the updated k configurations the description refers to.

Suggest either:

  • Adding await strategy.connect(curator).submitIntent(transparentVault); inside the loop, or
  • Renaming the test to reflect that it’s checking “stored intent always has valid weights” rather than change-after-parameter-updates.

Also applies to: 476-492


453-463: Whitelist length expectation reflects underlying presence; consider asserting the curator behavior too

Changing the expectation to expect(whitelist.length).to.equal(3); aligns with the expanded whitelist (two assets plus the underlying). Since this test is meant to validate strategy behavior on whitelist updates when the curator is a strategy, you might also assert that the current curator is still the strategy (or that intent remains valid) to fully exercise the “validation” semantics implied by the describe block name.


263-267: Update comments and simplify interface ID computation

The comment on line 265 is stale—it mentions "XOR all three selectors," but the code only computes a single selector and performs no XOR operation. Additionally, the BigInt conversion and manual hex formatting add unnecessary complexity.

Since EIP-165 defines interface identifiers as the XOR of all function selectors, and for a single-function interface the ID equals that selector, the computation can be simplified:

const interfaceId = ethers.id("submitIntent(address)").slice(0, 10);
expect(await strategy.supportsInterface(interfaceId)).to.be.true;

This keeps the test correct while making it easier to maintain.

contracts/strategies/KBestTvlWeightedAverage.sol (2)

37-52: submitIntent flow is coherent with push-based curator design

The new submitIntent(IOrionTransparentVault vault):

  • Reads vault.vaultWhitelist().
  • Computes TVLs (with graceful fallback) and selects top‑K.
  • Builds IntentPosition[] and forwards it via vault.submitIntent(intent).

This is clean and keeps the strategy stateless with respect to intents. One small suggestion: consider validating that address(vault) != address(0) (and optionally that config matches the vault’s config, if exposed) to fail fast on mis-wiring rather than propagating more obscure downstream errors.


59-72: TVL fallback on totalAssets() failure is reasonable; consider making the “dust” value configurable

The try/catch around IERC4626.totalAssets() that assigns tvls[i] = 1 on failure:

  • Prevents a single misbehaving asset (or non‑ERC4626 like the underlying) from reverting the entire strategy.
  • Ensures such assets are least favored in selection when k < n.

This matches the tests’ expectations. If you want more flexibility long term, you could expose the fallback “dust TVL” as a constant or config parameter instead of hard‑coding 1, but that’s a minor improvement, not a blocker.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ab1bbd and 13d9a58.

📒 Files selected for processing (28)
  • artifacts/contracts/OrionConfig.sol/OrionConfig.json (4 hunks)
  • artifacts/contracts/execution/OrionAssetERC4626ExecutionAdapter.sol/OrionAssetERC4626ExecutionAdapter.json (1 hunks)
  • artifacts/contracts/interfaces/IOrionConfig.sol/IOrionConfig.json (3 hunks)
  • artifacts/contracts/interfaces/IOrionStrategy.sol/IOrionStrategy.json (1 hunks)
  • artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json (1 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 (2 hunks)
  • artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json (1 hunks)
  • contracts/OrionConfig.sol (3 hunks)
  • contracts/factories/TransparentVaultFactory.sol (1 hunks)
  • contracts/interfaces/IOrionConfig.sol (1 hunks)
  • contracts/interfaces/IOrionStrategy.sol (1 hunks)
  • contracts/orchestrators/InternalStatesOrchestrator.sol (0 hunks)
  • contracts/strategies/KBestTvlWeightedAverage.sol (4 hunks)
  • contracts/test/KBestTvlWeightedAverageInvalid.sol (1 hunks)
  • contracts/vaults/OrionTransparentVault.sol (4 hunks)
  • test/MinimumAmountDOS.test.ts (1 hunks)
  • test/OrionConfigVault.test.ts (4 hunks)
  • test/PassiveCuratorStrategy.test.ts (9 hunks)
  • test/RedeemBeforeDepositOrder.test.ts (1 hunks)
  • test/Removal.test.ts (1 hunks)
  • test/TransparentVault.test.ts (1 hunks)
  • test/orchestrator/OrchestratorConfiguration.test.ts (3 hunks)
  • test/orchestrator/OrchestratorPerformUpkeep.test.ts (2 hunks)
  • test/orchestrator/OrchestratorSecurity.test.ts (2 hunks)
  • test/orchestrator/Orchestrators.test.ts (4 hunks)
  • test/orchestrator/OrchestratorsZeroState.test.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • contracts/orchestrators/InternalStatesOrchestrator.sol
⏰ 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 (28)
artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json (1)

792-793: Bytecode changes are expected recompilation output.

This artifact file reflects the recompilation of LiquidityOrchestrator after source code modifications in this PR. The bytecode and deployedBytecode have been updated (lines 792–793), while the ABI structure and public interface remain unchanged. The contract's function signatures, events, and error definitions are all preserved, confirming the recompilation is sound. No action needed.

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

168-169: Bytecode update follows recompilation—verify source contract alignment.

Since the AI summary states that only bytecode and deployedBytecode changed while the ABI and function signatures remain unchanged, this is a safe recompilation. However, compiled artifacts should be verified to ensure they correspond to the intended source changes introduced in this PR.

Please confirm that:

  1. The source contract OrionAssetERC4626ExecutionAdapter.sol was recompiled with the correct compiler version and settings (as specified in the repo's build config).
  2. The contract's public interface (ABI) is stable and backwards compatible, which the unchanged ABI confirms.
  3. Any changes to the underlying source were intentional and align with the PR's transition to the push-based active curator model.

If you'd like, I can generate a verification script to check that the artifact was produced by a clean recompilation of the source, or inspect related contracts to ensure consistency.

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

213-214: Artifact recompilation - LGTM!

Bytecode updated due to recompilation. No ABI changes, consistent with other contracts being updated in this PR.

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

246-258: Curator whitelisting ABI additions - LGTM!

The artifact correctly exposes the new curator whitelist management functions: addWhitelistedCurator, isWhitelistedCurator, and removeWhitelistedCurator. These align with the PR's objective to introduce curator whitelisting as part of the transition from passive to active curator model.

Also applies to: 464-482, 606-618, 815-816

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

7-18: Strategy interface simplification - LGTM!

The interface correctly reflects the architectural shift from passive to active curator model. The new submitIntent(IOrionTransparentVault vault) function replaces the previous multi-function approach (computeIntent/getStatefulIntent/validateStrategy), streamlining strategy-vault interaction.

test/MinimumAmountDOS.test.ts (1)

62-62: Curator whitelisting setup - LGTM!

Properly whitelists the curator before vault creation, aligning with the new curator access control model introduced in this PR.

test/Removal.test.ts (1)

156-157: Curator whitelisting setup - LGTM!

Correctly whitelists the curator in test setup, maintaining consistency with the new access control requirements across the test suite.

test/TransparentVault.test.ts (1)

130-131: Curator whitelisting setup - LGTM!

Curator is properly whitelisted in the test setup before vault operations, ensuring tests align with the new curator access control model.

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

104-105: Artifact recompilation - LGTM!

Bytecode updated due to recompilation. No ABI changes detected.

test/RedeemBeforeDepositOrder.test.ts (1)

170-171: Curator whitelisting setup - LGTM!

Curator whitelisting properly added to test setup, ensuring the test suite remains aligned with the new curator access control model.

test/orchestrator/OrchestratorsZeroState.test.ts (3)

77-78: LGTM: Curator whitelisting before vault creation.

The addition of curator whitelisting aligns with the new access control model introduced in this PR. The curator is properly whitelisted before vault creation, which is required by the updated TransparentVaultFactory validation.


334-335: LGTM: Curator whitelisting in test setup.

The curator is properly whitelisted before vault creation operations, ensuring compliance with the new access control requirements.


453-453: Ignore this review comment—the file reference and line numbers are incorrect.

The test file test/orchestrator/OrchestratorsZeroState.test.ts contains only 150 lines, making the reference to line 453 impossible. The code snippet shown is empty. No test for a "passive vault curator update flow" or updateCurator operation exists in this file. The file contains only two test cases related to upkeep execution with zero TVL and intents, with curator used only in setup and intent submission.

While the contract implementation (contracts/vaults/OrionTransparentVault.sol lines 155–159) does properly validate curator whitelist via config.isWhitelistedCurator() before updating, the test location specified in this review comment does not correspond to any actual code changes in the current codebase.

Likely an incorrect or invalid review comment.

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

47-59: LGTM: Curator whitelist management ABI entries.

The artifact correctly exposes three new curator whitelist management functions:

  • addWhitelistedCurator(address): nonpayable function to add curators
  • isWhitelistedCurator(address): view function to check whitelist status
  • removeWhitelistedCurator(address): nonpayable function to remove curators

These entries are consistent with the interface changes described in the PR summary.

Also applies to: 265-283, 394-406

test/orchestrator/OrchestratorPerformUpkeep.test.ts (1)

321-322: LGTM: Curator and strategy whitelisting in test setup.

Both the human curator and the strategy contract are properly whitelisted before vault creation and configuration. This ensures the test setup complies with the new whitelist-based authorization model.

Also applies to: 418-419

test/OrionConfigVault.test.ts (3)

131-132: LGTM: Curator whitelisting in test setup.

The curator is properly whitelisted in the beforeEach setup, ensuring all tests have a valid whitelisted curator available for vault operations.


429-448: Excellent test coverage for curator whitelist validation.

The updated tests properly cover both positive and negative scenarios:

  • Whitelisting curator before successful update (lines 432-438)
  • Verifying rejection of non-whitelisted curator (lines 441-448)

This ensures the whitelist authorization is properly enforced.


459-464: Improved error handling: Zero address now UnauthorizedAccess.

Changing the error from InvalidAddress to UnauthorizedAccess for zero address is semantically correct, as the zero address is not whitelisted and therefore unauthorized. This provides consistent error handling across all unauthorized curator scenarios.

test/orchestrator/OrchestratorConfiguration.test.ts (2)

311-312: LGTM: Curator and strategy whitelisting in test setup.

Both the human curator and the strategy contract are properly whitelisted before vault creation, consistent with the new authorization model.

Also applies to: 408-409


431-431: All verification criteria confirmed - no issues found.

The implementation correctly supports the push-based active curator model:

  1. Access control on submitIntent: The onlyCurator modifier at ./contracts/vaults/OrionTransparentVault.sol:63 enforces that only the vault's assigned curator can call submitIntent(). The modifier checks if (msg.sender != curator) revert ErrorsLib.UnauthorizedAccess().

  2. Vault validates curator identity: The onlyCurator modifier performs a direct identity check (msg.sender != curator), ensuring the calling strategy is confirmed as the vault's assigned curator.

  3. Idempotent and safe to retry: The portfolio intent submission is idempotent by design—the function clears the previous intent (_portfolioIntent.clear() at line 66) and replaces it atomically with the new one, making repeated submissions safe.

The test suite validates this behavior, particularly at test/TransparentVault.test.ts:363-378, which confirms non-curator calls are properly rejected.

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

1-182: LGTM: Test artifact for invalid strategy.

This artifact provides a test-only strategy contract that generates invalid intents (weights not summing correctly). This is useful for negative testing to ensure the system properly validates and rejects invalid intents with InvalidTotalWeight error.

The presence of this test artifact indicates good test coverage for edge cases and error handling.

contracts/interfaces/IOrionConfig.sol (1)

115-128: Curator whitelist interface matches existing whitelist patterns

The new curator whitelist methods mirror the existing vault‑owner whitelist API (ownership‑gated mutators and a simple view), so they slot cleanly into the config interface without changing existing call semantics.

test/orchestrator/Orchestrators.test.ts (1)

153-153: Whitelisting strategy/curator and pushing initial intent look correct

Whitelisting both the KBest strategy and the human curator before vault creation/update, and then having the strategy push its intent to passiveVault, is consistent with the new curator ACL and push‑based intent model. Callers used here (default signer / owner) align with Ownable/ACL expectations.

Also applies to: 253-253, 371-371

contracts/OrionConfig.sol (1)

63-63: Curator whitelist storage and API integrate cleanly with config

Introducing whitelistedCurators, seeding it with initialOwner, and exposing add/remove/is functions that mirror the vault‑owner whitelist keeps ACLs consistent and straightforward to reason about. The error semantics (AlreadyRegistered / InvalidAddress) also match existing patterns.

Also applies to: 113-115, 258-275

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

119-131: ABI/bytecode update for submitIntent looks consistent

The added ABI entry for submitIntent(IOrionTransparentVault vault) (nonpayable, no return) aligns with the new strategy interface, and the regenerated bytecode/deployedBytecode correspondingly reflect the implementation change. Nothing stands out as inconsistent here.

Also applies to: 178-179

test/PassiveCuratorStrategy.test.ts (1)

198-199: Curator whitelisting and strategy setup verified as correct

The push-based model implementation with curator whitelisting, vault curator update, and initial submitIntent call is confirmed at lines 249-252 and aligns with the pattern throughout the test suite. Subsequent tests consistently call submitIntent after updateParameters (lines 338-339, 358-359, 431-432, 438-439, 445-446, etc.), confirming that the codebase properly handles refreshing stored intents when parameters change.

test/orchestrator/OrchestratorSecurity.test.ts (2)

334-334: LGTM - Curator whitelisting properly integrated.

The curator is correctly whitelisted after configuration and before vault creation, ensuring the curator can submit intents later in the test setup. This aligns with the new push-based curator model.


431-453: LGTM - Strategy-as-curator architecture properly implemented.

The KBest TVL strategy is correctly whitelisted as a curator before being assigned to the passive vault. This change, combined with the removal of revert expectations (per the AI summary), properly implements the transition from a pull-based passive curator model to a push-based active curator model where strategies can submit intents directly to vaults.

The setup flow is correct:

  1. Whitelist strategy as curator (line 431)
  2. Create passive vault (lines 434-451)
  3. Update vault curator to strategy (line 453)

Comment thread contracts/factories/TransparentVaultFactory.sol

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contracts/vaults/OrionTransparentVault.sol (1)

176-205: Add guard to prevent removal of the underlying asset from vault whitelist (contracts/vaults/OrionTransparentVault.sol, line 186)

The review comment is accurate. removeFromVaultWhitelist currently lacks any protection against removing this.asset(), which breaks the invariant established by updateVaultWhitelist (lines 176–178) that the underlying asset must always remain whitelisted. The function unconditionally removes any asset passed to it, then reassigns removed weight to the underlying asset—creating a scenario where the underlying is referenced in _portfolioIntent but absent from _vaultWhitelistedAssets.

Verification confirms no require or revert guard exists to prevent asset == this.asset(). Git history indicates a prior fix attempt (commit 74ce08e), but it is not present in the current codebase.

Add validation to either revert when asset == this.asset() or re-add the underlying to the whitelist after removal to preserve the invariant.

♻️ Duplicate comments (1)
test/orchestrator/Orchestrators.test.ts (1)

688-689: Give the long “performUpkeep” scenario test a descriptive name

This it("") block is still using an empty string as its description, which makes the suite harder to scan and maintain. Please rename it to something that reflects the scenario (e.g., "full end-to-end epoch, fees, and buffer management").

🧹 Nitpick comments (8)
contracts/OrionConfig.sol (1)

63-64: Curator whitelist implementation is consistent; consider optional zero-address guard

The new whitelistedCurators set, constructor seeding with initialOwner, and the add/remove/isWhitelistedCurator helpers mirror the existing vault-owner whitelist and look correct from an access-control standpoint (onlyOwner, clear error types).

If you want extra safety against accidental configuration, you could optionally reject address(0) in addWhitelistedCurator, similar to how other parts of the config guard against zero addresses, but it’s not strictly required for correctness.

Also applies to: 113-115, 258-275

test/PassiveCuratorStrategy.test.ts (2)

264-267: Interface ID test works but the comment and computation could be simplified

For a single‑function interface, the EIP‑165 interface ID is just that function’s selector, so your test is logically fine. The comment about XOR-ing “all function selectors” is now stale, and the BigInt round‑trip is unnecessary.

You can simplify and clarify by e.g.:

const interfaceId = "0x" + ethers.id("submitIntent(address)").slice(2, 10);
expect(await strategy.supportsInterface(interfaceId)).to.be.true;

which directly reflects the interface definition and avoids the extra conversion steps.


301-318: Updated whitelist and intent expectations align with underlying-always-whitelisted behavior

The changes to expect:

  • vaultWhitelist.length === 5 after whitelisting 4 ERC4626 assets,
  • intent tokens excluding the underlying asset in the “top‑3 by TVL” case,
  • and including the underlying asset when k exceeds the number of ERC4626 assets,

are consistent with a model where the underlying asset is always part of the vault’s investment universe but only appears in the strategy’s intent when appropriate. The adjusted whitelist length check in the strategy‑validation test (length === 3 after whitelisting 2 assets) also fits this pattern.

If you want slightly stronger assertions, you could additionally assert that vaultWhitelist explicitly contains the underlying asset where you currently only check length.

Also applies to: 337-347, 353-354, 459-463

contracts/vaults/OrionTransparentVault.sol (2)

14-25: Update docstring: vault no longer supports passive curator strategies

The header comment still describes both “active” and “passive” management with automatic curator-type detection, but the passive-curator path and related state have been removed. Consider updating this description to match the active-only, push‑intent design to avoid misleading integrators.


155-159: Stricter curator updates: only whitelisted curators allowed

Requiring config.isWhitelistedCurator(newCurator) in updateCurator tightens access control, which is good. It does, however, mean:

  • You can no longer “clear” the curator by setting it to address(0).
  • All curator rotations must be pre‑whitelisted at the config level.

If this is the intended operational model, it’s fine; otherwise you may want an explicit way to unset the curator (e.g., a dedicated deactivation path) or treat address(0) as a special case.

contracts/test/KBestTvlWeightedAverageInvalid.sol (1)

19-53: Invalid strategy behaves as intended; consider documenting/guarding zero‑TVL edge case

This test‑only strategy cleanly mirrors the production K‑best implementation while intentionally omitting the final weight‑normalization step, which matches the contract’s purpose.

One edge case to be aware of: if all selected TVLs are zero, totalTVL stays 0 and the division in Line 130 will revert. That may be perfectly acceptable for a negative‑path test helper; if you ever reuse this pattern elsewhere, consider either:

  • Adding an explicit require(totalTVL > 0, ...), or
  • Falling back to equal weights when totalTVL == 0.

Also applies to: 115-138

contracts/strategies/KBestTvlWeightedAverage.sol (2)

59-73: _getAssetTVLs: dust fallback behavior is reasonable but slightly biases rankings

The try/catch approach with a fallback TVL of 1 for assets that revert on totalAssets() avoids a single bad asset taking down the whole strategy, which is desirable. The tradeoff is that:

  • Non‑ERC4626 or misbehaving assets are given a small but non‑zero TVL and may still be selected if all “good” assets also have very low TVL.
  • This bias may or may not be acceptable depending on how strictly you intend to treat non‑ERC4626 assets in the vault whitelist.

If the design goal is “best effort” under partial failures, this is fine; otherwise you might consider:

  • Assigning such assets TVL 0 and explicitly reverting when totalTVL == 0, or
  • Excluding them from the candidate set entirely.

133-135: Remainder allocation to intent[0] is fine; consider making the choice explicit in docs

Adjusting intent[0].weight to absorb the rounding remainder ensures the sum of weights matches the intent scale. That’s a sensible choice; it just implicitly favors the first selected asset.

If the intended behavior is “round to the first ranked asset,” consider briefly documenting this in the NatSpec for _calculatePositions or the strategy comment, so downstream users know which asset gets the residual weight.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ab1bbd and 13d9a58.

📒 Files selected for processing (28)
  • artifacts/contracts/OrionConfig.sol/OrionConfig.json (4 hunks)
  • artifacts/contracts/execution/OrionAssetERC4626ExecutionAdapter.sol/OrionAssetERC4626ExecutionAdapter.json (1 hunks)
  • artifacts/contracts/interfaces/IOrionConfig.sol/IOrionConfig.json (3 hunks)
  • artifacts/contracts/interfaces/IOrionStrategy.sol/IOrionStrategy.json (1 hunks)
  • artifacts/contracts/orchestrators/LiquidityOrchestrator.sol/LiquidityOrchestrator.json (1 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 (2 hunks)
  • artifacts/contracts/test/KBestTvlWeightedAverageInvalid.sol/KBestTvlWeightedAverageInvalid.json (1 hunks)
  • contracts/OrionConfig.sol (3 hunks)
  • contracts/factories/TransparentVaultFactory.sol (1 hunks)
  • contracts/interfaces/IOrionConfig.sol (1 hunks)
  • contracts/interfaces/IOrionStrategy.sol (1 hunks)
  • contracts/orchestrators/InternalStatesOrchestrator.sol (0 hunks)
  • contracts/strategies/KBestTvlWeightedAverage.sol (4 hunks)
  • contracts/test/KBestTvlWeightedAverageInvalid.sol (1 hunks)
  • contracts/vaults/OrionTransparentVault.sol (4 hunks)
  • test/MinimumAmountDOS.test.ts (1 hunks)
  • test/OrionConfigVault.test.ts (4 hunks)
  • test/PassiveCuratorStrategy.test.ts (9 hunks)
  • test/RedeemBeforeDepositOrder.test.ts (1 hunks)
  • test/Removal.test.ts (1 hunks)
  • test/TransparentVault.test.ts (1 hunks)
  • test/orchestrator/OrchestratorConfiguration.test.ts (3 hunks)
  • test/orchestrator/OrchestratorPerformUpkeep.test.ts (2 hunks)
  • test/orchestrator/OrchestratorSecurity.test.ts (2 hunks)
  • test/orchestrator/Orchestrators.test.ts (4 hunks)
  • test/orchestrator/OrchestratorsZeroState.test.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • contracts/orchestrators/InternalStatesOrchestrator.sol
⏰ 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). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (34)
artifacts/contracts/price/PriceAdapterRegistry.sol/PriceAdapterRegistry.json (1)

213-214: Artifact file updated — verify this is intentional recompilation.

The bytecode and deployedBytecode hex strings have been replaced, consistent with a contract recompilation. The ABI and contract interface remain unchanged, which is expected.

Note: Compiled artifacts are typically generated during the build process and excluded from version control. If this project uses hardhat artifacts in the repository, ensure your build/CI pipeline regenerates these automatically to prevent drift between source and compiled output.

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

168-169: Expected artifact regeneration from contract compilation.

The bytecode and deployedBytecode have been updated due to changes in the underlying Solidity source code, which is expected. The ABI remains unchanged, indicating no breaking changes to the contract's public interface.

contracts/factories/TransparentVaultFactory.sol (1)

46-46: LGTM: Curator whitelist validation correctly enforced.

The change from zero-address validation to whitelist checking properly implements the new curator access control model. The error type UnauthorizedAccess is appropriate.

Note: This is a breaking change—existing curator addresses must be whitelisted via OrionConfig.addWhitelistedCurator() before vault creation.

contracts/interfaces/IOrionConfig.sol (1)

115-128: LGTM: Curator whitelisting API follows established patterns.

The three new functions mirror the existing vault owner whitelisting pattern and provide complete access control functionality: add, remove, and check curator whitelist status.

test/MinimumAmountDOS.test.ts (1)

62-62: LGTM: Test setup correctly updated for curator whitelisting.

The curator whitelisting is properly added to the fixture setup before vault creation, ensuring compatibility with the new validation requirements.

test/RedeemBeforeDepositOrder.test.ts (1)

170-170: LGTM: Test setup correctly whitelists curator.

The curator whitelisting is properly positioned in the setup flow after asset whitelisting and before vault creation.

test/TransparentVault.test.ts (1)

131-131: LGTM: Global test setup correctly whitelists curator.

The curator whitelisting in the global beforeEach hook ensures all test cases in this suite can successfully create vaults with the new validation requirements.

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

104-105: Artifact bytecode changed without source or compiler config modifications.

The bytecode and deployedBytecode have changed, but the source contract and all compiler settings remain unchanged. The IPFS metadata hash embedded in the bytecode differs, indicating the artifact was regenerated differently. This appears to be either an unintended artifact regeneration or an accidental modification. Since the source code and ABI are identical, confirm whether this change was intentional or should be reverted to match the origin/main artifact.

test/orchestrator/OrchestratorsZeroState.test.ts (1)

77-78: LGTM! Curator whitelisting properly integrated into test setup.

The addition of addWhitelistedCurator(curator.address) in the beforeEach block correctly establishes the curator whitelist before vault creation, aligning with the new curator access control requirements introduced in this PR.

test/orchestrator/OrchestratorPerformUpkeep.test.ts (2)

321-321: LGTM! Curator whitelisting correctly positioned.

The curator is properly whitelisted after asset configuration and before vault creation, ensuring the curator can submit intents to the vaults in subsequent test scenarios.


418-418: LGTM! Strategy contract whitelisted as curator.

Whitelisting the KBestTvlWeightedAverage strategy contract as a curator is appropriate, as it needs curator permissions to call submitIntent on the passive vault (see line 440 where updateCurator is called with the strategy address).

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

47-59: LGTM! Curator whitelisting ABI entries are well-formed.

The three new ABI entries (addWhitelistedCurator, isWhitelistedCurator, removeWhitelistedCurator) follow the established pattern of the existing asset and vault owner whitelisting APIs, maintaining interface consistency.

Also applies to: 265-283, 394-406

test/Removal.test.ts (1)

156-157: LGTM! Curator whitelisting correctly integrated.

The curator is properly whitelisted in the setup phase, ensuring the removal flow tests can execute curator operations (like submitIntent on line 198) without authorization failures.

test/orchestrator/OrchestratorConfiguration.test.ts (3)

311-311: LGTM! Curator whitelisting properly positioned.

The curator is whitelisted before vault operations begin, consistent with the new access control requirements.


408-408: LGTM! Strategy contract whitelisted as curator.

Whitelisting the KBestTvlWeightedAverage strategy enables it to act as the passive vault's curator (line 430) and submit intents (line 431).


431-431: LGTM! New submitIntent flow correctly implemented.

The call to kbestTvlStrategy.connect(owner).submitIntent(passiveVault) demonstrates the new simplified strategy interface where the strategy directly submits its computed intent to the vault, replacing the previous multi-function approach.

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

1-182: LGTM! Test strategy contract artifact properly structured.

The KBestTvlWeightedAverageInvalid artifact correctly implements the new submitIntent(IOrionTransparentVault vault) interface method and includes appropriate constructor validation (ZeroAddress check). This test contract enables validation of invalid weight scenarios in the test suite.

test/OrionConfigVault.test.ts (6)

131-131: LGTM! Curator whitelisting added to test setup.

The addWhitelistedCurator(curator.address) call in beforeEach ensures the curator is whitelisted for all tests, establishing the proper access control baseline.


429-439: LGTM! Test updated to validate whitelisted curator flow.

The test correctly renames to emphasize "whitelisted curator" and adds the whitelisting step (lines 432-433) before attempting the curator update, ensuring the operation succeeds.


441-448: LGTM! New test validates non-whitelisted curator rejection.

This new test appropriately validates that attempting to update to a non-whitelisted curator results in an UnauthorizedAccess error, ensuring the whitelisting requirement is enforced.


459-464: Note: Error message changed for zero address curator.

The expected error for setting curator to zero address changed from InvalidAddress to UnauthorizedAccess (line 462). This suggests zero address is now treated as "not whitelisted" rather than explicitly invalid, which is semantically consistent with the whitelisting approach.


466-474: LGTM! Event test updated with whitelisting prerequisite.

The curator is properly whitelisted (lines 469-470) before the update that triggers the CuratorUpdated event, ensuring the test validates the complete happy path.


500-517: LGTM! Access control test updated with whitelisting.

The test properly whitelists other.address as a curator (lines 513-514) before the owner attempts to call updateCurator, ensuring the access control validation focuses on the owner check rather than the whitelisting check.

contracts/interfaces/IOrionStrategy.sol (1)

6-15: LGTM! Strategy interface successfully simplified.

The replacement of the multi-function interface (computeIntent, validateStrategy, getStatefulIntent) with a single submitIntent(IOrionTransparentVault vault) method is a significant improvement:

  • Push vs. Pull: Shifts from a pull model (compute and return) to a push model (compute and submit directly)
  • Encapsulation: Strategy now controls the submission flow internally
  • Reduced complexity: Single method is easier to implement and test
  • State access: Strategy can query vault state directly through the vault reference

The change is well-coordinated across tests and implementations throughout the PR.

test/orchestrator/OrchestratorSecurity.test.ts (1)

334-335: Curator whitelisting in security setup aligns tests with new protocol rules

Whitelisting both the human curator and the KBest strategy in the beforeEach keeps these security tests compatible with the new curator whitelist requirement without changing their intent. The placement (before vault creation / curator update) looks correct.

Also applies to: 431-432

test/orchestrator/Orchestrators.test.ts (1)

153-154: Whitelisting of curators and strategy plus passive-vault intent submission looks correct

Registering both the curator EOA and the KBestTvlWeightedAverage contract as whitelisted curators before creating vaults and updating the passive vault’s curator, then explicitly calling submitIntent(passiveVault), matches the new curator‑whitelisting plus strategy‑driven intent flow and should keep these orchestration tests representative of real usage.

Also applies to: 253-254, 371-372

test/PassiveCuratorStrategy.test.ts (3)

198-199: Curator/strategy whitelisting and initial intent submission are wired correctly

Whitelisting the curator EOA before vault creation, then whitelisting the strategy contract address before updateCurator and immediately calling strategy.submitIntent(transparentVault) ensures:

  • OrionConfig’s curator whitelist constraint is satisfied for both the initial curator and the strategy.
  • The vault has a populated intent before you start orchestrator‑driven flows or deposits.

This is the right sequencing for the new curator‑gated model.

Also applies to: 249-253


433-440: Calling submitIntent after each k-parameter change keeps intent state in sync

In the “Strategy Parameter Updates” test, invoking submitIntent(transparentVault) after each updateParameters call ensures the intent stored on the vault reflects the current k value before you read it back via getIntent(). This is important under the new submit‑only strategy interface and looks correctly sequenced.

Also applies to: 446-447


18-19: Negative test with KBestTvlWeightedAverageInvalid is a good regression guard

Importing KBestTvlWeightedAverageInvalid and using it to:

  • deploy a misbehaving strategy,
  • attach it to a fresh vault with a normal whitelist,
  • and then assert that submitIntent reverts with InvalidTotalWeight,

gives you a solid regression test that the vault enforces the “weights sum to intentScale” invariant regardless of strategy implementation. The flow (whitelisting the invalid strategy, updating curator, then attempting to submit intent) matches how a real misconfigured strategy would be exercised.

Also applies to: 495-554

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

9-15: ABI correctly reflects the new single-method IOrionStrategy interface

The artifact now exposes only submitIntent(IOrionTransparentVault vault) with an address-encoded parameter and no return values, which matches the described interface refactor away from compute/getStateful/validate methods. This should keep typechain and runtime calls aligned with the on-chain interface.

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

119-131: ABI entry for submitIntent matches source contract expectations

The new ABI fragment for submitIntent(IOrionTransparentVault vault) looks consistent (single address-typed vault parameter, nonpayable, no outputs) with the updated strategy interface.


178-179: Bytecode updates are expected from logic/interface changes

The bytecode and deployedBytecode changes reflect the new submitIntent entry point and helper logic; nothing stands out as anomalous at the artifact level.

contracts/vaults/OrionTransparentVault.sol (1)

56-58: Constructor intent seeding: confirm curatorIntentDecimals scale is consistent

Seeding _portfolioIntent to 100% underlying (10 ** config.curatorIntentDecimals()) is a good default and matches the decommissioning behavior in getIntent(). Just ensure config.curatorIntentDecimals() remains within a range that fits safely into the uint32 weights used elsewhere and is consistent with the intent scale assumed by strategies.

contracts/test/KBestTvlWeightedAverageInvalid.sol (1)

146-149: supportsInterface override correctly advertises IOrionStrategy

The ERC165 override correctly returns true for IOrionStrategy’s interface ID and delegates to super.supportsInterface for the rest, consistent with how the main strategy is declared.

Comment thread contracts/strategies/KBestTvlWeightedAverage.sol Outdated
@matteoettam09
matteoettam09 merged commit 381327e into main Nov 17, 2025
5 checks passed
@matteoettam09
matteoettam09 deleted the passive-curator branch November 17, 2025 21:50
@coderabbitai coderabbitai Bot mentioned this pull request Nov 20, 2025
Merged
@coderabbitai coderabbitai Bot mentioned this pull request Mar 9, 2026
Merged
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.

1 participant