feat: Versioned Registry Router + Upgradeable Proxies for All Core Contracts#310
Open
feat: Versioned Registry Router + Upgradeable Proxies for All Core Contracts#310
Conversation
- Wire core contracts and local deploy to the registry router - Add registry deploy scripts, tests, and spec for the router - Mine stats witnesses in tests; remove checked-in fixture JSON
Convert all core contract deployments (PostageStamp, PriceOracle, StakeRegistry, Redistribution) from direct deploys to TransparentUpgradeableProxy + DefaultProxyAdmin + initialize() across local, main, test, and tenderly networks. Add VersionedRegistryRouter deploy script to all networks that registers all 4 proxies and their v1.0.0 releases with codehash verification. Update role scripts to use keccak256 hashes instead of read() calls to avoid TransparentUpgradeableProxy admin-cannot-fallback errors. Remove superseded deploy/registry/ directory.
Security and correctness fixes for the new proxy registry / router: - Gate forwardUnchecked behind ROUTER_ADMIN_ROLE so it no longer bypasses the selector allowlist for arbitrary callers. - Reject zero codehash in registerRelease so verifyProxy can't be silently disabled. - Validate registered proxies are actually owned by this router's ProxyAdmin. - Add deprecateProxy + ProxyDeprecated event; verifyProxy now rejects deprecated proxies and verifyAllProxies skips them instead of reverting. - Reject calldata < 4 bytes in both forward paths instead of panicking. - Add explicit ZeroAddress check on the constructor's _proxyAdmin arg and a SelectorRouted event for setRoutedSelector. Multisig handover (deploy/main/012): - Grant REGISTRAR_ROLE / DEPRECATOR_ROLE / ROUTER_ADMIN_ROLE to the multisig and renounce them (and DEFAULT_ADMIN_ROLE) from the deployer EOA so the multisig is the sole authority on the router. Tooling and dead-code cleanup: - Restore working solhint config (extends solhint:recommended; the removed solhint:default preset broke the linter). - Drop unused imports/vars and dead scaffolding in scripts/mine-stats-witnesses.ts and deploy/local/011. - Prettier-format remaining files touched on this branch. - Expand VersionedRegistryRouter tests to cover the new behaviour (proxy admin mismatch, deprecateProxy, calldata length, zero codehash rejection, forwardUnchecked role gating, selector disable). All 225 tests pass.
The .ts source was formatted in dad1e86 but the compiled .js sibling (loaded by worker_threads at runtime) was missed; CI's prettier --check runs against both.
It's the CommonJS sibling of mine-worker.ts, loaded directly by worker_threads at runtime, so the require() calls flagged by @typescript-eslint/no-var-requires are intentional and can't be rewritten as ESM imports without breaking the worker.
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
This PR introduces a Versioned Registry + Router architecture for upgradeable proxy systems in the Swarm storage incentives contracts. The core idea: Bee nodes should not automatically trust new proxy implementations. Instead, they verify
(version → implementation)mappings on-chain before interacting with the system.What changed
PostageStamp,PriceOracle,StakeRegistry,Redistribution) are now deployed behind OpenZeppelinTransparentUpgradeableProxywith a sharedDefaultProxyAdmin, across all networks (local, main, test, tenderly)VersionedRegistryRoutercontract (src/VersionedRegistryRouter.sol) — a single contract that combines:version → implementationmappings with codehash, semver, and deprecation supportverifyAllProxies()batch verificationinitialize()instead of constructors, deploy the registry router, register all proxies, and register v1.0.0 releases with codehash verificationVersionedRegistryRoutercovering all registry, router, role, invariant, and end-to-end scenariosHow it works
Security model:
ProxyAdminownerRoles:
REGISTRAR_ROLE— can register new releasesDEPRECATOR_ROLE— can deprecate releasesROUTER_ADMIN_ROLE— can register proxies and configure selector routingDEFAULT_ADMIN_ROLE— can manage all rolesKey invariants:
Contract changes
All 4 core Solidity contracts were made proxy-compatible:
initialize()functions (using OZInitializable)immutablestate variables converted to regular storage_disableInitializers()in constructor to prevent implementation initializationDeploy pipeline (consistent across all networks)
Test improvements
worker_threadsacross all CPU cores (~3 min vs ~16 min per trial)010_deploy_cluster.tsduring testsCleanup
deploy/registry/directory (superseded by integrated pipeline)keccak256('ROLE_NAME')instead ofread()calls to avoidTransparentUpgradeableProxy: admin cannot fallback to proxy targeterrorsTest plan
npx hardhat test)