navi: resolve oracle price push from config API instead of hardcoded ids - #92
Conversation
NAVI is upgrading lending_core + oracle for Pyth's Sui redeployment, which
retires oracle_pro::update_single_price_v2 in favour of _v3 (arg 5 moves from
the legacy PriceInfoObject to one from the new Pyth package, 0x55300367...).
Rather than hardcode the new ids and hand-cut over at their upgrade window,
delegate the price push to @naviprotocol/lending, which resolves the oracle
package, entry function, Pyth/Wormhole state and per-feed price info objects
from open-api.naviprotocol.io/api/navi/config at runtime.
updateSingleTokenPrice now takes only (tx, feedId) and looks the feed up by
NAVI feedId. Matching on coinType would be unsafe: the config returns
fully-padded types (0x0000..0002::sui::SUI), so a '0x2::sui::SUI' compare
silently misses.
Bump @naviprotocol/lending 2.0.3 -> 2.0.7. 2.0.3 hardcodes
update_single_price_v2 and never reads updateFunction/hermesEndpoint, so it
would pair the new package id with the retired function name once NAVI flips
env=prod. 2.0.7 reads both, so the cutover needs no further code change --
config is cached in-process for 5 min, so a running process picks it up
within that window.
Call updatePythPriceFeeds explicitly rather than using
updateOraclePricesPTB's updatePythPriceFeeds flag. That flag gates on a stale
check reading content.fields.price_info.price_feed.price, but the object nests
a `fields` wrapper at each level, so parsing always fails, the stale list is
always empty and no VAA is ever posted. Posting unconditionally preserves the
previous behaviour instead of silently depending on NAVI's keepers.
Drop the now-dead hardcoded ids, none of which are re-exported from
src/index.ts and so are not public API:
- NAVI_CONFIG.ORACLE_PRO_PACKAGE_ID (was a direct move-call target)
- PYTH_STATE_ID / WORMHOLE_STATE_ID
- pythPriceInfo on all 21 PRICE_FEED entries (feedId is still used)
- the @pythnetwork/pyth-sui-js direct dependency; it stays in the tree
transitively via @alphafi/alphalend-sdk's aggregator deps
Drop src/naviprotocol-lending.d.ts: it worked around NAVI shipping
extensionless ESM re-exports that would not resolve under NodeNext. 2.0.7
ships a proper exports map with types, so tsc resolves the real
OraclePriceFeed types and the hand-written stub is no longer needed.
Blockchain.pythSuiClient is kept -- it is still used by the rebalanceCap,
slushAdmin and alphaVault helpers -- but its comments no longer claim it
exists for SuiPythClient.
Verified against mainnet: Lending USDC deposit, Looping SUI-VSUI deposit and
Navi USDC withdrawMax all dry-run successfully, targeting
update_single_price_v2 at 0x203728f4... as resolved from env=prod, with the
Pyth VAA posted through 0x04e20ddf... tsc --noEmit and eslint src/ are clean.
|
Updated for ✅ 1. Pyth reads routed through our client — verified
Worth recording why this needed checking beyond "it compiles": NAVI's provider type is ✅ 2. Feed coverage + optional-field guard — verified against live configThe guard is in at On the coverage question I raised: I fetched Note for later: this coverage now depends on a remote document, so a feed NAVI retires becomes a runtime throw for that pool rather than a build break. The new error messages make that diagnosable, which is the right trade — but it's worth knowing that adding a pool means checking 🟢 3. Still open — duplicate VAA post per transaction (unchanged, optional)Looping calls 🟢 4. Still open — unused import
🟢 5. Still open — PR descriptionThe body still describes the Also unchanged from the last pass: the mainnet dry-run evidence in the body predates Approving on the strength of findings 1 and 2 being verified fixed. Items 3–5 are advisory and don't gate merge. Approvals: 1/2 — the push dismissed the earlier approval, so this needs one more before merge. |
updateSingleTokenPrice passed no options to updatePythPriceFeeds / updateOraclePricesPTB, so NAVI's module-level default client served the SuiPythClient object reads on every deposit and withdraw — the public mainnet fullnode, the traffic #91 moved off public endpoints. Pass context.blockchain.suiGrpcClient to both. Guard pythPriceFeedId / pythPriceInfoObject, which NAVI treats as optional: the latter reaches tx.object() as arg 5 of oracle_pro::update_single_price_v3, so a supra/switchboard-only feed would abort on tx.object('') instead of naming the feed. Drop the DMC PRICE_FEED entry — the only one of our 21 absent from NAVI's live oracle.feeds, with no Navi pool and no reference in src/ outside the map. The other 20 match byte-identically and all carry Pyth data.
jangid
left a comment
There was a problem hiding this comment.
operate.md: clean at 15f0b5a — CI green. Both prior blocking findings verified fixed: Pyth reads now go through our client (checked that SuiGrpcClient.core actually satisfies NAVI's getCoreProvider probe at runtime, since the provider type is fully Partial and gives no compile-time guarantee), and all 20 remaining feedIds verified byte-identical against the live env=prod oracle.feeds with populated Pyth fields — DMC correctly removed as the only absentee. Non-blocking notes in the summary comment: duplicate VAA post per looping tx, an unused import in scripts/testRun.ts, and a stale PR description. Approvals: 1/2 — the last push dismissed the earlier approval, so this needs one more before merge.
NAVI is upgrading lending_core + oracle for Pyth's Sui redeployment, which retires oracle_pro::update_single_price_v2 in favour of _v3 (arg 5 moves from the legacy PriceInfoObject to one from the new Pyth package, 0x55300367...). Rather than hardcode the new ids and hand-cut over at their upgrade window, delegate the price push to @naviprotocol/lending, which resolves the oracle package, entry function, Pyth/Wormhole state and per-feed price info objects from open-api.naviprotocol.io/api/navi/config at runtime.
updateSingleTokenPrice now takes only (tx, feedId) and looks the feed up by NAVI feedId. Matching on coinType would be unsafe: the config returns fully-padded types (0x0000..0002::sui::SUI), so a '0x2::sui::SUI' compare silently misses.
Bump @naviprotocol/lending 2.0.3 -> 2.0.7. 2.0.3 hardcodes update_single_price_v2 and never reads updateFunction/hermesEndpoint, so it would pair the new package id with the retired function name once NAVI flips env=prod. 2.0.7 reads both, so the cutover needs no further code change -- config is cached in-process for 5 min, so a running process picks it up within that window.
Call updatePythPriceFeeds explicitly rather than using updateOraclePricesPTB's updatePythPriceFeeds flag. That flag gates on a stale check reading content.fields.price_info.price_feed.price, but the object nests a
fieldswrapper at each level, so parsing always fails, the stale list is always empty and no VAA is ever posted. Posting unconditionally preserves the previous behaviour instead of silently depending on NAVI's keepers.Drop the now-dead hardcoded ids, none of which are re-exported from src/index.ts and so are not public API:
Drop src/naviprotocol-lending.d.ts: it worked around NAVI shipping extensionless ESM re-exports that would not resolve under NodeNext. 2.0.7 ships a proper exports map with types, so tsc resolves the real OraclePriceFeed types and the hand-written stub is no longer needed.
Blockchain.pythSuiClient is kept -- it is still used by the rebalanceCap, slushAdmin and alphaVault helpers -- but its comments no longer claim it exists for SuiPythClient.
Verified against mainnet: Lending USDC deposit, Looping SUI-VSUI deposit and Navi USDC withdrawMax all dry-run successfully, targeting update_single_price_v2 at 0x203728f4... as resolved from env=prod, with the Pyth VAA posted through 0x04e20ddf... tsc --noEmit and eslint src/ are clean.