Skip to content

feat(near): add SetWormhole governance action to Pyth receiver - #3844

Open
jayantk wants to merge 1 commit into
mainfrom
hydra/i-thbrscdl/head
Open

feat(near): add SetWormhole governance action to Pyth receiver#3844
jayantk wants to merge 1 commit into
mainfrom
hydra/i-thbrscdl/head

Conversation

@jayantk

@jayantk jayantk commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the receiver portion of the NEAR Pyth Core Upgrade ([[i-thbrscdl]]): a new SetWormhole governance action that lets governance re-point the Pyth NEAR receiver at a different Wormhole core-bridge contract (e.g. a Pyth-owned bridge whose guardian set is the 5 Pyth Pro routers) without changing any existing public ABI or governance wire format.

This is PR-B's receiver change from the issue's suggested PR boundaries. The large, separable PR-A (vendor the Wormhole NEAR core bridge) and the vendored-bridge end-to-end tests (3/5 quorum accumulator update, guardian-set rotation) are escalated as a child issue, since vendoring an entire upstream contract is well over the ~500 LOC split threshold the issue calls out.

Changes

  • receiver/src/governance.rs: new GovernanceAction::SetWormhole { new_wormhole: AccountId } variant. Added as the last variant so it takes the next free discriminant (6); all existing discriminants, the PTGM magic, module, target-chain and governance-sequence replay protections are byte-identical. Updated the nom parser and the serializer (payload = the new Wormhole AccountId as its UTF-8 string). Handler mutates self.wormhole via a new set_wormhole setter, on the same replay-protected path as the other Set* actions.
  • receiver/tests/workspaces.rs: test_set_wormhole — swaps the receiver onto a second deployed Wormhole stub and asserts a price update verifies against the new address and lands in storage, then swaps onto an address with no contract and asserts subsequent updates are rejected (proves the swap is live). Plus unit tests for serialize/deserialize roundtrip and the handler.
  • target_chains/near/README.md: documents the two-step upgrade recipe — UpgradeContract then SetWormhole — and the single-step case.
  • receiver/Cargo.lock: reconciles a pre-existing mismatch (committed lock pinned pythnet-sdk 2.3.1; the path crate is now 3.0.0). Without this, the --locked CI builds fail for any PR touching target_chains/near/**. Purely the transitive fallout of that version bump (old borsh 0.10/ahash/proc-macro-error removed, borsh 1.5.7 added); no Cargo.toml / dependency additions.

Constraints honored

  • Receiver public function signatures unchanged.
  • Existing GovernanceAction discriminants and PTGM magic unchanged — only the SetWormhole variant added.
  • update_price_feeds receipt graph unchanged.
  • Storage layout forward-compatible (no Pyth field changes).

Testing

Full contract gate (workspace-test.sh) green: cargo build --release --target wasm32-unknown-unknown --locked, cargo near build reproducible-wasm (lib), and cargo test --locked8 unit + 11 integration tests pass, including the new test_set_wormhole.

Follow-up (escalated to child issue)

PR-A: vendor the Wormhole NEAR core bridge into target_chains/near/wormhole/ with 5-router guardian-set initialization, VENDOR.md pin, reproducible-wasm build, and rotation/3-of-5-quorum fixtures; then extend the e2e tests against the vendored bridge.


Open in Devin Review

Adds a new `SetWormhole { new_wormhole: AccountId }` governance action to
the NEAR Pyth receiver, letting governance re-point the receiver at a
different Wormhole core-bridge contract (e.g. a Pyth-owned bridge whose
guardian set is the Pyth Pro routers) without changing any existing ABI.

- New `GovernanceAction::SetWormhole` variant (next free discriminant, 6);
  existing discriminants and the PTGM/module/chain/sequence replay-protection
  path are unchanged. nom parser + serializer updated; payload is the new
  Wormhole AccountId as its UTF-8 string.
- Handler mutates `self.wormhole` via `set_wormhole`, sharing the same
  governance-sequence replay protection as the other actions.
- Unit tests: serialize/deserialize roundtrip + handler. Integration test
  (`test_set_wormhole`) swaps the receiver onto a second Wormhole stub and
  asserts a price update lands against the new address, then onto a dead
  address and asserts updates are rejected — proving the live swap.
- README: documents the two-step upgrade recipe (UpgradeContract + SetWormhole).
- Cargo.lock: reconcile pre-existing pythnet-sdk 2.3.1 -> 3.0.0 mismatch so the
  `--locked` CI builds (workspace-test.sh, reproducible-wasm) pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api-reference Ready Ready Preview, Comment Jun 25, 2026 4:13pm
component-library Ready Ready Preview, Comment Jun 25, 2026 4:13pm
developer-hub Ready Ready Preview, Comment Jun 25, 2026 4:13pm
entropy-explorer Ready Ready Preview, Comment Jun 25, 2026 4:13pm
insights Error Error Jun 25, 2026 4:13pm
proposals Ready Ready Preview, Comment Jun 25, 2026 4:13pm
staking Ready Ready Preview, Comment Jun 25, 2026 4:13pm

Request Review

@devin-ai-integration devin-ai-integration Bot left a comment

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.

Devin Review found 1 potential issue.

Open in Devin Review

SetDataSources { data_sources } => self.set_sources(data_sources),
SetFee { base, expo } => self.set_update_fee(base, expo)?,
SetValidPeriod { valid_seconds } => self.set_valid_period(valid_seconds),
SetWormhole { new_wormhole } => self.set_wormhole(new_wormhole),

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.

🚩 SetWormhole allows Chain::Any target unlike UpgradeContract which restricts to Chain::Near

The UpgradeContract action explicitly restricts its target to Chain::Near (governance.rs:353-356) as a safety measure against accidental upgrades. The new SetWormhole action does not apply the same restriction (governance.rs:348), accepting both Chain::Near and Chain::Any. This is consistent with other configuration actions (SetDataSources, SetFee, SetValidPeriod) which also accept Chain::Any. However, SetWormhole is a NEAR-specific operation (the payload is a NEAR AccountId UTF-8 string), and setting the wormhole to an invalid address can permanently brick the contract (no further governance actions or price updates can be verified). The Stylus implementation uses a 20-byte EVM address for the same action ID 6, so a Chain::Any governance VAA would be parsed differently on each chain. This may be intentional — the governance operator must be careful — but adding a Chain::Near-only restriction (like UpgradeContract) would provide an extra safety layer.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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