Skip to content

Add SGOV Feed#20

Open
Siddharth2207 wants to merge 8 commits intomainfrom
2026-04-19-sgov
Open

Add SGOV Feed#20
Siddharth2207 wants to merge 8 commits intomainfrom
2026-04-19-sgov

Conversation

@Siddharth2207
Copy link
Copy Markdown
Contributor

@Siddharth2207 Siddharth2207 commented Apr 19, 2026

Motivation

Extend rain.pyth equity feed coverage by adding SGOV and additional ETF mappings so downstream consumers can resolve and read these symbols through the existing Pyth integration.

What Changed

  • Added new equity feed constants and symbol mappings in src/lib/pyth/LibPyth.sol for:
    • EQUITY.US.SGOV/USD
    • EQUITY.US.QQQM/USD
    • EQUITY.US.VMO/USD
    • EQUITY.US.ARKK/USD
  • Extended fork baselines and unit tests to validate feed-id resolution, constants, and getPriceNoOlderThan behavior for the new feeds.
  • Regenerated pointers/formatting updates required by parser/pointer workflow.
  • Updated related workflow/deploy/config touchpoints included in this branch.

Validation

  • Updated tests in:
    • test/src/lib/pyth/LibPyth.constants.t.sol
    • test/src/lib/pyth/LibPyth.getPriceFeedId.t.sol
    • test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol
  • Used fork baseline updates in test/lib/LibFork.sol for deterministic feed checks.

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 19, 2026

Walkthrough

Added SGOV/USD Pyth price feed constants and resolution logic, updated tests and fork baseline for SGOV (and several additional equity feeds). Also applied small formatting tweaks to function-pointer declarations, updated CI workflow prelude steps, replaced an env-based deploy address with a constant, and edited .gitignore.

Changes

SGOV Price Feed and Tests

Layer / File(s) Summary
Data Shape / Constants
src/lib/pyth/LibPyth.sol
Added PRICE_FEED_ID_EQUITY_US_SGOV_USD and PRICE_FEED_SYMBOL_INTORASTRING_EQUITY_US_SGOV_USD constants.
Core Implementation
src/lib/pyth/LibPyth.sol
Extended getPriceFeedId(IntOrAString) with a branch mapping the SGOV symbol to its feed ID (inserted before existing QQQM/VWO/ARKK branches).
Test Fork Baselines
test/lib/LibFork.sol
Added FORK_BLOCK_BASE_SGOV = 44912388.
Unit Tests — Constants & Mapping
test/src/lib/pyth/LibPyth.constants.t.sol, test/src/lib/pyth/LibPyth.getPriceFeedId.t.sol
Added assertions that SGOV (and QQQM/VWO/ARKK) symbol constants unwrap correctly and that getPriceFeedId returns expected feed IDs; expanded vm.assume(...) to exclude these known symbols from unknown-symbol tests.
Integration Tests — Forked Price Retrieval
test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol
Added external tests that fork Base at FORK_BLOCK_BASE_SGOV, FORK_BLOCK_BASE_QQQM, FORK_BLOCK_BASE_VWO, and FORK_BLOCK_BASE_ARKK, asserting getPriceNoOlderThan returns expected packed price/confidence values with given maxAge.

Formatting, CI, and Deploy

Layer / File(s) Summary
Repo Ignore
.gitignore
Updated ignore entries (ensure cache ignored) and added .pre-commit-config.yaml to the ignore list.
Minor Formatting
src/abstract/PythExtern.sol, src/abstract/PythSubParser.sol
Reformatted inline function-pointer type declarations into more compact single-line forms; no API or behavior changes.
CI Workflow
.github/workflows/manual-sol-artifacts.yaml
Added an extra nix develop -c rain-pyth-prelude step to the prelude sequence before rain-sol-artifacts; removed DEPLOY_METABOARD_ADDRESS from the deploy job env.
Deploy Script
script/Deploy.sol
Replaced environment-derived metaboard address with a fixed constant METABOARD_ADDRESS and initialize metaboard from that constant instead of vm.envAddress(...); deployment flow otherwise unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add SGOV Feed' accurately summarizes the main objective of the pull request, which adds support for a new SGOV/USD price feed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-04-19-sgov

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.gitignore:
- Line 3: Remove the .pre-commit-config.yaml entry from .gitignore so the shared
pre-commit configuration is tracked by the repository; locate the .gitignore
line that lists ".pre-commit-config.yaml" and delete that line (or stop ignoring
that specific filename) so the repository can update and version the pre-commit
hooks without requiring forced adds.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 752a9c68-8075-4373-a43f-b52657239ad9

📥 Commits

Reviewing files that changed from the base of the PR and between 7db8604 and df6cd9a.

⛔ Files ignored due to path filters (2)
  • flake.lock is excluded by !**/*.lock
  • src/generated/PythWords.pointers.sol is excluded by !**/generated/**
📒 Files selected for processing (8)
  • .gitignore
  • src/abstract/PythExtern.sol
  • src/abstract/PythSubParser.sol
  • src/lib/pyth/LibPyth.sol
  • test/lib/LibFork.sol
  • test/src/lib/pyth/LibPyth.constants.t.sol
  • test/src/lib/pyth/LibPyth.getPriceFeedId.t.sol
  • test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol

Comment thread .gitignore
out
cache No newline at end of file
cache
.pre-commit-config.yaml No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Don’t ignore the shared pre-commit config.

.pre-commit-config.yaml is normally repository-owned; ignoring it makes hook updates easy to miss and forces git add -f if the project later adopts pre-commit.

♻️ Proposed cleanup
-.pre-commit-config.yaml
📝 Committable suggestion

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

Suggested change
.pre-commit-config.yaml
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.gitignore at line 3, Remove the .pre-commit-config.yaml entry from
.gitignore so the shared pre-commit configuration is tracked by the repository;
locate the .gitignore line that lists ".pre-commit-config.yaml" and delete that
line (or stop ignoring that specific filename) so the repository can update and
version the pre-commit hooks without requiring forced adds.

@Siddharth2207 Siddharth2207 self-assigned this Apr 19, 2026
@Siddharth2207 Siddharth2207 requested a review from hardyjosh April 19, 2026 17:33
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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)
script/Deploy.sol (1)

12-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a bytecode existence guard for METABOARD_ADDRESS before emitting metadata.

On Line 18, the script trusts a fixed address without checking deployment presence. If that address is not deployed on a target network, metadata registration can fail or no-op unexpectedly. Add a hard fail before emitForDescribedAddress.

Suggested patch
-        IMetaBoardV1_2 metaboard = IMetaBoardV1_2(METABOARD_ADDRESS);
+        if (METABOARD_ADDRESS.code.length == 0) {
+            revert("METABOARD_ADDRESS has no code");
+        }
+        IMetaBoardV1_2 metaboard = IMetaBoardV1_2(METABOARD_ADDRESS);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@script/Deploy.sol` around lines 12 - 23, Add a bytecode-existence guard for
METABOARD_ADDRESS in run(): after creating metaboard (IMetaBoardV1_2 metaboard =
...), check address(metaboard).code.length > 0 (or
address(METABOARD_ADDRESS).code.length > 0) and revert/require with a clear
message (e.g., "METABOARD not deployed on this network") if zero; only call
LibDescribedByMeta.emitForDescribedAddress when the check passes so the script
hard-fails instead of silently continuing when the address has no deployed
bytecode.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol`:
- Around line 401-409: Add a clear NatSpec/doc comment above the
PRICE_FEED_ID_EQUITY_US_SGOV_USD constant in LibPyth.sol explaining that the
SGOV Pyth feed can be up to ~48 hours stale (versus the usual 24h for equities)
due to T-bill/ETF weekend and market-closure behavior, and recommend downstream
callers use staleAfter >= 48 hours (or handle weekend/holiday gaps) when calling
functions like getPriceNoOlderThan; include the rationale (iShares 0-3 Month
Treasury Bond updates/market closures) and the concrete recommended minimum
window so callers don’t choose a sub-48h staleAfter and trigger on-chain
reverts.

---

Outside diff comments:
In `@script/Deploy.sol`:
- Around line 12-23: Add a bytecode-existence guard for METABOARD_ADDRESS in
run(): after creating metaboard (IMetaBoardV1_2 metaboard = ...), check
address(metaboard).code.length > 0 (or address(METABOARD_ADDRESS).code.length >
0) and revert/require with a clear message (e.g., "METABOARD not deployed on
this network") if zero; only call LibDescribedByMeta.emitForDescribedAddress
when the check passes so the script hard-fails instead of silently continuing
when the address has no deployed bytecode.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f0522882-ab88-4c9a-b779-39777bc14eab

📥 Commits

Reviewing files that changed from the base of the PR and between df6cd9a and f2981c4.

⛔ Files ignored due to path filters (1)
  • src/generated/PythWords.pointers.sol is excluded by !**/generated/**
📒 Files selected for processing (7)
  • .github/workflows/manual-sol-artifacts.yaml
  • script/Deploy.sol
  • src/lib/pyth/LibPyth.sol
  • test/lib/LibFork.sol
  • test/src/lib/pyth/LibPyth.constants.t.sol
  • test/src/lib/pyth/LibPyth.getPriceFeedId.t.sol
  • test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol

Comment on lines +401 to +409
function testPriceNoOlderThanBaseSgov() external {
vm.createSelectFork(FORK_RPC_URL_BASE, FORK_BLOCK_BASE_SGOV);
checkPriceNoOlderThan(
LibIntOrAString.fromString2("Equity.US.SGOV/USD"),
LibDecimalFloat.packLossless(48 hours, 0),
LibDecimalFloat.packLossless(100.56505e5, -5),
LibDecimalFloat.packLossless(0.10552e5, -5)
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

SGOV uses 48 hours staleAfter — document the wider staleness requirement for callers.

Every other equity feed test uses 24 hours, but SGOV requires 48 hours at FORK_BLOCK_BASE_SGOV. This is expected for a T-bill ETF (iShares 0-3 Month Treasury Bond) whose Pyth price feed doesn't update over weekends or market-closure periods. The fork block likely falls on a post-weekend open, making the most recent published price ~48h old.

This is not a bug in the test, but downstream callers setting a sub-48h staleAfter for SGOV will encounter on-chain reverts during weekend/holiday gaps. A doc comment on the PRICE_FEED_ID_EQUITY_US_SGOV_USD constant noting this staleness characteristic would help callers set an appropriate window.

📝 Suggested doc comment addition in `src/lib/pyth/LibPyth.sol`
-    /// SGOV/USD
+    /// SGOV/USD (iShares 0-3 Month Treasury Bond ETF)
+    /// Note: this feed does not update during weekends or market closures; callers
+    /// should use a staleAfter window of at least 48 hours to avoid weekend reverts.
     bytes32 constant PRICE_FEED_ID_EQUITY_US_SGOV_USD =
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol` around lines 401 - 409,
Add a clear NatSpec/doc comment above the PRICE_FEED_ID_EQUITY_US_SGOV_USD
constant in LibPyth.sol explaining that the SGOV Pyth feed can be up to ~48
hours stale (versus the usual 24h for equities) due to T-bill/ETF weekend and
market-closure behavior, and recommend downstream callers use staleAfter >= 48
hours (or handle weekend/holiday gaps) when calling functions like
getPriceNoOlderThan; include the rationale (iShares 0-3 Month Treasury Bond
updates/market closures) and the concrete recommended minimum window so callers
don’t choose a sub-48h staleAfter and trigger on-chain reverts.

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