Skip to content

feat(lib): LibCorporateActionsPause reader helper (RAI-319)#22

Open
hardyjosh wants to merge 1 commit into
docs/spec-corporate-action-pausefrom
feat/lib-corporate-actions-pause
Open

feat(lib): LibCorporateActionsPause reader helper (RAI-319)#22
hardyjosh wants to merge 1 commit into
docs/spec-corporate-action-pausefrom
feat/lib-corporate-actions-pause

Conversation

@hardyjosh

Copy link
Copy Markdown
Collaborator

Stateless library that wraps ICorporateActionsV1 and tells callers whether the current block is inside any pre- or post-window of a matching scheduled or completed action.

Algorithm (from SPEC § 16.3):

  • Pending side: query earliestActionOfType(mask, PENDING). If now + pauseTimeBefore >= effectiveTime, return paused=true.
  • Completed side: query latestActionOfType(mask, COMPLETED). If now <= effectiveTime + pauseTimeAfter, return paused=true.
  • When both windows are open simultaneously, return the pending action's effectiveTime — integrators see the next event coming, not the last one done.

Short-circuits cleanly when corporateActionsVault == address(0) or mask == 0 — no external call, no state. Cancelled action nodes are unlinked from the linked list by st0x.deploy and unreachable from the traversal API, so no explicit filter is needed.

14 unit tests against a minimal MockCorporateActions stub cover:

  • both short-circuits (zero vault, zero mask)
  • no actions, pending only, completed only, both
  • exact-edge inclusivity at both window boundaries
  • mask filtering (matching and non-matching action types, wildcard)
  • zero-width window edges (pauseTimeBefore=0, pauseTimeAfter=0)
  • pending-takes-precedence-when-both-windows-open

Adds the rain.tofu.erc20-decimals foundry remapping needed by the transitive import chain ICorporateActionsV1 → LibCorporateActionNode → LibCorporateAction → LibStockSplit → LibTOFUTokenDecimals.

@linear

linear Bot commented May 9, 2026

Copy link
Copy Markdown

RAI-319

@coderabbitai

coderabbitai Bot commented May 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b6661b0-b8db-40d3-a8e4-753f2aea7f6a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/lib-corporate-actions-pause

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.

hardyjosh commented May 9, 2026

Copy link
Copy Markdown
Collaborator Author

@hardyjosh hardyjosh force-pushed the docs/spec-corporate-action-pause branch from 0540e39 to 581a552 Compare May 9, 2026 11:51
@hardyjosh hardyjosh force-pushed the feat/lib-corporate-actions-pause branch 2 times, most recently from ac0cecc to b9aca8c Compare May 9, 2026 12:08
@hardyjosh hardyjosh force-pushed the feat/lib-corporate-actions-pause branch from b9aca8c to 6c0d395 Compare May 11, 2026 21:22
@hardyjosh hardyjosh force-pushed the feat/lib-corporate-actions-pause branch from 6c0d395 to 8116e4f Compare May 26, 2026 17:35
@hardyjosh hardyjosh force-pushed the docs/spec-corporate-action-pause branch from 581a552 to 6af8c8f Compare May 26, 2026 17:35
Stateless library that wraps ICorporateActionsV1 and tells callers whether the current block is inside any pre- or post-window of a matching scheduled or completed action.

Algorithm (from SPEC § 16.3):
* Pending side: query earliestActionOfType(mask, PENDING). If now + pauseTimeBefore >= effectiveTime, return paused=true.
* Completed side: query latestActionOfType(mask, COMPLETED). If now <= effectiveTime + pauseTimeAfter, return paused=true.
* When both windows are open simultaneously, return the pending action's effectiveTime — integrators see the next event coming, not the last one done.

Short-circuits cleanly when corporateActionsVault == address(0) or mask == 0 — no external call, no state. Cancelled action nodes are unlinked from the linked list by st0x.deploy and unreachable from the traversal API, so no explicit filter is needed.

No-match detection uses the NODE_NONE = type(uint256).max sentinel
documented by ICorporateActionsV1.{earliest,latest}ActionOfType — cursor
0 is the bootstrap INIT node (a real walkable node) and must not be
treated as "no match". The pending and completed sides each treat
cursor == NODE_NONE as the unambiguous "no matching action" signal.

Adds three regression tests in `LibCorporateActionsPause.t.sol`:
- testNodeNoneSentinelOnBothSidesDoesNotPause — explicit no-match path
- testWildcardMaskAcceptsBootstrapCursorZero — bootstrap cursor-0 must
  be accepted as a real match under wildcard mask
- testFuzzPausedFalseImpliesEffectiveTimeZero — SPEC 16.3 invariant
  (paused=false iff effectiveTime=0)

Plus defensive boundary fuzz coverage (audit #72):
- testPendingEffectiveAtNowStillPausesDefensive — pins the documented
  "upstream filter is authoritative" behaviour when PENDING returns
  effectiveTime <= now
- testMaxPauseTimeAfterDoesNotOverflow — confirms uint256-space addition
  in post-window check tolerates type(uint64).max
- additional defensive fuzz tests

14+ unit tests against a shared MockCorporateActions stub
(`test/mocks/MockCorporateActions.sol`) cover:
* both short-circuits (zero vault, zero mask)
* no actions, pending only, completed only, both
* NODE_NONE no-match on both sides
* exact-edge inclusivity at both window boundaries
* mask filtering (matching and non-matching action types, wildcard)
* zero-width window edges (pauseTimeBefore=0, pauseTimeAfter=0)
* pending-takes-precedence-when-both-windows-open

The mock is intentionally shared from the start so the three test files
that will need it across the corporate-action stack (this one,
PythOracleAdapter.autoPause.t.sol, AutoPausePropagation.t.sol) cannot
drift on the ICorporateActionsV1 signature.

Adds the rain.tofu.erc20-decimals foundry remapping needed by the transitive import chain ICorporateActionsV1 → LibCorporateActionNode → LibCorporateAction → LibStockSplit → LibTOFUTokenDecimals.

Also gitignores `audit/` and `.fixes/` so the audit skill's local
artifacts don't pollute commits or REUSE compliance.

Found by /audit Pass 1 (Security) A15-1, Pass 5 (Correctness) A15p5-1,
and Pass 6 (Hazard Surface) H1 against ST0x-Technology/st0x.oracle at
3a24b5d..f45f652.

Closes #72, #207, #221.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hardyjosh hardyjosh force-pushed the feat/lib-corporate-actions-pause branch from 74112b9 to fd0d3ec Compare May 31, 2026 11:48
@hardyjosh hardyjosh force-pushed the docs/spec-corporate-action-pause branch from 6af8c8f to e9cc087 Compare May 31, 2026 11:48
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