Skip to content

Convertible Deposits: Limit Orders - #191

Merged
0xJem merged 96 commits into
developfrom
feature/cd-limit-orders
Jan 13, 2026
Merged

0xJem merged 96 commits into
developfrom
feature/cd-limit-orders

Conversation

@0xJem

@0xJem 0xJem commented Dec 17, 2025 •

Copy link
Copy Markdown
Member

Summary

Introduces a limit order system for the Convertible Deposit Auctioneer, enabling users to place persistent buy orders that execute when the auction price reaches their specified maximum. MEV bots are incentivized to fill orders, creating a permissionless execution layer.

Motivation

Currently, users must actively monitor CDAuctioneer prices and manually execute bids. This creates friction and may result in missed opportunities when prices briefly dip to favorable levels. Limit orders allow users to set-and-forget, capturing favorable prices without active management.

Features

Limit Orders

  • Users specify deposit period, deposit budget, max execution price, and minimum fill size
  • Orders remain open until fully filled or cancelled
  • Partial fills supported — orders can be filled incrementally

MEV Incentives

  • Users allocate an incentive budget alongside their deposit budget
  • Incentives paid proportionally to fill size (e.g., filling 20% of order pays 20% of incentive budget)
  • Removes gaming incentive to split fills into minimum-sized chunks

Yield Generation

  • Idle deposits held in sUSDS, generating yield while awaiting execution
  • Yield accrues to a configurable recipient address
  • sweepYield() transfers accrued yield as sUSDS shares

Price Validation

  • Uses previewBid() to check actual execution price including slippage across ticks
  • Orders only fill if effective price ≤ user's max price

User Flow

  1. User approves USDS spending
  2. User calls createOrder() with:
    • depositPeriod: CD term length
    • depositBudget: USDS to spend on bids
    • incentiveBudget: USDS to pay fillers
    • maxPrice: Maximum USDS per OHM
    • minFillSize: Minimum fill per transaction
  3. Contract deposits total into sUSDS
  4. MEV bot monitors prices, calls fillOrder() when profitable
  5. User receives position NFT + receipt tokens per fill
  6. User can cancelOrder() anytime to reclaim remaining funds

Bot Flow

  1. Monitor getFillableOrders() or index OrderCreated events
  2. Check canFillOrder() for fillability and effective price
  3. Call fillOrder() with order ID and fill amount
  4. Receive proportional incentive in USDS

Contract Architecture

┌─────────────────────────────────────────────────────────────┐
│                  CDAuctioneerLimitOrders                    │
├─────────────────────────────────────────────────────────────┤
│  Orders: mapping(orderId => LimitOrder)                     │
│  totalUsdsOwed: tracks principal for yield accounting       │
├─────────────────────────────────────────────────────────────┤
│  createOrder() ──────► USDS ──► sUSDS (yield)               │
│  fillOrder()   ──────► sUSDS ──► USDS ──► CDAuctioneer      │
│  cancelOrder() ──────► sUSDS ──► USDS ──► User              │
│  sweepYield()  ──────► sUSDS ──► Yield Recipient            │
└─────────────────────────────────────────────────────────────┘

Security Considerations

  • Reentrancy: All state-modifying functions use nonReentrant
  • Access Control: Ownable for yield recipient management; order cancellation restricted to owner
  • Price Manipulation: Uses previewBid() for actual execution price, not tick price
  • Yield Accounting: Tracks totalUsdsOwed to isolate user principal from yield

Testing

Comprehensive test suite covering:

  • Order creation (success + all revert cases)
  • Order filling (single, multiple, partial, final fill incentive handling)
  • Order cancellation (full refund, partial refund after fills)
  • Yield accrual and sweep
  • Admin functions
  • Edge cases (zero incentive, exact min fill, multiple users/fillers)

Files

  • src/CDAuctioneerLimitOrders.sol — Main contract
  • test/CDAuctioneerLimitOrders.t.sol — Test suite

Deployment Parameters

Parameter Description
owner_ Admin address for yield recipient management
cdAuctioneer_ CDAuctioneer contract address
usds_ USDS token address
sUsds_ sUSDS vault address
positionNft_ CD position NFT address
yieldRecipient_ Address to receive accrued yield
depositPeriods_ Array of supported deposit periods
receiptTokens_ Array of receipt token addresses (1:1 with periods)

Summary by CodeRabbit

  • New Features

    • Full limit-order marketplace for convertible deposits: create/preview/change/fill/cancel orders with deposit & incentive budgets, min-fill/max-price constraints, receipt-token support, NFT integration, yield accrual and sweeping.
  • Interfaces

    • Added a limit-orders interface and a small versioning interface to expose order, yield and admin APIs.
  • Tests

    • Comprehensive unit and mainnet-fork tests with extensive mocks covering flows, edge cases and integrations.
  • Chores

    • Deployment configs, deploy scripts, batch enablement tooling and environment entries added; compiler pragmas broadened in several modules.

✏️ Tip: You can customize this high-level summary in your review settings.


Note

Introduces a limit-order layer for convertible deposits and wires it into deployment/ops.

  • Adds CDAuctioneerLimitOrders with createOrder/fillOrder/cancelOrder, max-price enforcement via previewBid, proportional filler incentives, sUSDS yield accounting (sweepYield), and per-period receipt token support; exposes IVersioned and ILimitOrders interfaces
  • Updates deployment scripts: new deployConvertibleDepositAuctioneerLimitOrders() and helpers to read array args; adds saved deployment configs and records deployed addresses (mainnet/sepolia); updates env.json
  • Adds ops batch PeripheryEnable and args to enable the new periphery contract
  • Bumps pragmas to >=0.8.15 in RANGE/CHREG modules and various test libs; adds/extends mocks for testing (auctioneer, deposit manager, price)

Written by Cursor Bugbot for commit a33d3e5. This will update automatically on new commits. Configure here.

@coderabbitai

coderabbitai Bot commented Dec 17, 2025 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a new CDAuctioneerLimitOrders contract and ILimitOrders interface implementing a limit-order marketplace integrated with the Convertible Deposit system, plus comprehensive unit/fork tests, mocks, deployment scripts, ops batch, and pragma relaxations across tests and mocks.

Changes

Cohort / File(s) Summary
Implementation — Limit orders
src/policies/deposits/LimitOrders.sol, src/policies/interfaces/deposits/ILimitOrders.sol
New CDAuctioneerLimitOrders + ILimitOrders: full order lifecycle (create/change/fill/cancel), yield accounting & sweep, deposit-period ↔ receiptToken mapping, errors/events, ERC721 receiver, integrations with CD_AUCTIONEER/USDS/SUSDS/POSITION_NFT, and rich public views/helpers.
Tests & Forks
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol, src/test/policies/ConvertibleDepositAuctioneer/LimitOrdersFork.t.sol
New comprehensive unit and mainnet-fork tests covering create/fill/change/cancel, yield sweep, admin paths, view helpers, edge cases, and negative-path assertions.
Test Mocks
src/test/mocks/*.sol, src/test/lib/bonds/*.sol
New/expanded mocks: MockUSDS, MockSUSDS (ERC4626), MockReceiptToken, MockPositionNFT, MockCDAuctioneer (configurable price/minBid, preview/bid with deposit+mint), MockDepositManager; several test pragmas broadened.
Deploy & Ops
src/scripts/deploy/DeployV3.s.sol, src/scripts/deploy/savedDeployments/*.json, deployments/*.json, src/scripts/env.json, src/scripts/ops/batches/PeripheryEnable.sol, src/scripts/ops/batches/args/ConvertibleDepositLimitOrders.json
Added deploy helper for ConvertibleDepositAuctioneerLimitOrders, saved deployment configs and sepolia/mainnet mappings, env entries, batch op to enable periphery, and deployment-arg array readers.
Mock Auctioneer (tests)
src/test/mocks/MockConvertibleDepositAuctioneer.sol
Expanded mock: dynamic mockPrice, minimumBid, deposit-period enablement; bid now performs deposit into depositManager and mints receipt tokens & NFTs; preview/bid signatures updated and test setters added.
Auxiliary / Pragmas
src/modules/..., src/test/lib/bonds/*.sol
Broadened Solidity pragma ranges (from fixed 0.8.15 to >=0.8.15 / >=0.8.20) across multiple files; mostly no functional changes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LimitOrders
    participant CDAuctioneer
    participant sUSDS
    participant USDS
    participant PositionNFT
    participant YieldRecipient

    rect rgb(220,238,255)
    Note over User,LimitOrders: Create order
    User->>LimitOrders: createOrder(depositBudget,incentiveBudget,depositPeriod,maxPrice,minFillSize)
    LimitOrders->>CDAuctioneer: isDepositPeriodEnabled / getMinimumBid
    CDAuctioneer-->>LimitOrders: enabled / minBid
    LimitOrders->>USDS: transferFrom(user, depositBudget+incentive)
    LimitOrders->>sUSDS: deposit(USDS) -> receive shares
    LimitOrders-->>User: OrderCreated event
    end

    rect rgb(232,248,232)
    Note over Filler,LimitOrders: Fill order
    Filler->>LimitOrders: fillOrder(orderId, fillAmount)
    LimitOrders->>CDAuctioneer: previewBid(depositPeriod, fillAmount)
    CDAuctioneer-->>LimitOrders: effectivePrice / expectedOhmOut
    LimitOrders->>CDAuctioneer: bid(depositPeriod, amount, minOhmOut, ...)
    CDAuctioneer-->>LimitOrders: (ohmOut, positionId, receiptTokenId, actualAmount)
    LimitOrders->>sUSDS: withdraw shares (ohmOut + incentive share)
    LimitOrders->>PositionNFT: transfer position NFT to filler
    LimitOrders-->>Filler: transfer receipt token + incentive, emit OrderFilled
    end

    rect rgb(255,243,217)
    Note over LimitOrders,sUSDS: Yield sweep
    LimitOrders->>sUSDS: getAccruedYield / getAccruedYieldShares
    LimitOrders->>sUSDS: withdraw/sweep shares to YieldRecipient
    sUSDS-->>YieldRecipient: shares transferred
    LimitOrders-->>YieldRecipient: YieldSwept event
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • #188 — Adds the same CDAuctioneerLimitOrders contract and matching tests; direct overlap with implementation and tests.
  • #192 — Follow-up adjustments to LimitOrders (IERC721Receiver, storage/view fixes) that touch the same file and behavior.
  • #179 — Changes around ConvertibleDepositAuctioneer minimum-bid and activation semantics used by LimitOrders.

Suggested labels

audit-convertible-deposits-guardian

Poem

🐰 I hopped through bids and receipts so neat,

Carrots as budgets, incentives to meet.
sUSDS whispers yields in a gentle heap,
NFTs hop out and positions leap.
A rabbit cheers this market's new beat! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Convertible Deposits: Limit Orders' clearly summarizes the main feature being added—a limit-order system for convertible deposits—and accurately reflects the substantial changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a83cfdd and a33d3e5.

📒 Files selected for processing (3)
  • deployments/.mainnet-1767809879.json
  • src/scripts/deploy/DeployV3.s.sol
  • src/scripts/env.json
✅ Files skipped from review due to trivial changes (1)
  • deployments/.mainnet-1767809879.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/scripts/deploy/DeployV3.s.sol
  • src/scripts/env.json
⏰ 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). (8)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci

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

@0xJem

0xJem commented Dec 17, 2025

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Dec 17, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
src/policies/deposits/LimitOrders.sol (1)

10-11: Consider exporting the interface alias for test compatibility.

The test file imports ICDAuctioneer from this contract, but you import IConvertibleDepositAuctioneer. Either export an alias or update the test to import the interface directly.

 import {IConvertibleDepositAuctioneer} from "../interfaces/deposits/IConvertibleDepositAuctioneer.sol";
+
+// Re-export for convenience
+alias ICDAuctioneer = IConvertibleDepositAuctioneer;

Or simpler, just have the test import the interface from its source directly.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65cc70f and dcc4905.

📒 Files selected for processing (2)
  • src/policies/deposits/LimitOrders.sol (1 hunks)
  • src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: src/modules/TRSRY/TRSRY.v1.sol:2-2
Timestamp: 2025-07-18T00:21:49.138Z
Learning: 0xJem prefers to avoid changing historical/already-deployed contracts to minimize risk and maintain stability, even when it would improve consistency across the codebase.
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: remappings.txt:35-40
Timestamp: 2025-07-18T00:22:32.511Z
Learning: 0xJem prefers to keep OpenZeppelin 4.8.0 as the standard/default dependency in remappings.txt for stability, with newer versions like 5.3.0 available only through explicit versioned dependency paths (e.g., openzeppelin-5.3.0/) to ensure intentional opt-in to newer versions.
📚 Learning: 2025-08-08T07:33:13.575Z
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 86
File: src/policies/deposits/DepositManager.sol:271-320
Timestamp: 2025-08-08T07:33:13.575Z
Learning: DepositManager (src/policies/deposits/DepositManager.sol) is deployed as non-upgradeable; when releasing a new version, existing receipt tokens and underlying deposits remain with the previous DepositManager instance. No migration path is expected or required when introducing facility scoping.

Applied to files:

  • src/policies/deposits/LimitOrders.sol
📚 Learning: 2025-08-08T11:14:54.317Z
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 88
File: src/test/policies/ConvertibleDepositAuctioneer/ConvertibleDepositAuctioneerTest.sol:413-416
Timestamp: 2025-08-08T11:14:54.317Z
Learning: In ConvertibleDepositAuctioneer (src/policies/deposits/ConvertibleDepositAuctioneer.sol), bid() reverts with ConvertibleDepositAuctioneer_ConvertedAmountZero when ohmOut == 0, before evaluating the minOhmOut slippage check. Therefore, setting minOhmOut=0 does not guarantee acceptance in zero-output scenarios; the zero-output revert triggers first.

Applied to files:

  • src/policies/deposits/LimitOrders.sol
🪛 GitHub Actions: Build Size
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol

[error] 11-11: Source 'src/CDAuctioneerLimitOrders.sol' not found: File not found. ParserError: Source 'src/CDAuctioneerLimitOrders.sol' not found. Searched locations: '/home/runner/work/olympus-v3/olympus-v3'.

🪛 GitHub Actions: Lint Check
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol

[warning] 1-1: Prettier formatting issues detected in 'src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol'. Run 'prettier --write' to fix code style issues.

src/policies/deposits/LimitOrders.sol

[warning] 1-1: Prettier formatting issues detected in 'src/policies/deposits/LimitOrders.sol'. Run 'prettier --write' to fix code style issues.

🪛 GitHub Actions: Test Code Coverage
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol

[error] 11-11: Source 'src/CDAuctioneerLimitOrders.sol' not found. Import statement references a missing file. Searched paths: /home/runner/work/olympus-v3/olympus-v3

🪛 GitHub Actions: Tests - Cross-Chain
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol

[error] 11-11: Compiler run failed: Source "src/CDAuctioneerLimitOrders.sol" not found: File not found. Searched locations: .../olympus-v3

🪛 GitHub Actions: Tests - Fork
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol

[error] 11-11: Source 'src/CDAuctioneerLimitOrders.sol' not found: File not found. Searched the following locations: '/home/runner/work/olympus-v3/olympus-v3'. Import in LimitOrders.t.sol:11.

🪛 GitHub Actions: Tests - OCG Proposals
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol

[error] 11-11: Compiler run failed: Source "src/CDAuctioneerLimitOrders.sol" not found. Searched locations include project root.

🪛 GitHub Actions: Tests - Unit
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol

[error] 11-11: Compiler run failed: Source "src/CDAuctioneerLimitOrders.sol" not found. ParserError: Source not found for import in LimitOrders.t.sol (import {CDAuctioneerLimitOrders, ICDAuctioneer} from "src/CDAuctioneerLimitOrders.sol").

🔇 Additional comments (14)
src/policies/deposits/LimitOrders.sol (6)

114-143: Constructor validation is thorough.

Good input validation for all addresses. The max approval to SUSDS is a common pattern for vault interactions and is safe since SUSDS is trusted.


164-218: Order creation logic is sound.

Proper validation, reentrancy protection, and accounting. The flow (transfer → deposit to sUSDS → track owed) correctly maintains yield accounting.


227-274: Change order logic correctly handles fund adjustments.

The reset of depositSpent and incentiveSpent to zero is documented behavior. The calculation of fund differences handles both increase and decrease cases properly.


371-374: Defensive underflow checks are good practice.

The ternary operators on lines 372-373 prevent underflow in edge cases. This defensive coding is appropriate for a financial contract.


4-10: Mixed OpenZeppelin versions are intentional and correctly configured.

The use of @openzeppelin-5.3.0 for ReentrancyGuardTransient and @openzeppelin (4.8.0) for other contracts follows the project's preference for explicit version opt-in. The interface import path is correct: ../interfaces/deposits/IConvertibleDepositAuctioneer.sol points to the existing file at src/policies/interfaces/deposits/IConvertibleDepositAuctioneer.sol.


319-341: Accounting mismatch between fillAmount_ and actualAmount can occur.

The order's depositSpent is incremented by fillAmount_ (line 319), but the receipt tokens transferred are based on actualAmount (line 340), which corresponds to depositIn from the auctioneer. In ConvertibleDepositAuctioneer._previewBid() (line 406), depositIn = deposit_ - remainingDeposit, meaning the actual deposit used can be less than fillAmount_ if the bid loop exits early when convertibleAmount == 0. While the check at line 309 prevents zero output, it does not guarantee depositIn == fillAmount_. This creates an inconsistency: the order tracks spending fillAmount_ but receives receipt tokens representing only depositIn, potentially understating what was actually spent for the order.

⛔ Skipped due to learnings
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 88
File: src/test/policies/ConvertibleDepositAuctioneer/ConvertibleDepositAuctioneerTest.sol:413-416
Timestamp: 2025-08-08T11:14:54.317Z
Learning: In ConvertibleDepositAuctioneer (src/policies/deposits/ConvertibleDepositAuctioneer.sol), bid() reverts with ConvertibleDepositAuctioneer_ConvertedAmountZero when ohmOut == 0, before evaluating the minOhmOut slippage check. Therefore, setting minOhmOut=0 does not guarantee acceptance in zero-output scenarios; the zero-output revert triggers first.
src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol (8)

27-47: MockSUSDS correctly simulates yield accrual.

The exchange rate manipulation via setExchangeRate allows testing yield scenarios. The override of _convertToShares and _convertToAssets properly uses the Math.Rounding parameter from the parent ERC4626.


69-144: MockCDAuctioneer adequately simulates the real auctioneer.

The mock correctly:

  • Returns 0 from previewBid when below minimum (testing ZeroOhmOut path)
  • Mints tokens to msg.sender (the limit orders contract)
  • Uses controllable price and minimum bid for various test scenarios

166-210: Test setup is well-structured.

Good separation of concerns with distinct addresses for owner, users (alice, bob), filler, and yieldRecipient. The setup properly initializes multiple deposit periods.


226-239: Tests use undefined functions.

These tests call getOrder() (line 226) and getSUsdsBalance() (line 238) which are not defined in the contract. See the contract review for the missing function implementations.


347-367: Good test for final fill incentive logic.

This test validates the important dust-avoidance behavior where the final fill receives all remaining incentive rather than a proportional amount.


473-489: Correct partial fill refund calculation.

The test correctly calculates the expected refund: 7000 deposit remaining + 35 incentive remaining (50 - 15 spent on 3000 fill).


545-551: Test expects revert but contract returns 0.

As flagged in the contract review, sweepYield() returns 0 when there's no yield, but this test expects NoYieldToSweep revert. Align the contract implementation with this test expectation.


818-847: Good coverage of change order after partial fill.

This test validates the documented behavior that changeOrder resets spent amounts, allowing flexible order modification even after partial fills.

Comment thread src/policies/deposits/LimitOrders.sol Outdated
Comment thread src/policies/deposits/LimitOrders.sol Outdated
Comment thread src/policies/deposits/LimitOrders.sol
Comment thread src/policies/deposits/LimitOrders.sol
Comment thread src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol Outdated
@0xJem 0xJem self-assigned this Dec 25, 2025
@0xJem
0xJem marked this pull request as ready for review January 2, 2026 10:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/policies/deposits/LimitOrders.sol (1)

500-509: sweepYield returns 0 on no yield — past comment suggested revert.

A previous review noted that tests expect a NoYieldToSweep revert when there's no yield, but line 502 returns 0 instead. If tests have been updated to match this behavior, this is fine. Otherwise, consider:

     function sweepYield() external nonReentrant onlyEnabled returns (uint256 shares) {
         shares = getAccruedYieldShares();
-        if (shares == 0) return 0;
+        if (shares == 0) revert NoYieldToSweep();

Note: The NoYieldToSweep error would need to be added to the interface if this change is made.

🧹 Nitpick comments (11)
src/test/mocks/MockDepositManager.sol (1)

2-2: Verify the higher minimum pragma version requirement.

This mock uses pragma solidity >=0.8.20, which is higher than other files in this PR (>=0.8.0 for IVersioned.sol, >=0.8.15 for others). Confirm whether this higher requirement is necessary or if it should be aligned with the rest of the codebase for consistency.

src/test/mocks/MockPrice.sol (1)

2-2: Verify pragma version consistency across the PR.

This file uses >=0.8.15, but other new files in this PR use different minimum versions: IVersioned.sol uses >=0.8.0 and MockDepositManager.sol uses >=0.8.20. Ensure these differences are intentional and align with project standards.

#!/bin/bash
# Description: Check pragma versions across all Solidity files in this PR

# Search for pragma declarations to identify version inconsistencies
rg -n "pragma solidity" --type sol
src/test/lib/bonds/BondAggregator.sol (1)

2-2: Consider adding an upper bound to the pragma.

While broadening the Solidity version for test code is acceptable, using >=0.8.15 without an upper bound could introduce unexpected behavior with future major versions (e.g., 0.9.0+). Consider using >=0.8.15 <0.9.0 to avoid potential breaking changes.

🔎 Proposed fix
-pragma solidity >=0.8.15;
+pragma solidity >=0.8.15 <0.9.0;
src/test/lib/bonds/BondFixedTermSDA.sol (1)

2-2: Consider adding an upper bound to the pragma.

Same as BondAggregator.sol, consider using >=0.8.15 <0.9.0 to avoid potential breaking changes in future major compiler versions.

src/test/lib/bonds/bases/BondBaseSDA.sol (1)

2-2: Consider adding an upper bound to the pragma.

Consider using >=0.8.15 <0.9.0 to avoid potential breaking changes in future major compiler versions.

src/test/lib/bonds/bases/BondBaseTeller.sol (1)

2-2: Consider adding an upper bound to the pragma.

Consider using >=0.8.15 <0.9.0 to avoid potential breaking changes in future major compiler versions.

src/test/policies/EmissionManager.t.sol (1)

3-3: Pragma bump and MockConvertibleDepositAuctioneer ctor updates look safe; consider a clearer dummy for the new arg.

  • Bumping the test pragma to >=0.8.20 is fine as long as your global toolchain/Foundry config already targets 0.8.20+.
  • The updated MockConvertibleDepositAuctioneer constructor calls all pass address(0) for the new middle parameter and vary only the final asset argument. That keeps existing test intent intact (only the deposit asset is relevant), but it’s a bit opaque.

If the new ctor parameter represents something meaningful (e.g., facility/manager), you might optionally:

  • Introduce a dedicated dummy address/contract in tests instead of address(0) to make misuse more obvious if the mock starts reading that field later.

Functionally everything still aligns with the previous expectations around asset-mismatch and decimal handling.

Also applies to: 317-321, 845-845, 3265-3266

src/scripts/deploy/DeployV3.s.sol (1)

799-850: Limit-orders deploy function is wired correctly; consider a small sanity check on arg arrays.

The new deployConvertibleDepositAuctioneerLimitOrders():

  • Resolves dependencies via _getAddressNotZero using keys that match env.json (DepositManager, ConvertibleDepositAuctioneer, USDS, sUSDS, OlympusDepositPositionManager, OlympusTreasury).
  • Reads depositPeriods and receiptTokens from the sequence under "ConvertibleDepositAuctioneerLimitOrders", then passes them directly into the CDAuctioneerLimitOrders constructor.
  • Returns "olympus.periphery" as the prefix, matching the env/deployments keys.

Two optional robustness tweaks you might consider:

  • Require non-empty arrays and matching lengths before deployment to catch misconfigured sequence files early:
Optional precondition guard
        uint8[] memory depositPeriods = _readDeploymentArgUint8Array(
            "ConvertibleDepositAuctioneerLimitOrders",
            "depositPeriods"
        );
        address[] memory receiptTokens = _readDeploymentArgAddressArray(
            "ConvertibleDepositAuctioneerLimitOrders",
            "receiptTokens"
        );
+
+       require(depositPeriods.length > 0, "LimitOrders: no depositPeriods");
+       require(
+           depositPeriods.length == receiptTokens.length,
+           "LimitOrders: periods/receipts length mismatch"
+       );

Not mandatory, but it would make misconfigured JSON fail fast at script time rather than later.

src/test/policies/ConvertibleDepositAuctioneer/LimitOrdersFork.t.sol (1)

1-181: Fork test wiring looks solid; you may want to assert on NFT/receipt token outcomes as well.

  • Mainnet constants for DEPOSIT_MANAGER, CD_AUCTIONEER, USDS, SUSDS, POSITION_NFT, and CD_FACILITY all line up with the addresses in env.json at the time of this PR.
  • _deployLimitOrders correctly discovers enabled deposit periods and corresponding receipt tokens from DepositManager and wires them into a fresh CDAuctioneerLimitOrders instance, then enables it and funds the test user.
  • test_createAndFillOrder exercises a realistic create→fill path (including a previewBid-based price sanity check and a full fill).

Optional coverage improvement:

  • After the fill, you could explicitly assert that:
    • The user’s POSITION_NFT balance increased and/or the specific position token was minted.
    • The expected receipt token balance (for the chosen period) is held by the user.

That would make the fork test validate not just order accounting and incentives, but also that the on-chain CD pipeline delivered the expected position assets.

src/policies/deposits/LimitOrders.sol (2)

221-248: Consider warning users when incentive budget is reduced to zero.

The _deposit function correctly handles sUSDS rounding, but if actualDeposit <= depositBudget_, the entire incentiveBudget_ is silently discarded (line 238-240). Users who intended to offer incentives might not realize this happened.

Consider either:

  1. Emitting an event when the actual budgets differ from requested
  2. Documenting this behavior prominently in the createOrder NatSpec

This is a design choice rather than a bug, so flagging for awareness.


675-693: Consider validating index1 >= index0 to provide clearer error.

Line 680 would revert with an arithmetic underflow if index1 < index0. While this is safe (reverts), a clearer error message would improve UX:

     function _getFillableOrders(
         uint8 depositPeriod_,
         uint256 index0,
         uint256 index1
     ) internal view returns (uint256[] memory) {
+        if (index1 < index0) revert InvalidParam("index range");
         uint256[] memory tmp = new uint256[](index1 - index0);

This is a minor improvement for clarity.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcc4905 and 08cb07a.

📒 Files selected for processing (25)
  • deployments/.sepolia-1766489520.json
  • deployments/.sepolia-1766582124.json
  • src/interfaces/IVersioned.sol
  • src/modules/CHREG/OlympusClearinghouseRegistry.sol
  • src/modules/RANGE/OlympusRange.sol
  • src/modules/RANGE/RANGE.v2.sol
  • src/policies/deposits/LimitOrders.sol
  • src/policies/interfaces/deposits/ILimitOrders.sol
  • src/scripts/deploy/DeployV3.s.sol
  • src/scripts/deploy/savedDeployments/convertible_deposit_limit_orders.json
  • src/scripts/deploy/savedDeployments/convertible_deposit_limit_orders_sepolia.json
  • src/scripts/env.json
  • src/scripts/ops/batches/PeripheryEnable.sol
  • src/scripts/ops/batches/args/ConvertibleDepositLimitOrders.json
  • src/test/lib/bonds/BondAggregator.sol
  • src/test/lib/bonds/BondFixedTermSDA.sol
  • src/test/lib/bonds/BondFixedTermTeller.sol
  • src/test/lib/bonds/bases/BondBaseSDA.sol
  • src/test/lib/bonds/bases/BondBaseTeller.sol
  • src/test/mocks/MockConvertibleDepositAuctioneer.sol
  • src/test/mocks/MockDepositManager.sol
  • src/test/mocks/MockPrice.sol
  • src/test/policies/ConvertibleDepositAuctioneer/LimitOrders.t.sol
  • src/test/policies/ConvertibleDepositAuctioneer/LimitOrdersFork.t.sol
  • src/test/policies/EmissionManager.t.sol
✅ Files skipped from review due to trivial changes (4)
  • src/scripts/ops/batches/args/ConvertibleDepositLimitOrders.json
  • src/modules/RANGE/RANGE.v2.sol
  • src/test/lib/bonds/BondFixedTermTeller.sol
  • deployments/.sepolia-1766489520.json
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: src/policies/deposits/BaseDepositFacility.sol:631-639
Timestamp: 2025-11-07T11:09:53.808Z
Learning: OlympusDAO/olympus-v3: BaseDepositFacility.setAssetPeriodReclaimRate now uses a dedicated reclaim-rate error (not InvalidAddress) when reclaimRate_ > ONE_HUNDRED_PERCENT, fixed in a follow-up PR (#180). Avoid re-flagging this in earlier PRs.
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 86
File: src/policies/deposits/DepositManager.sol:271-320
Timestamp: 2025-08-08T07:33:13.575Z
Learning: DepositManager (src/policies/deposits/DepositManager.sol) is deployed as non-upgradeable; when releasing a new version, existing receipt tokens and underlying deposits remain with the previous DepositManager instance. No migration path is expected or required when introducing facility scoping.
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: src/modules/TRSRY/TRSRY.v1.sol:2-2
Timestamp: 2025-07-18T00:21:49.138Z
Learning: 0xJem prefers to avoid changing historical/already-deployed contracts to minimize risk and maintain stability, even when it would improve consistency across the codebase.
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: remappings.txt:35-40
Timestamp: 2025-07-18T00:22:32.511Z
Learning: 0xJem prefers to keep OpenZeppelin 4.8.0 as the standard/default dependency in remappings.txt for stability, with newer versions like 5.3.0 available only through explicit versioned dependency paths (e.g., openzeppelin-5.3.0/) to ensure intentional opt-in to newer versions.
📚 Learning: 2025-08-08T07:33:13.575Z
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 86
File: src/policies/deposits/DepositManager.sol:271-320
Timestamp: 2025-08-08T07:33:13.575Z
Learning: DepositManager (src/policies/deposits/DepositManager.sol) is deployed as non-upgradeable; when releasing a new version, existing receipt tokens and underlying deposits remain with the previous DepositManager instance. No migration path is expected or required when introducing facility scoping.

Applied to files:

  • src/scripts/deploy/savedDeployments/convertible_deposit_limit_orders.json
  • src/scripts/deploy/savedDeployments/convertible_deposit_limit_orders_sepolia.json
  • src/test/policies/ConvertibleDepositAuctioneer/LimitOrdersFork.t.sol
  • src/test/policies/EmissionManager.t.sol
  • src/scripts/deploy/DeployV3.s.sol
  • src/test/mocks/MockConvertibleDepositAuctioneer.sol
  • src/test/mocks/MockDepositManager.sol
  • src/policies/interfaces/deposits/ILimitOrders.sol
  • src/policies/deposits/LimitOrders.sol
📚 Learning: 2025-08-08T11:14:54.317Z
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 88
File: src/test/policies/ConvertibleDepositAuctioneer/ConvertibleDepositAuctioneerTest.sol:413-416
Timestamp: 2025-08-08T11:14:54.317Z
Learning: In ConvertibleDepositAuctioneer (src/policies/deposits/ConvertibleDepositAuctioneer.sol), bid() reverts with ConvertibleDepositAuctioneer_ConvertedAmountZero when ohmOut == 0, before evaluating the minOhmOut slippage check. Therefore, setting minOhmOut=0 does not guarantee acceptance in zero-output scenarios; the zero-output revert triggers first.

Applied to files:

  • src/test/policies/EmissionManager.t.sol
  • src/scripts/deploy/DeployV3.s.sol
  • src/test/mocks/MockConvertibleDepositAuctioneer.sol
  • src/policies/interfaces/deposits/ILimitOrders.sol
  • src/policies/deposits/LimitOrders.sol
📚 Learning: 2025-11-07T11:09:53.808Z
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: src/policies/deposits/BaseDepositFacility.sol:631-639
Timestamp: 2025-11-07T11:09:53.808Z
Learning: OlympusDAO/olympus-v3: BaseDepositFacility.setAssetPeriodReclaimRate now uses a dedicated reclaim-rate error (not InvalidAddress) when reclaimRate_ > ONE_HUNDRED_PERCENT, fixed in a follow-up PR (#180). Avoid re-flagging this in earlier PRs.

Applied to files:

  • src/test/mocks/MockConvertibleDepositAuctioneer.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: Cursor Bugbot
🔇 Additional comments (21)
src/interfaces/IVersioned.sol (1)

1-14: LGTM!

The IVersioned interface is well-defined and documented. The use of >=0.8.0 provides maximum compatibility for an interface, and the forge-lint directives appropriately handle the mixed-case function naming convention.

src/test/mocks/MockDepositManager.sol (2)

26-38: Verify test coverage handles the simplified mock logic.

The deposit() and withdraw() functions perform actual token transfers but return hardcoded values (e.g., receiptTokenId = 1) and lack validation logic present in real implementations. Since this is a test mock, the simplified logic is acceptable, but ensure that:

  1. Tests using this mock don't rely on receipt token ID generation logic
  2. Tests cover edge cases that would normally be caught by validation (e.g., zero amounts, unauthorized callers)
  3. The actual DepositManager contract is tested separately with full validation

40-161: LGTM!

The stub implementations returning zero/empty values are appropriate for a test mock. This allows tests to focus on the specific interactions they care about without requiring full DepositManager behavior.

src/modules/CHREG/OlympusClearinghouseRegistry.sol (1)

2-2: Contract is already deployed in production—clarify if pragma change is necessary and whether the contract has been tested with compiler versions beyond 0.8.15.

OlympusClearinghouseRegistry is deployed on mainnet (0x69a3E97027d21a5984B6a543b36603fFbC6543a4), Sepolia (0x38038bdd78602e5AA2accd0Ce07557369e21a6c1), and Goerli. The current pragma (>=0.8.15) is already permissive and accepts any version >= 0.8.15. However:

  1. Confirm whether this pragma represents an actual change and, if so, why it is necessary for the limit-orders feature
  2. The codebase supports compilation with 0.8.24 (for some contracts), but CHREG is compiled with 0.8.15 per foundry.toml defaults. Confirm whether CHREG has been tested with 0.8.24 before deploying
src/modules/RANGE/OlympusRange.sol (1)

2-2: The pragma is already broadened to >=0.8.15—this change has already been applied.

OlympusRange is deployed on mainnet (0xb212D9584cfc56EFf1117F412Fe0bBdc53673954 and newer v2 at 0x399cD3685912bb56aAeD0949119dB6cE5Df60FB5). The RANGE v2 architecture uses >=0.8.15 consistently across RANGEv2 and OlympusRange.

However, there is a build-system constraint: foundry.toml forces all code to compile with Solidity 0.8.15 specifically ({ paths = "**", version = "0.8.15" }), despite the pragma declaring compatibility with newer versions. No testing with compiler versions >0.8.15 has been performed. The permissive pragma should either be tightened to pragma solidity 0.8.15; to match the actual build environment, or the foundry restriction should be relaxed and testing conducted with newer versions if forward compatibility is intended.

src/scripts/deploy/savedDeployments/convertible_deposit_limit_orders.json (1)

1-13: Verify the receipt token address against the deployed DepositManager state on the target network.

The configuration structure is valid: the depositPeriods and receiptTokens arrays have matching lengths (both length 1) as required by the constructor, and depositPeriods: [3] is the established 3-month deposit period constant used throughout the system. However, the receipt token address 0x03d95a2f9A29228ea6D0690f2d1Bcd15973d926F must be confirmed to correspond to the existing receipt token created by the DepositManager for the USDS/3-month/ConvertibleDepositFacility combination on mainnet. Since the DepositManager is non-upgradeable and receipt tokens persist across new ConvertibleDepositAuctioneerLimitOrders deployments, ensure this address matches the actual token state on the target network before deployment.

src/scripts/deploy/savedDeployments/convertible_deposit_limit_orders_sepolia.json (1)

1-13: Limit-orders saved deployment JSON is consistent with DeployV3 wiring.

name matches the DeployV3 entry and depositPeriods/receiptTokens are aligned (both length 1). No issues from a scripting perspective.

src/scripts/env.json (1)

641-641: New env.json periphery entry matches deployment keying.

The ConvertibleDepositAuctioneerLimitOrders address under current.sepolia.olympus.periphery lines up with the "olympus.periphery.ConvertibleDepositAuctioneerLimitOrders" key returned from DeployV3. Looks consistent.

deployments/.sepolia-1766582124.json (1)

1-3: Deployment mapping is correctly keyed for the new periphery contract.

The mapping key olympus.periphery.ConvertibleDepositAuctioneerLimitOrders and address match the env.json entry and DeployV3 prefixing, so downstream resolution should work.

src/scripts/deploy/DeployV3.s.sol (1)

30-30: Helper array readers are consistent with existing deploy argument helpers.

The new _readDeploymentArgUint8Array / _readDeploymentArgAddressArray helpers follow the same pattern as the other _readDeploymentArg* utilities and align with the saved deployment JSON (uint arrays for depositPeriods, address arrays for receiptTokens). No functional concerns here.

Also applies to: 293-319

src/scripts/ops/batches/PeripheryEnable.sol (1)

1-35: Periphery enable batch script is minimal and correctly targets IEnabler.

The script cleanly:

  • Pulls a contract key from the batch args.
  • Resolves the address via _envAddressNotZero.
  • Adds a single IEnabler.enable(bytes("")) call and forwards via proposeBatch().

This is a nice generic helper for enabling periphery contracts (including the new limit-orders periphery). No changes needed.

src/test/mocks/MockConvertibleDepositAuctioneer.sol (2)

62-112: Mock bid() implementation looks reasonable for testing.

The function correctly simulates the real auctioneer behavior with deposit period validation, OHM calculation, and token interactions. The use of low-level calls with success checks (lines 97-100, 106-107) is acceptable for a mock where you control the target contracts.

One minor observation: the actualAmount calculation on line 80 uses subtraction which could underflow if actualAmountDifference > depositAmount_, though this is controlled by test setup.


236-255: Test helper setDepositPeriodEnabled is functional for test scenarios.

The swap-and-pop pattern for array removal is correct. Note that calling setDepositPeriodEnabled(period, true) twice for the same period would add duplicates to enabledPeriods since the mapping would already be true and found would be set. This is acceptable for a test mock if tests avoid this pattern.

src/policies/deposits/LimitOrders.sol (7)

87-121: Constructor implementation is well-structured.

All immutable addresses are validated for non-zero values, array length mismatch is checked, and deposit periods are initialized in a loop. The max approval to sUSDS (line 118) is standard for ERC4626 vault interactions.


451-473: cancelOrder correctly allows cancellation even when contract is disabled.

The function intentionally omits onlyEnabled to allow users to withdraw funds if the contract is disabled. The use of saturatingSub (lines 461-462) is defensive programming—while the revert on line 458 should prevent underflow, the saturating subtraction provides an extra safety layer.


555-566: calculateIncentive now correctly handles final fills.

The function delegates to _calculateFillAndIncentive (line 564) which properly returns all remaining incentive on final fills (lines 346-350). This addresses the previous review comment about inconsistency with fillOrder.


517-519: getOrder getter is now implemented as requested.

This addresses the previous review comment about needing a helper function to return the LimitOrder struct rather than the tuple from the public mapping.


761-768: The super.supportsInterface(interfaceId) call is correctly supported. PeripheryEnabler implements supportsInterface (returning true for ERC-165 and IEnabler interface), so the code compiles and functions properly. No changes needed.

Likely an incorrect or invalid review comment.


283-285: The use of tokenId=0 as a sentinel value to verify the caller can receive ERC721 tokens is standard practice and not problematic. OpenZeppelin's checkOnERC721Received forwards the exact tokenId provided, and using 0 as a dummy value for capability checks is the intended pattern (also confirmed in the test suite). The LimitOrders contract's onERC721Received implementation ignores the tokenId parameter and simply returns the selector, so any value works. No action needed.


408-418: No issues found. The approval to DEPOSIT_MANAGER is correct and intentional—DEPOSIT_MANAGER is the contract that ultimately pulls USDS tokens from LimitOrders via safeTransferFrom during the deposit process.

src/policies/interfaces/deposits/ILimitOrders.sol (1)

9-40: Error definitions are comprehensive.

All necessary errors are defined for the contract's revert conditions. Note that if sweepYield is later changed to revert on zero yield (as suggested in past reviews), a NoYieldToSweep error would need to be added here.

Comment thread src/policies/interfaces/deposits/ILimitOrders.sol

@cursor cursor 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.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Comment thread src/policies/deposits/LimitOrders.sol

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/scripts/deploy/DeployV3.s.sol:
- Around line 813-821: The deployment reads depositPeriods via
_readDeploymentArgUint8Array and receiptTokens via
_readDeploymentArgAddressArray but doesn't check their lengths; add a validation
right after reading these arrays that requires depositPeriods.length ==
receiptTokens.length (use require or revert with a clear message referencing
depositPeriods and receiptTokens) before constructing the
ConvertibleDepositAuctioneerLimitOrders/CDAuctioneerLimitOrders to ensure the
arrays correspond 1:1 and prevent confusing constructor failures.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8e58f2 and a83cfdd.

📒 Files selected for processing (1)
  • src/scripts/deploy/DeployV3.s.sol
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: src/policies/deposits/BaseDepositFacility.sol:631-639
Timestamp: 2025-11-07T11:09:53.808Z
Learning: OlympusDAO/olympus-v3: BaseDepositFacility.setAssetPeriodReclaimRate now uses a dedicated reclaim-rate error (not InvalidAddress) when reclaimRate_ > ONE_HUNDRED_PERCENT, fixed in a follow-up PR (#180). Avoid re-flagging this in earlier PRs.
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: src/modules/TRSRY/TRSRY.v1.sol:2-2
Timestamp: 2025-07-18T00:21:49.138Z
Learning: 0xJem prefers to avoid changing historical/already-deployed contracts to minimize risk and maintain stability, even when it would improve consistency across the codebase.
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 29
File: remappings.txt:35-40
Timestamp: 2025-07-18T00:22:32.511Z
Learning: 0xJem prefers to keep OpenZeppelin 4.8.0 as the standard/default dependency in remappings.txt for stability, with newer versions like 5.3.0 available only through explicit versioned dependency paths (e.g., openzeppelin-5.3.0/) to ensure intentional opt-in to newer versions.
📚 Learning: 2025-08-08T07:33:13.575Z
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 86
File: src/policies/deposits/DepositManager.sol:271-320
Timestamp: 2025-08-08T07:33:13.575Z
Learning: DepositManager (src/policies/deposits/DepositManager.sol) is deployed as non-upgradeable; when releasing a new version, existing receipt tokens and underlying deposits remain with the previous DepositManager instance. No migration path is expected or required when introducing facility scoping.

Applied to files:

  • src/scripts/deploy/DeployV3.s.sol
📚 Learning: 2025-08-08T11:14:54.317Z
Learnt from: 0xJem
Repo: OlympusDAO/olympus-v3 PR: 88
File: src/test/policies/ConvertibleDepositAuctioneer/ConvertibleDepositAuctioneerTest.sol:413-416
Timestamp: 2025-08-08T11:14:54.317Z
Learning: In ConvertibleDepositAuctioneer (src/policies/deposits/ConvertibleDepositAuctioneer.sol), bid() reverts with ConvertibleDepositAuctioneer_ConvertedAmountZero when ohmOut == 0, before evaluating the minOhmOut slippage check. Therefore, setting minOhmOut=0 does not guarantee acceptance in zero-output scenarios; the zero-output revert triggers first.

Applied to files:

  • src/scripts/deploy/DeployV3.s.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). (8)
  • GitHub Check: run-ci
  • GitHub Check: Cursor Bugbot
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
  • GitHub Check: run-ci
🔇 Additional comments (4)
src/scripts/deploy/DeployV3.s.sol (4)

30-30: LGTM!

The import is correctly placed and follows the established pattern for policy imports.


293-309: LGTM!

The helper function correctly reads and converts uint256 arrays from JSON to uint8 arrays, using SafeCast for safe type conversion that will revert on overflow.


311-319: LGTM!

The helper function follows the established pattern for reading deployment arguments and correctly handles address arrays.


823-850: Deployment flow follows established patterns.

The logging, broadcast, and return structure align well with other deployment functions in this file. The owner configuration to the DAO multisig is appropriate for governance control.

Comment thread src/scripts/deploy/DeployV3.s.sol
depositSpent: 0,
incentiveSpent: 0,
maxPrice: maxPrice_,
minFillSize: minFillSize_

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

minFillSize validation bypassed due to rounding loss

Medium Severity

The minFillSize validation on line 281 checks against the input depositBudget_, but the order is created with actualDepositBudget which can be less due to sUSDS rounding losses. When actualDepositBudget < minFillSize_ <= depositBudget_, the order gets created with minFillSize > depositBudget. This causes the minimum fill check in fillOrder (line 393) to always evaluate as false since remainingDeposit < minFillSize, treating every fill as a "final fill" and allowing any fill size. This defeats the anti-griefing protection that minFillSize is intended to provide.

Fix in Cursor Fix in Web

@0xJem

0xJem commented Jan 7, 2026

Copy link
Copy Markdown
Member Author

Deployed to mainnet, awaiting activation by DAO MS

@0xJem
0xJem merged commit 5715d2b into develop Jan 13, 2026
9 checks passed
@0xJem
0xJem deleted the feature/cd-limit-orders branch January 13, 2026 08:56
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.

3 participants