Skip to content

feat(proxy-oracle): standardize contract self-upgrade (ENG-481)#519

Merged
peer2f00l merged 11 commits into
devfrom
feature/eng-481-upgrade-methods-support-upgrading-to-a-global-contract-by
Jul 22, 2026
Merged

feat(proxy-oracle): standardize contract self-upgrade (ENG-481)#519
peer2f00l merged 11 commits into
devfrom
feature/eng-481-upgrade-methods-support-upgrading-to-a-global-contract-by

Conversation

@peer2f00l

@peer2f00l peer2f00l commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Standardizes NEAR contract self-upgrade across the proxy-oracle, its governance contract, and the pyth-lazer adapter.

What

  • UpgradeSource + deploy_and_migrate primitive (common/src/upgrade.rs): one shared way to atomically deploy new code and run migrate in a single receipt (a failed migration reverts the deploy). Two sources — Code (raw blob) and GlobalHash (immutable, content-addressed global contract). Global-by-account-id is deliberately excluded: it is a live delegation to the publisher that would bypass governance and brick versioned state.
  • Wire/borsh stability: Code is untagged in JSON (bare base64, matching the pre-UpgradeSource wire); borsh discriminants are pinned explicitly (use_discriminant) so persisted governance proposals stay stable across future variants.
  • Governance SelfUpgrade action + self_upgrade TTL on the proxy-oracle governance contract, and a v0→v1 versioned-state migration that reshapes pending AdminUpgrade proposal bodies into the new Operation layout.
  • Framework migrate guard (impl_versioned_state!): stored-vs-target version — never migrate_args — decides whether to migrate, and a post-run re-assert makes a multi-version-skip deploy revert atomically instead of stranding state.
  • Events: proposal events emit a minimal {id, kind} (was the full proposal, incl. the wasm blob — over the 16KB log limit); pyth-lazer's Upgraded emits a bounded UpgradeSummary and is honestly framed as scheduled, not completed.
  • Manager CLI: admin-upgrade / self-upgrade proposal builders sharing a typed UpgradeArgs.

Testing

  • Unit coverage for the untagged/tagged JSON round-trips, golden borsh discriminant bytes, the v0→v1 migration (ttls + pending-proposal reshape), and the migrate no-op/guard decision.
  • Sandbox upgrade_ordering test: upgrades both contracts from their real pinned mainnet blobs to this branch, in both orders, seeding a real pending proposal so the on-chain reshape is exercised, and probing each upgraded contract with a domain view — proving no bricking.

Adversarial review ran to zero findings; /simplify applied.


This change is Reviewable

peer2f00l and others added 7 commits July 22, 2026 10:19
Extend the self-upgrade path across contracts to accept a source enum —
raw wasm blob, global contract by code hash, or by account id — with an
atomic deploy-then-migrate. Add a governance SelfUpgrade operation and give
the proxy-oracle governance contract versioned state + a v0->v1 migration.

- UpgradeSource + deploy_and_migrate helper in templar-common. `Code` is
  untagged in JSON (a bare base64 string) and the governance->oracle wire
  key stays `code`, so raw-blob admin_upgrade is compatible across contract
  versions and order-independent.
- proxy-oracle & pyth-lazer admin_upgrade take an UpgradeSource.
- Governance: new SelfUpgrade operation (own TTL, Admin role, empty-code
  validation, local self-deploy dispatch); versioned_state + a v0->v1
  migration that also converts pending proposal bodies to the new layout.
- Framework migrate() no-ops on a same-version refresh, decided by
  needs_migration() (never the caller's args), so a required migration can
  never be skipped.
- Governance lifecycle events now carry {id, kind} rather than the full
  proposal, whose payload (an AdminUpgrade/SelfUpgrade wasm blob) otherwise
  exceeds NEAR's 16KB per-log limit.
- pyth-lazer Upgraded event: structured UpgradeSummary + optional
  migrate_args (v2.0.0).
- Manager: --code-file | --global-hash | --global-account-id, plus a
  self-upgrade subcommand; typed proposal tests.
- Both-orders key-driven upgrade sandbox test against pinned mainnet blobs
  (proxy-oracle 0.3.0 / proxy-governance 0.1.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…e-methods-support-upgrading-to-a-global-contract-by
Post-review cleanup from an adversarial correctness review and a /simplify
pass:

- Migration: panic on a >u32 proposal id (mirroring the contract's overflow
  behavior) instead of silently dropping the proposal; correct a stale
  test comment about sandbox migrate() coverage.
- Manager: drop hand-rolled parse_global_hash; Base58CryptoHash's FromStr
  is clap's default value parser.
- Sandbox test-common: reuse the shared test_signer (cached Arc<Signer>)
  and pin TEST_FINALITY_POLICY on reads/writes, matching the oracle test
  common; drop the dead `call` helper.
- upgrade_ordering: collapse deploy_init/deploy_migrate into one helper and
  run the two independent setup deploys concurrently.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Address review-bot findings on the admin_upgrade event:

- The deploy+migrate runs in the returned Promise, a separate receipt from
  the one that emits the event, so the log is committed even if that receipt
  reverts. The prior "one atomic receipt" comment was wrong. Reframe the
  event (and its doc) as recording the *scheduled* upgrade, not completion.
- migrate_args was logged in full (base64), an unbounded payload that could
  exceed NEAR's 16KB per-log limit and abort the receipt — the same class of
  bug fixed for the governance events. Replace it with a bounded `migrated`
  flag (also drops the migrate_args clone).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Ruthless /simplify pass over the change's comments: cut lines that restated
the code, narrated a sequence the code already shows, or carried
design-rationale that belongs in a commit/PR. Kept only invariants and
non-obvious "why" (borsh-layout notes, the migrate decision guarantee, the
untagged-JSON ordering, the drop-before-prefix-reuse footgun, the "event
records scheduling not completion" semantics).

Behavior and public API unchanged; comments only.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
`UpgradeSource::GlobalAccountId` was a live delegation to the publisher
account: a later republish there would swap the contract's code with no
proposal, timelock, role check, or `migrate` — bypassing governance and
bricking versioned state. Remove it; keep only `Code` (raw blob) and
`GlobalHash` (immutable, content-addressed).

Pin the persisted borsh tags with explicit discriminants forwarded to the
derive (`borsh(use_discriminant = true)` + `#[repr(u8)]`, `Code = 0`,
`GlobalHash = 1`). `Code` stays declared last for serde's untagged rule, but
its borsh tag no longer tracks declaration order — a future variant takes its
own discriminant without disturbing stored proposals. A golden-byte test locks
the format.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…igrate

Address adversarial-review findings on the upgrade work:

- versioned_state: after `Migrator::run`, re-assert `!needs_migration()` so a
  deploy more than one version ahead of stored reverts atomically instead of
  returning success with state stranded between versions.
- upgrade_ordering: seed a pending `AdminUpgrade` proposal on the old gov before
  the v0→v1 migrate, then assert the migrated `Proposal<Operation>` reshaped its
  raw code into `UpgradeSource::Code` — so the on-chain proposal-body reshape is
  actually exercised, not an empty map. Probe each upgraded contract with a
  domain view (`own_get_owner`) to prove it still answers. Build the seed/expect
  values from the typed `Operation`, not `json!`.
- Trim two comments that restated the docs they pointed at.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f5230c85-e8fa-45c8-87b2-37a87439102d

📥 Commits

Reviewing files that changed from the base of the PR and between 46507e6 and 25eeb21.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • contract/pyth-lazer/contract/Cargo.toml
  • contract/pyth-lazer/contract/tests/test.rs

📝 Walkthrough

Summary

  • Introduce shared NEAR upgrade primitives in common::upgrade: UpgradeSource (raw WASM Code vs immutable global GlobalHash), UpgradeSummary, and a standardized deploy_and_migrate that atomically binds/deploys and then calls the pinned "migrate" entrypoint with migration args and gas.
  • Standardize contract self-upgrades:
    • Proxy-oracle governance: add SelfUpgrade operation with UpgradeSource-typed upgrade code, TTL support, empty-code validation, updated role checks, and receipt/event behavior changes to stay within log limits.
    • Proxy-oracle contracts: switch admin_upgrade to accept UpgradeSource and use deploy_and_migrate.
    • Pyth-lazer adapter: switch admin_upgrade to UpgradeSource + deploy_and_migrate, and update NEP-297 Upgraded event to log UpgradeSummary (scheduled upgrade initiation) with a new event version.
  • Add governance state versioning and migration:
    • Move governance storage into VersionedState and implement a v0→v1 migration for pending proposals (including rewriting legacy AdminUpgrade raw bytes into UpgradeSource::Code and defaulting self_upgrade TTL from legacy admin TTL).
    • Migration execution is guarded to only run when needed and to verify migration completion (prevents leaving contracts between versions).
  • Update tooling/tests:
    • Manager CLI: typed proposal builders for both AdminUpgrade and SelfUpgrade, with exactly-one upgrade source input (WASM path or global hash) plus optional migrate-args file.
    • Sandbox fixtures/pinned WASM blobs for cross-version testing; self_upgrade TTL set in test TTL helpers.
    • Tests cover serialization (JSON/Borsh + pinned discriminants), empty-code rejection, receipt ordering/action selection (DeployContract vs UseGlobalContract), correct migrate args/deposit/gas, v0→v1 migration behavior, and both upgrade deployment orders via an end-to-end “upgrade ordering” suite.

Review focus

  • Atomicity / safety of deploy_and_migrate: ensure deploy/bind and migrate are coupled so migration failure can’t leave the contract in an inconsistent “between versions” state.
  • Serialization compatibility: verify JSON dual representation and Borsh discriminant stability for UpgradeSource/events so existing deployed state and off-chain tooling remain compatible.
  • Migration guard correctness (version “needs” logic + completion verification): confirm the “no migration needed => migration args must be empty” behavior can’t be bypassed and that completion checks are comprehensive.
  • Governance security: validate authorization and TTL enforcement for both AdminUpgrade and SelfUpgrade, including role resolution (SelfUpgrade treated as admin) and the correctness of self_upgrade defaulting during v0→v1.
  • Upgrade source handling: ensure GlobalHash upgrades always resolve through UseGlobalContract and cannot be substituted to bypass intended governance controls.
  • Event/log constraints: confirm event schema/version updates match consumers and that logged data stays compact (using UpgradeSummary) to avoid NEAR log-limit issues.
  • Critical test assertions to inspect for correctness: receipt action ordering, zero deposit, exact prepaid gas for migrate, and migration arg pass-through for both upgrade source variants.
  • If you use automated vulnerability checklists, review these changes against common upgrade-related patterns (malformed migration inputs, authorization gaps, and upgrade atomicity) as indexed in repositories like kadenzipfel/smart-contract-vulnerabilities.

Walkthrough

This PR adds shared upgrade sources for raw WASM and global contract hashes, deploy-and-migrate execution, governance self-upgrades, versioned governance-state migration, compact event payloads, CLI support, and sandbox coverage.

Changes

Upgrade and governance modernization

Layer / File(s) Summary
Shared upgrade primitives
common/src/lib.rs, common/src/upgrade.rs, common/src/versioned_state/macros.rs
Adds serializable upgrade sources, hash-only summaries, deploy-and-migrate execution, stable Borsh tags, and guarded migration handling.
Governance operations and state migration
contract/proxy-oracle/near/governance-common/src/*, contract/proxy-oracle/near/governance-contract/src/*
Adds SelfUpgrade, shared validation and TTL configuration, compact lifecycle events, versioned state storage, and v0-to-v1 conversion.
Proxy-oracle upgrade execution and sandbox coverage
contract/proxy-oracle/near/common/*, contract/proxy-oracle/near/contract/*, gateway/testing/*, justfile
Routes upgrades through the shared flow and adds receipt, migration-ordering, sandbox, and pinned-WASM tests.
Pyth Lazer upgrade integration
contract/pyth-lazer/contract/*
Accepts structured upgrade sources and emits version 2.0.0 upgrade events containing compact upgrade summaries.
Governance upgrade CLI and typed tests
tools/manager/src/commands/proxy_oracle/governance/*, tools/manager/src/tests/proxy_oracle.rs
Supports WASM or global-hash inputs for admin and self-upgrades and validates typed operation output.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/eng-481-upgrade-methods-support-upgrading-to-a-global-contract-by

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • LINEAR integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contract/proxy-oracle/near/contract/tests/proxy_oracle.rs`:
- Around line 159-195: Strengthen the migrate action assertions in
admin_upgrade_from_global_hash_uses_global_contract_then_migrates by also
verifying that args equal the constructed migrate_args value and
attached_deposit is zero, matching
admin_upgrade_creates_one_self_receipt_with_deploy_then_migrate while preserving
the existing method and gas checks.

In `@contract/proxy-oracle/near/governance-contract/src/lib.rs`:
- Around line 293-296: Update the self-upgrade branch for Operation::SelfUpgrade
so the receipt returned by code.deploy_and_migrate is observed rather than
silently detached. Attach the contract’s established success/failure outcome
handling or alert mechanism, ensuring migration failures are surfaced while
preserving the existing deploy-and-migrate behavior.

In `@contract/pyth-lazer/contract/src/lib.rs`:
- Around line 500-510: Update admin_upgrade to call UpgradeSource::is_empty_code
before emitting PythLazerEvent::Upgraded or scheduling deploy_and_migrate, and
fail immediately when it reports an empty code blob. Preserve the existing
authorization, event, and deployment behavior for non-empty upgrade sources.

In `@contract/pyth-lazer/contract/tests/test.rs`:
- Around line 1042-1062: Extend admin_upgrade_emits_upgraded to parameterize the
UpgradeSource input and add an #[case] using UpgradeSource::GlobalHash(...).
Assert the emitted event’s event["data"]["code"]["GlobalHash"] summary for that
case, while preserving the existing Code hash assertion and migration-flag
coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6069545f-0134-487b-a280-2b8a481982d2

📥 Commits

Reviewing files that changed from the base of the PR and between 5e38202 and 0b72807.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • gateway/testing/src/wasm/proxy_governance_0_1_0.wasm is excluded by !**/*.wasm
  • gateway/testing/src/wasm/proxy_oracle_0_3_0.wasm is excluded by !**/*.wasm
📒 Files selected for processing (23)
  • .config/nextest.toml
  • common/src/lib.rs
  • common/src/upgrade.rs
  • common/src/versioned_state/macros.rs
  • contract/proxy-oracle/near/common/src/governance.rs
  • contract/proxy-oracle/near/contract/src/lib.rs
  • contract/proxy-oracle/near/contract/tests/proxy_oracle.rs
  • contract/proxy-oracle/near/governance-common/src/interface.rs
  • contract/proxy-oracle/near/governance-common/src/lib.rs
  • contract/proxy-oracle/near/governance-contract/Cargo.toml
  • contract/proxy-oracle/near/governance-contract/src/lib.rs
  • contract/proxy-oracle/near/governance-contract/src/state.rs
  • contract/proxy-oracle/near/governance-contract/src/tests.rs
  • contract/proxy-oracle/near/governance-contract/tests/common/mod.rs
  • contract/proxy-oracle/near/governance-contract/tests/upgrade_ordering.rs
  • contract/pyth-lazer/contract/src/events.rs
  • contract/pyth-lazer/contract/src/lib.rs
  • contract/pyth-lazer/contract/tests/test.rs
  • gateway/testing/src/sandbox.rs
  • gateway/testing/src/wasm.rs
  • tools/manager/src/commands/proxy_oracle/governance/create_proposal.rs
  • tools/manager/src/commands/proxy_oracle/governance/mod.rs
  • tools/manager/src/tests/proxy_oracle.rs

Comment thread contract/proxy-oracle/near/contract/tests/proxy_oracle.rs
Comment thread contract/proxy-oracle/near/governance-contract/src/lib.rs
Comment thread contract/pyth-lazer/contract/src/lib.rs
Comment thread contract/pyth-lazer/contract/tests/test.rs Outdated

@carrion256 carrion256 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Really cool actually. Couple Qs

Comment thread common/src/upgrade.rs
pub fn deploy_and_migrate(
self,
migrate_method: impl Into<String>,
migrate_args: Base64VecU8,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this type not limiting calldata by ~37% rather than raw byte array?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Depends. Vec<u8> is serialized as [1, 2, 3...]. However, we could use Borsh, though that hurts inspectability on block explorers. But the migration arguments are usually pretty simple (usually similar in size to the arguments sent to a new initialization constructor function call).

Comment thread common/src/upgrade.rs
GlobalHash(Base58CryptoHash) = 1,
/// A raw WASM blob deployed onto the account.
#[serde(untagged)]
Code(Base64VecU8) = 0,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this type not limiting calldata by ~37% rather than raw byte array? Ignoring *args, selecting base58 here reduces max contract blob.

Also, if i was being particularly anal about this I'd mention we dont even need to decode it at all and just take the first frame as the blob.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, this is, but the only realistic way to reduce the size would be to start serializing everything with Borsh.

This should not really matter though, because we should be moving to using global contract hashes for the vast majority of contract deployments and upgrades moving forward.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What is the issue with doing the proper way of just passing a Vec rather than intentionally limit every contract to ~63% size limit. I dont see every contract becoming a global contract just because, otherwise we shouldnt even support this type in the first place.

))
})
.collect();
drop(old_proposals);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why are we smarter than the borrow checker here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We want to run the Drop implementation here (we could equivalently call .flush(), I suppose) to actually clear the contract storage.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The borrow checker calls drop when the variable goes out of scope. Why do we need to try to call it?

- pyth-lazer admin_upgrade: reject an empty `Code` blob up front (mirrors the
  governance path's EmptyUpgradeCode guard) so no misleading Upgraded event is
  logged and no gas is spent on a doomed deploy; add a should_panic test.
- pyth-lazer test: cover the GlobalHash summary variant by cross-parameterizing
  admin_upgrade_emits_upgraded over source × migrate_args, asserting against the
  typed UpgradeSource::summary().
- proxy-oracle test: assert args and attached_deposit on the global-hash migrate
  receipt, matching the raw-blob sibling test.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

@coderabbitai coderabbitai 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.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contract/pyth-lazer/contract/tests/test.rs`:
- Around line 1054-1075: Extend admin_upgrade_emits_upgraded to inspect the
created receipt in addition to the NEP-297 event. Assert the receipt contains
the expected Code or GlobalHash action matching code, the migrate arguments
matching migrate_args, zero deposit, and GAS_FOR_MIGRATE, while preserving the
existing assertions for both UpgradeSource variants.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4c1a62ac-228c-4dd9-9d3d-b22653787c1e

📥 Commits

Reviewing files that changed from the base of the PR and between 0b72807 and ee4635e.

📒 Files selected for processing (3)
  • contract/proxy-oracle/near/contract/tests/proxy_oracle.rs
  • contract/pyth-lazer/contract/src/lib.rs
  • contract/pyth-lazer/contract/tests/test.rs

Comment thread contract/pyth-lazer/contract/tests/test.rs
peer2f00l and others added 2 commits July 22, 2026 16:52
admin_upgrade_emits_upgraded now inspects the scheduled receipt for both
UpgradeSource variants: DeployContract/UseGlobalContract as the first action, and
a `migrate` call carrying the exact args, zero deposit, and GAS_FOR_MIGRATE —
locking the adapter-specific deploy+migrate wiring, not just the NEP-297 event.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…e-methods-support-upgrading-to-a-global-contract-by

# Conflicts:
#	.config/nextest.toml

@coderabbitai coderabbitai 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.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
justfile (1)

22-26: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep explicit package selection aligned with the sandbox filter.

When --package is supplied, the default -p arguments are disabled, but the fixed sandbox_test_filter still only admits packages in sandbox_full_packages. Selecting another valid package can therefore run zero tests while appearing successful. Derive the filter from explicit packages, or reject packages outside the sandbox allowlist.

Also applies to: 79-84, 106-115

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@justfile` around lines 22 - 26, Align the explicit package-selection path
with sandbox_test_filter so --package selections outside sandbox_full_packages
are not silently filtered to zero tests. Update the relevant package
argument/filter construction near sandbox_test_filter and its other usages to
derive the sandbox filter from the explicitly selected packages, or reject
selections outside the sandbox allowlist while preserving current defaults.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contract/pyth-lazer/contract/tests/test.rs`:
- Around line 1084-1088: Strengthen the assertions in the UpgradeSource match
test: for UpgradeSource::Code, destructure MockAction::DeployContract and
compare its payload with the source code bytes; for UpgradeSource::GlobalHash,
destructure MockAction::UseGlobalContract and compare its hash with the source
value. Preserve the existing action-variant checks while validating the
forwarded payloads.

---

Outside diff comments:
In `@justfile`:
- Around line 22-26: Align the explicit package-selection path with
sandbox_test_filter so --package selections outside sandbox_full_packages are
not silently filtered to zero tests. Update the relevant package argument/filter
construction near sandbox_test_filter and its other usages to derive the sandbox
filter from the explicitly selected packages, or reject selections outside the
sandbox allowlist while preserving current defaults.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d440936a-20b3-415a-8ddc-245f054fb0a3

📥 Commits

Reviewing files that changed from the base of the PR and between ee4635e and 46507e6.

📒 Files selected for processing (2)
  • contract/pyth-lazer/contract/tests/test.rs
  • justfile

Comment thread contract/pyth-lazer/contract/tests/test.rs
…ction

Destructure the deploy action and check the forwarded payload: for `Code`,
compare `DeployContract`'s bytes to the source blob; for `GlobalHash`, compare
`UseGlobalContract`'s `GlobalContractIdentifier::CodeHash` to the source hash. A
regression forwarding a different source to `deploy_and_migrate` now fails. Adds
near-primitives (already the workspace-pinned 0.34.7) as a dev-dep to name the
identifier type.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25eeb21b85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread common/src/versioned_state/macros.rs
@peer2f00l

Copy link
Copy Markdown
Collaborator Author

This follow up should be resolved before deploying new contract versions: https://linear.app/templar-protocol/issue/ENG-517/migrate-methods-support-running-n-consecutive-migrations-in-one

@peer2f00l
peer2f00l merged commit 8ec04f2 into dev Jul 22, 2026
23 of 24 checks passed
@peer2f00l
peer2f00l deleted the feature/eng-481-upgrade-methods-support-upgrading-to-a-global-contract-by branch July 22, 2026 16:47
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.

2 participants