paritytech / paritytech/dotns

[Feat]: Decide contract upgrade authority: governance (Root) or a wallet

Open
#238 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

P1 type: feature
Dominant language
Solidity
Stars
4
Forks
2
Avg merge
1d 18h
Merged PRs (30d)
24

Description

Component

Other

Priority

P1

Summary

Contract upgrades are authorised by _authorizeUpgrade, gated onlyOwner on every UUPS proxy, so a single owner key can replace any implementation and bypass every other control. Before mainnet we need to decide who holds upgrade authority. Two options below; the aim is to pick one and wire it consistently across all upgradeable contracts.

Proposal

Option 1: governance (Root), via originIsRoot().

Gate _authorizeUpgrade on ISystem(SYSTEM_ADDR).originIsRoot(). Only a Root-origin dispatch can upgrade, which on Polkadot Asset Hub means a passed OpenGov referendum. originIsRoot() (the pallet-revive System precompile) reads the transaction-level origin and holds through the UUPS delegatecall frame, unlike callerIsRoot(), which returns false from behind the proxy.

  • Decentralised: token holders decide, and there is no admin key.
  • Secure: nothing to steal or phish, and upgrades ride the Root referendum track with its confirmation period.
  • Cost: no unilateral hotfix. An urgent upgrade runs through a governance track, so we also want a short or emergency track for the worst case (see #205).
  • Robust to the Asset Hub Migration: whether OpenGov dispatches locally on Asset Hub or reaches us from the Relay as Root over XCM, the contract sees Root and the gate holds.

Option 2: wallet (keep onlyOwner).

Owner is an account, either an EOA or a multisig. This is today's model; the only change worth making is moving owner to a shared multisig.

  • Fast: an upgrade is a single transaction, no referendum.
  • Simple: no new precompile dependency, and no track to stand up.
  • Weaker: the owner keys are a standing target. A compromised key, or a coerced signer set, can replace any implementation and bypass every other control. A multisig raises the bar but is still a fixed keyholder set, not the token holders.

Recommendation. Option 1 for mainnet, since upgrade is the most dangerous power and it should have no single key behind it. Option 2 with a multisig is a reasonable interim on testnets, or until the Asset Hub Migration lands OpenGov on Polkadot Asset Hub.

Acceptance criteria
  • Upgrade authority decided and recorded.
  • _authorizeUpgrade updated to the chosen authority across every UUPS proxy.
  • If governance: gated on originIsRoot(), with a paired fork test proving a Root dispatch can upgrade and a non-root caller cannot.
  • If wallet: owner set to the agreed account or multisig and documented in DEPLOYMENTS.md.
  • Emergency-upgrade path decided and linked (#205).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by searching all upgradeable contracts for _authorizeUpgrade and reviewing the UUPS proxy setup; also read DEPLOYMENTS.md if the wallet option is chosen. The work is done when one authority is decided and applied consistently, the corresponding Root or wallet fork test passes, and the emergency-upgrade decision is linked to #205.

Written by the indexing model from the issue text.

Assessment

Tech stack
solidity
Domain
authorization, blockchain
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.