Skip to content

feat: add Commodities.UKOILSPOT (Brent Crude Oil) price feed#19

Open
alastairong1 wants to merge 4 commits intomainfrom
add-ukoilspot-feed
Open

feat: add Commodities.UKOILSPOT (Brent Crude Oil) price feed#19
alastairong1 wants to merge 4 commits intomainfrom
add-ukoilspot-feed

Conversation

@alastairong1
Copy link

@alastairong1 alastairong1 commented Mar 19, 2026

Summary

  • Adds Commodities.UKOILSPOT (Brent Crude Oil CFD spot) to the Pyth symbol-to-feed-ID mapping
  • Feed ID: 0x27f0d5e09a830083e5491795cac9ca521399c8f7fd56240d09484b14e614d57a
  • This is the first commodity feed — enables Rain strategies to price oil-backed tokenized assets using pyth-price(pair timeout) with the UKOILSPOT symbol

Changes

  • src/lib/pyth/LibPyth.sol — Added PRICE_FEED_ID_COMMODITIES_UKOILSPOT + PRICE_FEED_SYMBOL_INTORASTRING_COMMODITIES_UKOILSPOT constants and else if branch in getPriceFeedId()
  • src/generated/PythWords.pointers.sol — Regenerated BYTECODE_HASH
  • test/lib/LibFork.sol — Added FORK_BLOCK_BASE_UKOILSPOT (block 40538400, 16s after price publish)
  • test/src/lib/pyth/LibPyth.constants.t.sol — Added IntOrAString encoding assertion
  • test/src/lib/pyth/LibPyth.getPriceFeedId.t.sol — Added known mapping assertion + fuzz exclusion
  • test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol — Added fork test with 24h maxAge (price: $60.30017, conf: $0.15811)

Test plan

  • forge test — all 17 tests pass (constants, known mappings, fuzz, fork tests including new UKOILSPOT)
  • forge script script/BuildPointers.sol — pointers regenerated

Summary by CodeRabbit

  • New Features

    • Added support for the UK Oil Spot commodity price feed so it can be looked up and used by the system.
  • Tests

    • Added and updated tests to validate the new feed mapping, retrieval behavior, and time-based price checks across relevant forked environments.
  • Chores

    • Deployment script updated to use a fixed address for deterministic deployments.

alastairong1 and others added 2 commits March 19, 2026 12:06
Add Brent Crude Oil CFD spot price feed (Commodities.UKOILSPOT) to the
Pyth symbol-to-feed-ID mapping. This enables Rain strategies to use
pyth-price with the UKOILSPOT symbol for oil-backed tokenized assets.

Feed ID: 0x27f0d5e09a830083e5491795cac9ca521399c8f7fd56240d09484b14e614d57a

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use block 40538400 (16 seconds after price publish) instead of 40582366
(24.4 hours after) so the test can use 24 hours maxAge consistently
with all other fork tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 19, 2026

Walkthrough

Introduces a new commodity price feed (Commodities.UKOILSPOT): adds feed ID and symbol constants, updates Pyth library symbol-to-ID resolution, adds a fork constant, and extends tests to validate constants, mapping, and price retrieval for the new feed.

Changes

Cohort / File(s) Summary
Library Constants & Resolution
src/lib/pyth/LibPyth.sol
Added PRICE_FEED_ID_COMMODITIES_UKOILSPOT (bytes32) and PRICE_FEED_SYMBOL_INTORASTRING_COMMODITIES_UKOILSPOT (uint256); extended getPriceFeedId(IntOrAString) to return the new feed ID for Commodities.UKOILSPOT.
Test Fork Constants
test/lib/LibFork.sol
Added FORK_BLOCK_BASE_UKOILSPOT = 40538400 to the fork-block constants used by tests.
Unit Tests
test/src/lib/pyth/LibPyth.constants.t.sol, test/src/lib/pyth/LibPyth.getPriceFeedId.t.sol, test/src/lib/pyth/LibPyth.getPriceNoOlderThan.t.sol
Added assertions verifying the new symbol constant, mapping "Commodities.UKOILSPOT" → new feed ID, excluded the symbol from unknown-mapping fuzz inputs, and added a test selecting the UKOILSPOT fork to check getPriceNoOlderThan with a 24-hour maxAge against expected packed price/confidence.
Deployment Script
script/Deploy.sol
Replaced env-based metaboard address retrieval with a compile-time METABOARD_ADDRESS constant and direct instantiation of IMetaBoardV1_2(METABOARD_ADDRESS) (removed vm.envAddress usage).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 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 pull request title directly and accurately summarizes the main change: adding a new commodity price feed (Commodities.UKOILSPOT/Brent Crude Oil) to the Pyth symbol mapping, which is the primary focus across all modified files.
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.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-ukoilspot-feed
📝 Coding Plan
  • Generate coding plan for human review comments

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.

alastairong1 and others added 2 commits March 19, 2026 15:50
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MetaBoard is deployed via Zoltu CREATE2 deployer at the same address
on every chain, so there is no need for a DEPLOY_METABOARD_ADDRESS
environment variable. This fixes the deployment CI failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
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 `@script/Deploy.sol`:
- Around line 10-13: The code uses the constant METABOARD_ADDRESS to instantiate
and call MetaBoard without verifying that contract code exists there; add a
preflight check using extcodesize (or Address.code.length) on METABOARD_ADDRESS
and require it be > 0 with a clear error like "MetaBoard not deployed on this
chain" before creating the MetaBoard instance (the line that does
MetaBoard(METABOARD_ADDRESS)) or making any calls; if you prefer, import
OpenZeppelin's Address library and use Address.isContract(METABOARD_ADDRESS) for
the same guard.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4f5ffd67-5302-485c-86df-23c1a26d1bc2

📥 Commits

Reviewing files that changed from the base of the PR and between f5692ef and 65a18a9.

📒 Files selected for processing (1)
  • script/Deploy.sol

Comment on lines +10 to +13
/// @dev MetaBoard is deterministically deployed via Zoltu CREATE2 deployer
/// at the same address on every chain.
address constant METABOARD_ADDRESS = address(0xfb8437AeFBB8031064E274527C5fc08e30Ac6928);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether a hardcoded metaboard address is used without an on-chain code existence guard.
rg -n -C2 'METABOARD_ADDRESS|IMetaBoardV1_2\(METABOARD_ADDRESS\)|\.code\.length|MetaBoardNotDeployed' script/Deploy.sol

Repository: rainlanguage/rain.pyth

Length of output: 613


🏁 Script executed:

cat -n script/Deploy.sol

Repository: rainlanguage/rain.pyth

Length of output: 1387


Add a preflight contract-code check for the fixed MetaBoard address.

Using a constant address without verifying code exists on the active chain can make deployments brittle on chains where MetaBoard is not deployed yet. The instantiation at line 18 will succeed, but the call at line 22 will revert with a confusing error. Add a guard to fail fast.

🔧 Proposed fix
 address constant METABOARD_ADDRESS = address(0xfb8437AeFBB8031064E274527C5fc08e30Ac6928);
+error MetaBoardNotDeployed(address metaboard, uint256 chainId);

 contract Deploy is Script {
     function run() public {
         uint256 deployerPrivateKey = vm.envUint("DEPLOYMENT_KEY");
         bytes memory subParserDescribedByMeta = vm.readFileBinary("meta/PythWords.rain.meta");
+        if (METABOARD_ADDRESS.code.length == 0) {
+            revert MetaBoardNotDeployed(METABOARD_ADDRESS, block.chainid);
+        }
         IMetaBoardV1_2 metaboard = IMetaBoardV1_2(METABOARD_ADDRESS);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@script/Deploy.sol` around lines 10 - 13, The code uses the constant
METABOARD_ADDRESS to instantiate and call MetaBoard without verifying that
contract code exists there; add a preflight check using extcodesize (or
Address.code.length) on METABOARD_ADDRESS and require it be > 0 with a clear
error like "MetaBoard not deployed on this chain" before creating the MetaBoard
instance (the line that does MetaBoard(METABOARD_ADDRESS)) or making any calls;
if you prefer, import OpenZeppelin's Address library and use
Address.isContract(METABOARD_ADDRESS) for the same guard.

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