feat(near): add SetWormhole governance action to Pyth receiver - #3844
feat(near): add SetWormhole governance action to Pyth receiver#3844jayantk wants to merge 1 commit into
Conversation
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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| 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), |
There was a problem hiding this comment.
🚩 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.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Implements the receiver portion of the NEAR Pyth Core Upgrade ([[i-thbrscdl]]): a new
SetWormholegovernance 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: newGovernanceAction::SetWormhole { new_wormhole: AccountId }variant. Added as the last variant so it takes the next free discriminant (6); all existing discriminants, thePTGMmagic, module, target-chain and governance-sequence replay protections are byte-identical. Updated thenomparser and the serializer (payload = the new WormholeAccountIdas its UTF-8 string). Handler mutatesself.wormholevia a newset_wormholesetter, on the same replay-protected path as the otherSet*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 —UpgradeContractthenSetWormhole— and the single-step case.receiver/Cargo.lock: reconciles a pre-existing mismatch (committed lock pinnedpythnet-sdk 2.3.1; the path crate is now3.0.0). Without this, the--lockedCI builds fail for any PR touchingtarget_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
GovernanceActiondiscriminants andPTGMmagic unchanged — only theSetWormholevariant added.update_price_feedsreceipt graph unchanged.Pythfield changes).Testing
Full contract gate (
workspace-test.sh) green:cargo build --release --target wasm32-unknown-unknown --locked,cargo near build reproducible-wasm(lib), andcargo test --locked→ 8 unit + 11 integration tests pass, including the newtest_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.mdpin, reproducible-wasm build, and rotation/3-of-5-quorum fixtures; then extend the e2e tests against the vendored bridge.