feat(soroban): owner-gated upgradeability for PredicateRegistry - #66
Merged
alex-predicate merged 4 commits intoJul 20, 2026
Merged
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
penDerGraft
approved these changes
Jul 20, 2026
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.
Summary
Makes the deployed
PredicateRegistrySoroban contract upgradeable in place using Soroban's native upgrade mechanism (update_current_contract_wasm) — same contract address, storage preserved, bytecode swapped. No proxy pattern needed.Scope is the registry only.
predicate-clientis a library linked into consumers, so there is nothing there to upgrade independently; consumer/token contracts are unchanged.Changes
upgrade(owner, new_wasm_hash)onPredicateRegistryContract, gated by the existingrequire_ownerhelper (owner check +require_auth). Non-owner calls revert withRegistryError::Unauthorized(v1.0.2 #1). Emits anupgradeevent with the new WASM hash, following the existing event convention. No new storage keys, no version counter (the ledger already records the WASM hash).test_upgrade_happy_path_preserves_storage): uploads the crate's own compiled WASM, upgrades to it, and asserts owner + a registered attester survive the swap — proving the upgrade path and storage preservation. Plustest_non_owner_cannot_upgradefor the auth gate.scripts/upgrade-registry.sh: builds →stellar contract upload→ invokesupgradeon an existing registry, mirroringdeploy-registry.sh.soroban-buildnow installs thewasm32v1-nonetarget and builds that artifact beforecargo test, because the self-upgrade testcontractimport!s it at compile time.Build-target note
Both the test and the ops script build with
stellar contract build/wasm32v1-none, notcargo build --target wasm32-unknown-unknown— the latter emits reference-types WASM that the Soroban host rejects at upload (reference-types not enabled).Upgrade discipline
Because storage survives the bytecode swap, future registry WASM must remain compatible with the existing storage schema (owner, pending owner, attesters, policies, spent UUIDs). Adding keys is safe; changing an existing key's type/meaning requires an explicit migration.
Testing
cargo test— 39 tests pass across the workspace (21 inpredicate-registry, including both new upgrade tests). Reviewed via subagent-driven review per task plus a whole-branch review; the one Critical found (CI missing the wasm32v1-none build) is fixed in this branch.🤖 Generated with Claude Code