feat: /context/v7 signs the underlying price and drops the NAV ratio (RAI-2198) - #70
Open
hardyjosh wants to merge 1 commit into
Open
feat: /context/v7 signs the underlying price and drops the NAV ratio (RAI-2198)#70hardyjosh wants to merge 1 commit into
hardyjosh wants to merge 1 commit into
Conversation
…(RAI-2198) Part of the "derive, don't gate" pivot (RAI-1479). v6's exact-match NAV gate is a DoS surface (audit H03): the vault NAV can step between sign and settle for reasons outside any attacker's control, bricking otherwise-valid signed frames. v7 signs only the vault's UNDERLYING asset rate and leaves the NAV ratio UNSIGNED — the consuming strategy (RAI-2199) reads the vault's live convertToAssets on-chain at settlement and derives the vault price (underlying x convertToAssets(1 share)) atomically. Nothing to straddle. - /context/v7: the v5 nine-slot shape, slot 1 carrying the underlying price (directional underlying_rate_*, picked and inverted exactly as the vault rate), NO slot-9 ratio. v1-v6 stay served unchanged. - pick_underlying_rate_bytes: v7 analogue of pick_rate_bytes; fails closed on the all-zero "not carried" sentinel (old producer / misconfigured pair) rather than signing a garbage mark. - Carry underlying_rate_* from PriceFrame into the cached Quote so v7 signs off the same observation as everything else. - Re-pin st0x-pricing-types to the rev that added the underlying_rate_* fields; re-pin to tag v0.7.0 once pricing-types #4 merges and is tagged. Tests: v7 route + slot layout (underlying at slot 1, no ratio slot), v7-is-v5-shape, v5/v6 still sign the vault rate when underlying differs, maker orientation across v1/v4/v5/v6/v7, fail-closed on absent underlying. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQ3QV1QrwmaS7ACSf7cds7
ueco-jb
approved these changes
Sep 3, 2026
ueco-jb
left a comment
There was a problem hiding this comment.
LGTM 👍
I was wondering if this gave up the oracle's bound on the vault price, but I went back to your note on telegram and it cleared it up for me - keeping the ratio and banding it covers that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
/context/v7— the signed-context version for the "derive, don't gate" pivot (RAI-1479). v7 signs the vault's UNDERLYING asset price and drops the signed NAV ratio entirely. v1–v6 stay served unchanged.Why
v6's
/context/v6signs the NAV ratio at slot 9 and forces the strategy to assert exact equality against the vault's liveconvertToAssetsanswer at settlement. That exact-match gate is a DoS surface (audit H03): the vault NAV can step between the sign and the settle for reasons entirely outside an attacker's control, and every step bricks otherwise-valid signed frames.v7 removes the gate. It signs only the underlying price and leaves the ratio unsigned. The consuming Rainlang strat (RAI-2199, separate follow-on) reads the vault's live
erc4626-convert-to-assetson-chain at settlement and derives the vault price atomically:Nothing to straddle — the ratio used is always the live one. The underlying is the only quantity the on-chain side can re-derive the vault price from, so it is what must be signed. The server stays a dumb carrier: it signs the underlying rate straight off the same cached
Quote, no re-derivation.v7 slot layout (0-indexed) — load-bearing for RAI-2199
The v5 nine-slot shape, but slot 1 is the underlying price and there is no slot 9:
context[0]: schema version (Rain Float, = 7)context[1]: UNDERLYING price (Rain Float; directionalunderlying_rate_*for the request's swap direction, inverted into Raindex ratio units, spread included)context[2]: publish_time (Rain Float, Unix seconds)context[3]: session tag (Rain IntOrAString V3, bytes32)context[4]: session_start (Rain Float, Unix seconds)context[5]: session_end (Rain Float, Unix seconds)context[6]: input_token address (bytes32, Address left-padded)context[7]: output_token address (bytes32, Address left-padded)context[8]: quote expiry (Rain Float, Unix seconds;less-thanconsumer assert makes the expiry second itself EXCLUSIVE)No
context[9]. 9 elements total. The ratio is never signed; the strat reads it live on-chain.Direction selection & fail-closed
pick_underlying_rate_bytesis the v7 analogue ofpick_rate_bytes: it picksunderlying_rate_quote_to_base/underlying_rate_base_to_quoteby the same input/output orientation and inverts the same way. It fails closed on the all-zero "not carried" sentinel (a producer predating theunderlying_rate_*fields, or a misconfigured pair) rather than signing a garbage mark — unlike v6's NAV-ratio zero, which is a legitimate "no assertion" sentinel the strategy may accept, a zero underlying price is never usable.The underlying rate is carried from
PriceFrameinto the cachedQuoteso v7 signs off the same observation as the rest of the context.Dependency pin
Re-pins
st0x-pricing-typesfromtag = "v0.6.0"torev = 7794ed474dd032a927c5b51a8b32c28259f4eb82— the head of st0x.pricing-types #4 (branchfeat/underlying-price), which added the directionalunderlying_rate_*fields toPriceFrame/Quote. Re-pin totag = "v0.7.0"once #4 merges and is tagged (noted in theCargo.tomlcomment).v6 left as-is
v6 (ratio-signing) is kept, unchanged, still served on
/context/v6. v7 is an additive new version per the repo's convention (every earlier version stays served); nothing consuming v6 is touched by this PR.Tests
PriceFrame→Quotebit-for-bitLocal gate
nix develop -c oracle-rs-test✅ ·nix develop -c oracle-rs-static✅ · rainix pre-commit ✅. (cargo-audit fails pre-existingly on main — crossbeam-epoch/ruint — not from this change.)🤖 Generated with Claude Code
https://claude.ai/code/session_01TQ3QV1QrwmaS7ACSf7cds7
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.