Skip to content

chore(upgrades): Paseo v0.8.0 to v1.0.0 in-place upgrade campaign - #331

Merged
re-gius merged 25 commits into
dev/testnet-upgradesfrom
chore/paseo-v1.0.0-upgrade
Oct 5, 2026
Merged

re-gius merged 25 commits into
dev/testnet-upgradesfrom
chore/paseo-v1.0.0-upgrade

Conversation

@re-gius

@re-gius re-gius commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

Description

Prepares the in-place upgrade of Paseo Asset Hub Next from v0.8.0 to v1.0.0. Nothing is broadcast here; the steps run afterwards through the label console, per docs/PASEO-V100-RUNBOOK.md. No ownership rotation.

Step Upgrades
UpgradeRegistry DotnsRegistry (255-octet name-path bound via StringUtils)
UpgradePopRules PopRules (personhoodOf becomes popStatusOf, tier renames)
UpgradePopResolverAndController DotnsPopResolver then DotnsPopController, consecutive txs (each calls a function only its new counterpart has)
RedeployPopLens DotnsPopLens at a release-scoped CREATE3 salt (the default slot holds an old lens); rewires popLens + declares its codehash
DeclareRelease codehashes, then 1.0.0

Other changes:

  • Merges master, keeping the branch's retained storage
  • Removes the v0.8.0 campaign material
  • BaseDeployer: salt-taking _broadcastDeployCreate3. The store verification now ignores the metadata trailer, because v1.0.0 changes only store comments; without this, DeclareRelease reverts on Paseo.
  • Console: each upgrade step checks only the snapshots of the contracts it upgrades (SNAPSHOT_SUBJECTS).

Type

  • Bug fix
  • Feature
  • Breaking change
  • Documentation
  • Chore
  • Refactor
  • Security

Scope

  • Registration
  • Resolver
  • Store
  • Proof of Personhood
  • Deployment scripts
  • Tests

Related Issues

Upgrade to the v1.0.0 release; follows the v0.8.0 campaign

Fixes

Checklist

Code

  • [x Follows project style
  • forge build passes
  • forge test passes
  • No new compiler warnings

Testing

  • New tests added for changed behavior
  • Fuzz tests added where applicable
  • Invariant tests verified

Security

  • No new selfdestruct or delegatecall
  • Access control reviewed
  • No storage layout conflicts (for upgradeable contracts)

Documentation

  • NatSpec updated on changed interfaces
  • README updated if needed

Breaking Changes

  • No breaking changes
  • Breaking changes documented below

Breaking changes:

How to test

RPC_URL=https://eth-rpc-paseo-next.polkadot.io scripts/shell/verify-snapshots.sh
PASEO_FORK_RPC=https://eth-rpc-paseo-next.polkadot.io forge test --match-path 'test/fork/**'
forge test --match-path test/unit/upgrade/LayoutCompatibility.t.sol

Notes

re-gius and others added 21 commits September 21, 2026 11:09
The file named @waytwotall and @sphamjoli. @sphamjoli has read access and has
left the organisation, so they cannot approve a pull request, which left one
person able to satisfy a code-owner review on the whole repository.

That is about to matter. The "main" ruleset is active but its target list is
empty, so it currently matches no branches and master is unprotected. Once its
targets are set, every pull request needs a code-owner approval, and with the
old list that meant @waytwotall or nothing.

Replaces them with @re-gius and @GHkrishna, both of whom can approve. Two
owners rather than one, because a code owner cannot approve their own pull
request, so a single owner cannot merge anything they wrote.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The team outlives its membership: people joining and leaving @paritytech/dotns
is a team-settings change, and this file stops needing a pull request every
time that happens, which is exactly how it went stale last time.

Inert until the team is granted write on this repository: CODEOWNERS ignores
teams without access, so that grant lands before this merges.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Description

`.github/CODEOWNERS` named `@waytwotall` and `@sphamjoli`, which is
outdated behavior.

Now any member of the
[dotns](https://github.com/orgs/paritytech/teams/dotns) team can
approve.

## Type

- [x] Chore

## Scope

_None: repository configuration only._

## Related Issues

Precedes setting targets on the `main` ruleset, which is what actually
protects master.

## Fixes

A code-owner list that could not be satisfied once code-owner review is
enforced.

## Checklist

### Code

- [x] Follows project style
- [x] `forge build` passes
- [x] `forge test` passes
- [x] No new compiler warnings

### Testing

- [ ] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [x] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes

**Breaking changes:**

## How to test

Nothing to run: one line of repository configuration, no contract or
test changes.

## Notes

Merge this before adding targets to the `main` ruleset, while master is
still unprotected and this can land without needing the approval it
exists to make possible.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Pushed to master directly by mistake; it belongs in a reviewed PR.
This reverts commit 6bbd97d.
## Description

 Records what the two live testnets actually run.

- `paseo-assethub` is updated to the post-v0.8.0 in-place-upgrade state:
the store factory lives behind a proxy at `0x99605a92…71f6`, its beacons
moved with it, and the outgoing factory and beacons stay recorded under
`*Legacy` keys because the migrated stores remain on them (see #312).
- `previewnet` gets its first committed manifest, read from its chain.
It runs an unmodified v0.8.0 genesis, so every address equals
`deployments/expected.json`. A README explains the chain id shared with
`paseo-assethub` and the `*Legacy` convention.
- `release-metadata.mjs verify` learns two general rules: a `*Legacy`
manifest entry is a superseded deployment that holds no registry key by
design, and a key tolerated unset is also tolerated undeclared where an
older genesis set it.

## Type

- [ ] Bug fix
- [ ] Feature
- [ ] Breaking change
- [ ] Documentation
- [x] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [x] Deployment scripts
- [ ] Tests

## Related Issues

## Fixes

## Checklist

### Code

- [x] Follows project style
- [x] `forge build` passes
- [x] `forge test` passes
- [x] No new compiler warnings

### Testing

- [x] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [ ] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

**Breaking changes:**

## How to test

```bash
node scripts/js/release-metadata.mjs validate

node scripts/js/release-metadata.mjs verify --network paseo-assethub \
  --rpc https://eth-rpc-paseo-next.polkadot.io --tag v0.8.0

node scripts/js/release-metadata.mjs verify --network previewnet \
  --rpc https://previewnet.substrate.dev/eth-rpc --tag v0.8.0
```

Both verifies end with "matches the chain".

## Notes

Manifests are records of live networks; the Paseo one diverges from
expected.json where its history does (Legacy entries, a lens deployed
before the current set), and the previewnet one matches it exactly
## Description

Three low severity findings from the internal audit, grouped together.

**Subname paths now have a length limit.** `isNamePath` checked that
each dot separated segment was at most 63 octets but never checked the
path as a whole, so a caller could build an arbitrarily long
`parentLabel` out of legal segments. `setSubnodeOwner` stores the
resulting full name in the new owner's `LabelStore`, and that row cannot
be deleted, so the text sat there permanently and made every enumeration
that reads it back more expensive. The path is now capped at 255 octets,
which is the DNS wire format ceiling. A path over that limit reverts
with `ParentLabelMismatch`, same as a malformed one. Nothing live comes
close: real parent paths are one or two labels.

**CI now enforces the live manifest rule.** `CONTRIBUTING.md` says a
code PR must not edit `deployments/<network>/<chainId>.json`, because
those files are records of what is actually deployed and they ship
straight into the `deployments.json` release asset. The CREATE3 parity
gates compare `deployments/expected.json` instead, so nothing was
checking the live files. A new job in `release-metadata.yml` fails a PR
that touches one, unless the PR carries the `deployment-record` label,
which is what a real deploy uses.

**`setOwner` now mentions subnames.** The comment on `setOwner` warned
that a name sold directly keeps the seller's resolver pointer until the
buyer overwrites it. That is true for the node itself but not for
anything under it: a subname stores its own owner and `isAuthorised`
returns on that before it looks at the registrar, so the seller keeps
write access to every subname they created until the buyer reassigns
each one. Someone acting on the old wording would clean up the node and
think the name was clear. Added to both the implementation and the
interface.

## Type

- [x] Bug fix
- [ ] Feature
- [ ] Breaking change
- [x] Documentation
- [ ] Chore
- [ ] Refactor
- [x] Security

## Scope

- [x] Registration
- [ ] Resolver
- [x] Store
- [ ] Proof of Personhood
- [x] Deployment scripts
- [x] Tests

## Related Issues

Internal security audit, low severity findings.

## Fixes

## Checklist

### Code

- [x] Follows project style
- [ ] `forge build` passes
- [ ] `forge test` passes
- [ ] No new compiler warnings

### Testing

- [x] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [x] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [x] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

## How to test

```bash
forge test --mt test_accepts_a_path_at_the_ceiling
forge test --mt test_rejects_a_path_one_octet_over_the_ceiling
forge test --mt test_subnode_parent_path_over_the_octet_ceiling_is_rejected
```

## Notes
The length cap makes the injection cheaper to live with, it does not
close it. Anyone holding a node can still name someone else as a subnode
owner and push an undeletable row into their store. What changed is that
the row is now bounded at roughly 320 octets instead of being unbounded,
so the cost of reading it back is in the same range as a genuine row.
Closing it properly means one of three things( they are design decisions
though tbh): require the caller to be the subnode's new owner on the
persist branch, give `LabelStore` an owner callable removal, or bound
the scan in `DotnsPopLens` with a resumable cursor.

The `deployment-record` label has to exist in the repo before the new CI
job is useful, otherwise a legitimate deploy PR has no way through.

The audit also flagged that the release workflows hold deployment keys
with no environment gate. That one needs a GitHub environment set up
before the workflow change means anything, so it is not inc in this PR.

---------

Signed-off-by: GHkrishna <krishna@parity.io>
## Description

The genesis owner key `DOTNS_ADMIN_KEY` was a repository-level secret,
readable by any workflow on any branch, with a silent mnemonic fallback
deciding the owner when unset.

- Both publish jobs now run in the `releases` environment: reviewer
approval required, refs limited to `master` and `v[0-9]*` tags, key
stored as an environment secret.
- A pre-build step checks the key derives to the environment's declared
`DOTNS_ADMIN_ADDRESS`, so a mistyped key fails before a genesis is
built.
- The mnemonic fallback is removed from the genesis script: one explicit
key, or a loud failure.

Follow-up once merged: delete the repository-level `DOTNS_ADMIN_KEY` and
`DOTNS_ADMIN_MNEMONIC`, whose last consumers this PR removes.

## Type

- [ ] Bug fix
- [ ] Feature
- [ ] Breaking change
- [ ] Documentation
- [x] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [x] Deployment scripts
- [ ] Tests

## Related Issues

## Fixes

## Checklist

### Code

- [x] Follows project style
- [x] `forge build` passes
- [x] `forge test` passes
- [x] No new compiler warnings

### Testing

- [x] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [x] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [ ] No breaking changes
- [x] Breaking changes documented below

**Breaking changes:** a release run now requires the `releases`
environment to exist with `DOTNS_ADMIN_KEY` and `DOTNS_ADMIN_ADDRESS`
configured, and pauses for a reviewer approval. Building a genesis
locally with only `DOTNS_ADMIN_MNEMONIC` set no longer works; pass
`DOTNS_ADMIN_KEY`.
`workflow_dispatch` releases can only be started from master; a dispatch
from another branch stops at the environment gate.

## How to test

```bash
bash -n scripts/genesis/build-genesis.sh

# refuses without a key, with a message naming the one accepted credential
unset DOTNS_ADMIN_KEY DOTNS_ADMIN_MNEMONIC; bash scripts/genesis/build-genesis.sh release
```

The full gate is exercised by the next prerelease: the run must pause on
the releases environment, pass the address check, and build with the
fresh key.

## Notes

The environment itself (reviewers, ref patterns, secret, variable) has
already been configured.
## Description

Aligns the repository with the legal guidelines for open source
attribution.

- Every Parity-authored contract gains one line under its SPDX
identifier: `SPDX-FileCopyrightText: © 2026 Parity Technologies`. A
contract file travels alone through explorers and vendoring, and carried
a license identifier with no copyright holder to preserve;
`SPDX-FileCopyrightText` is the REUSE-standard field for this, so
coverage stays machine-checkable.
- Vendored third-party code keeps its own notices: `contracts/external/`
(authoritative SPDX headers) and `contracts/utils/Multicall3.sol`
(mds1/multicall3, MIT) carry no Parity line.
- A `NOTICE` file records the project copyright, the MIT license
pointer, and the third-party attributions; the README's license section
now points at it.

Comment-only for the contracts: bytecode, ABIs, and storage layouts are
unchanged.

## Type

- [ ] Bug fix
- [ ] Feature
- [ ] Breaking change
- [ ] Documentation
- [x] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [ ] Deployment scripts
- [ ] Tests

## Related Issues

## Fixes

## Checklist

### Code

- [x] Follows project style
- [x] `forge build` passes
- [x] `forge test` passes
- [x] No new compiler warnings

### Testing

- [ ] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [x] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

**Breaking changes:**

## How to test

```bash
grep -rL "SPDX-FileCopyrightText" contracts --include='*.sol' | grep -v external
```

Prints only `contracts/utils/Multicall3.sol`, the vendored file that
keeps its original authors' notice.

## Notes

The added lines change each file's compiler metadata hash and nothing
else. Release tooling strips metadata before comparing codehashes, so
codehashes.json and the deployed-bytecode checks are unaffected.
## Description
This PR fixes three problems with our GitHub Actions setup.
First, when you pushed several commits to an open PR, some checks kept
running for every old commit instead of stopping and only running for
the latest one. This was happening because four workflows (Format and
Lint, PR Title and Labels, Release Metadata, and the Genesis Extractor
Test) were missing a concurrency setting that every other workflow
already had. This PR adds that setting so a new push now cancels the
still running check from the previous commit

Second, our slowest checks (the test suite, the gas report, and the
coverage report) were doing a full cold Foundry build every single time,
even when nothing in the contracts had changed. This PR adds a cache for
Foundry's build output so unchanged code does not need to be recompiled
from scratch on every run.
While setting up that cache, we found a timing bug: the cache key was
being calculated before bun install runs, but bun install is what
actually re-downloads and patches our OpenZeppelin dependencies. So the
cache key was based on the wrong version of those files. This is fixed
by moving the cache step to run after bun install, so the key always
reflects what actually gets built.

Lastly, we noticed the Gas Report workflow was starting and stopping a
Docker container (the local RPC node used for fork tests) on every run,
even though the gas report command explicitly skips fork tests. That
container was never being used, so it has been removed. This saves time
on every single gas report run.

## Type

- [x] Bug fix
- [ ] Feature
- [ ] Breaking change
- [ ] Documentation
- [x] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [ ] Deployment scripts
- [x] Tests

## Related Issues

This came out of a general review of our CI setup.

## Fixes

## Checklist

### Code

- [x] Follows project style
- [x] `forge build` passes
- [x] `forge test` passes
- [x] No new compiler warnings

### Testing

- [ ] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [x] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

**Breaking changes:**
No

## How to test
This PR changes workflow behavior, so the best way to test it is to run
it.

## Notes

While reviewing this, a couple of smaller ideas came up that are
intentionally not part of this PR, flagging them for later:
- None of our workflows set a timeout-minutes limit on any job, so a
stuck run could sit there for hours (GitHub's default) and hold up its
concurrency group. Worth adding reasonable limits later.
- The Foundry cache key does not account for a future bump of the pinned
Foundry version in .github/actions/setup-foundry/action.yml. Worth
adding that file's hash to the cache key whenever that version is next
bumped.
- Below checks should be marked required in the repo setting:
  - Format & Lint (catches formatting or build issues)
  - PR Title (validates title format)
  - Secret Scan (catches leaked secrets)
  - File Validation (catches bad tracked files)
- Run Solidity Tests / Contract Tests (Unit + Fuzz) (core correctness
check, also fast)
  - Coverage (fails on threshold drops)
- Deploy Contracts and Verify artifacts (catches deploy address
regressions)

- Following not req:
- Run Solidity Tests / Contract Tests (Invariant): slowest check, mostly
re-covers what unit and fuzz already catch
  - Gas Report: informational diff only, never fails the job
- 4naly3er Analysis: always green by design, continue-on-error with no
fail step
  - Slither Analysis: same as 4naly3er, can't actually fail
  - Documentation: doc build health, not a correctness gate
- Release Metadata: path filtered, would get stuck pending on unrelated
PRs
  - Genesis Extractor Test: same path filtered issue as above

---------

Signed-off-by: GHkrishna <krishna@parity.io>
)

## Description
Releases now ship a DotNS genesis for Paseo Asset Hub Next V2 as well as
previewnet, so a wipe can boot with DotNS already deployed

- `dotns-genesis-testnet.json` (previewnet) and
`dotns-genesis-paseo.json` (Next V2), one build per TLD in `DOTNS_TLDS`
- New `dotns-genesis-addresses.json` asset: the address set those
genesis files carry, copied from `deployments/expected.json`
- The genesis builder clears the localhost manifest first, so a second
build in the same job starts clean
- Previewnet README said `.dot`, the chain's registry reports `.testnet`

## Type

- [ ] Bug fix
- [x] Feature
- [ ] Breaking change
- [x] Documentation
- [ ] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [x] Deployment scripts
- [ ] Tests

## Related Issues

#309

## Fixes

Closes #309

## Checklist

### Code

- [x] Follows project style
- [ ] `forge build` passes
- [ ] `forge test` passes
- [x] No new compiler warnings

### Testing

- [ ] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [ ] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

**Breaking changes:**

## How to test

Cut a pre-release: it should carry `dotns-genesis-testnet.json`,
`dotns-genesis-paseo.json` and `dotns-genesis-addresses.json`

## Notes
…hanges first (#323)

## Description

This PR fixes two things in the release tooling
(`scripts/js/release-metadata.mjs`).

**1. `changedset` no longer flags StoreFactory after comment-only
edits**

StoreFactory deploys other contracts with `new`, so its bytecode carries
a copy of their creation code. Each copy ends with that contract's own
metadata hash, and that hash changes whenever a comment or NatSpec line
changes. `changedset` only stripped StoreFactory's own metadata at the
end of its bytecode, so a comment edit in LabelStore made StoreFactory
look changed and asked for an upgrade nobody needed.

Now the hash inside each embedded copy is set to zeros before hashing.
Real code changes still show up. `codehashes.json` gets a new
`hashScheme` field so that files hashed the old way and the new way are
never compared by mistake. `changedset` reads that field and hashes the
current build the same way the previous file was hashed.

**2. Release notes list breaking changes first**

The "ABI changes" section of the release body is now grouped by how much
each change matters:

1. Breaking changes: the ones declared in pull request descriptions,
then changed function signatures, removed functions, contracts that are
no longer published, and changed or removed events.
2. New contracts, new functions and new events.
3. Custom errors.

A new `pulls` command reads the pull requests merged since the previous
release. A pull request counts as breaking if any of these is true: its
"Breaking Changes" section has text, its title has a `!`, it has the
`breaking` label, or one of the breaking boxes is ticked. Its text is
copied into the notes. `abi-diff.json` gets a new `declaredBreaking`
list. Both publish workflows now need `pull-requests: read`.

## Type

- [x] Bug fix
- [x] Feature
- [ ] Breaking change
- [x] Documentation
- [ ] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [ ] Deployment scripts
- [ ] Tests

Release tooling only. No contract code changes.

## Related Issues

Found in #321, whose NatSpec-only edits to LabelStore put StoreFactory
in its changedset.

## Fixes

Fixes #322

## Checklist

### Code

- [x] Follows project style
- [x] `forge build` passes
- [ ] `forge test` passes
- [x] No new compiler warnings

### Testing

- [ ] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [ ] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [ ] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

**Breaking changes:**

## How to test

**changedset fix**

```bash
forge build
node scripts/js/release-metadata.mjs build --tag base --out /tmp/base --addresses false
# change only a comment in contracts/store/LabelStore.sol
forge build
node scripts/js/release-metadata.mjs changedset --previous /tmp/base/codehashes.json
# nothing is listed

# now make a real code change in LabelStore.sol
forge build
node scripts/js/release-metadata.mjs changedset --previous /tmp/base/codehashes.json
# LabelStore and StoreFactory are listed
```

**Release notes**

```bash
# needs gh logged in with read access to the repo
node scripts/js/release-metadata.mjs pulls --repo paritytech/dotns \
  --base <previous-tag> --head HEAD --out /tmp/pulls.json
node scripts/js/release-metadata.mjs abidiff --current <abis-dir> \
  --previous <previous-abis-dir> --previous-tag <previous-tag> --pulls /tmp/pulls.json
```

## Notes

- The next release still compares against the previous release's
`codehashes.json`, which was hashed the old way. So StoreFactory will
show up once more in that release's changedset if any contract it
deploys changed, even if only a comment changed. After that it is clean.
- If we want that next release to be clean too, we can regenerate the
previous release's metadata with this fix and compare against that
instead. Check out the previous release tag, apply this change, run
`forge build` and `release-metadata.mjs build`, then pass the new
`codehashes.json` to `changedset`. If StoreFactory is not listed, its
code did not change and it does not need an upgrade.
- `pulls` reads every merged pull request, not only the labelled ones,
because missing a breaking change is costly and a label is easy to
forget. It makes one API call per commit, which is fine for our release
size. If releases grow a lot, we can switch to a cheaper approach.
- If reading the pull requests fails, the release step fails. It is
better to re-run the step than to publish notes that miss a breaking
change.
- Any `@mention` in a pull request's breaking changes text will notify
that person when the release is published.

---------

Signed-off-by: GHkrishna <krishna@parity.io>
…teway entrypoints (#321)

## Description

Renames the Proof of Personhood surface from lite/full to the vocabulary
v1.0.0 launches with: **devicehood** and **personhood** for what an
account has proven or a label requires, **device name** (`stem.NN`) and
**personhood name** for the names the gateway issues. v1.0.0 is the
first mainnet launch, so this is the last moment the rename is cheap.

The gateway pallet runtime shipping with this release is frozen and
keeps calling today's three controller functions and decoding today's
errors. The controller therefore serves both: the new entrypoints, and a
separate `IDotnsPopControllerLegacy` that keeps the old selectors. The
next release (R2) will move the pallet to the new entrypoints and remove
the legacy interface.

### What changes

**`DotnsPopController` / `IDotnsPopController`**

| Master | This PR |
| --- | --- |
| `reserveLiteName` | `issueDeviceName` |
| `reserveBaseName` | `issueDeviceNameWithReservation` |
| `reserveBaseNameOnly` | `reservePersonhoodName` |
| `registerBaseName` | `issuePersonhoodName` |
| `reservedBaseLabelOf` | `reservedLabelOf` |
| `LiteRegistration`, `BaseReservation`, `BaseNameReservation`,
`FullRegistration` | `DeviceNameIssuance`,
`DeviceNameIssuanceWithReservation`, `PersonhoodNameReservation`,
`PersonhoodNameIssuance` |
| `LinkKind.LiteUsername` | `LinkKind.DeviceName` |
| `LiteNameReserved` | `DeviceNameIssued` |
| `StandaloneNameRegistered`, `BaseNameClaimed` | `PersonhoodNameIssued`
on every issuance, plus `ReservationClaimed` on a claim |
| `LiteToFullLinked` | `DeviceNameLinked` |
| `InvalidLiteLabel`, `InvalidBaseLabel` | `InvalidDeviceLabel`,
`InvalidPersonhoodLabel` |
| `LiteNameAlreadyIssued` | `DeviceNameAlreadyIssued` |
| `LiteLabelNotOwnedByUser` | `DeviceNameNotOwned` |
| `BaseNameAlreadyRegistered` | `PersonhoodNameUnavailable` |

"Issue" creates a gateway name; "reserve" is only the personhood-name
queue. `reserveLiteName` issued a name, which is why it is renamed.

**`DotnsPopResolver`**: `setLiteLink` and `LiteLinkUpdated` become
`setDeviceLink` and `DeviceLinkUpdated`. The getters are named by what
they return, because the two directions take and return different
identifiers: `liteLink(personhoodNode)` becomes
`deviceLabelhashOf(personhoodNode)`, returning a device-name labelhash,
and `fullClaim(deviceLabelhash)` becomes
`personhoodNodeOf(deviceLabelhash)`, returning a personhood-name node.
  
**`DotnsPopLens`**: `liteNamesOf` + `fullNamesOf` and their two counts
merge into `namesOf(user, offset, limit)` and `nameCountOf(user)`: one
listing of every gateway-issued name the user holds, with a single
offset over store entries first and then pending claims.
`NameDetail.tier`, `liteLink`, `fullClaim` become `requiredTier`,
`deviceLabelhash`, `personhoodNode`. `Name` no longer carries a
`deadline`, because pending claims never lapse (#324).

**`PopRules`**: `PopStatus.PopLite` / `PopFull` become `Devicehood` /
`Personhood` (same `uint8` values), and `personhoodOf` becomes
`popStatusOf`, since it also returns devicehood. Revert messages follow
the new vocabulary.

**What keeps its name**
  
- Lite/Full where dotNS mirrors another team's code: the `IPersonhood`
precompile interface. `PopRules` maps status 1 to `Devicehood` and 2 to
`Personhood` in one place.
- "PoP" in contract names, registry keys and `isPopIssued`.
- The `*BaseName*` identifiers in `PopRules`, which the public
controller and the SDK call. The prose now uses the same word: a label's
**base name** is the label with any device suffix removed, and **stem**
means only the letters of a device name.

### Legacy entrypoints for the frozen pallet
  
`IDotnsPopControllerLegacy` keeps `reserveLiteName`, `reserveBaseName`
and `registerBaseName` with their current selectors (`0x220015c0`,
`0xd89f1bce`, `0x7c4b376b`), checked against the gateway pallet in
individuality-community (v0.3.3 and `main`). Each forwards to its
replacement's shared body. Called through them, label validation reverts
with `InvalidLiteLabel` / `InvalidBaseLabel` (`0x5c6c2eea`,
`0x39e67d31`), the errors the pallet decodes; every other error is
shared. `supportsInterface` reports both interfaces.

### Behaviour changes

- Every exit from a reservation queue now emits an event.
`ReservationClaimed` and `ReservationEvicted` are new, and
`ReservationRelinquished` is emitted wherever a user's entry is dropped
(standalone issuance and re-reservation included), exactly once, and
only when an entry existed.
- `DotnsPopLens.nameDetail(label)` now returns the label and its
required tier for a personhood name whose claim has not settled. It
returned an empty label and `NoStatus`, because the registrar reads a
tokenised name's label from the holder's `LabelStore`.
`nameDetailByNode` still has no label for an unsettled name, which the
node alone cannot recover.
- `DotnsPopLens.Name` drops `deadline`. It reported `mintedAt +
reservationDuration`, but pending claims never lapse and can be settled
at any time, so the field had no meaning (#324). A claim's `mintedAt` is
still available from `IDotnsPopController.pendingClaims`.

### Upgrade shape
  
- Code-only swaps of the `DotnsPopController`, `DotnsPopResolver` and
`PopRules` proxies, plus a redeployed `DotnsPopLens`. No storage
migration.
- Storage layout is unchanged against master, apart from two annotated
mapping renames in `DotnsPopResolver`; every `__gap` stays
`uint256[50]`.
- `DotnsPopController` is 23,497 bytes, 1,079 under the limit.

### Docs

- README gains an **Identifiers** section defining label, labelhash,
node and tokenId, including where a device name's labelhash and node
diverge. It corrects the `DotnsRegistrar` description: a tokenId is
`uint256(node)`.
- README, CONTRIBUTING, KNOWN_ISSUES and NatSpec follow the new
vocabulary, and "dotNS" is spelled consistently across contracts, docs,
scripts and workflows.
- Stale statements fixed along the way:
- `baseLength` was described as "digit-stripped", and `classifyName` as
classifying "by the length it leaves"; every label is measured as
written, less a device name's suffix.
- Pending claims were described as expiring, or as settleable by third
parties only after a window; settlement is permissionless at any time
and always writes the label.
- The commit-reveal controller was described as writing reservations; it
only reads the slot, and clears a reclaimed name's stale slot.
- The lens described ownership as read from the registrar; it reads the
registry, which covers device-name subnames.
- The escrow's zero-amount positions come from cross-paid registrations.

### Consumers

Checked [dotns-sdk](https://github.com/paritytech/dotns-sdk),
[bulletin-deploy](https://github.com/paritytech/bulletin-deploy),
[getcash-community](https://github.com/paritytech/getcash-community),
[host-rust-core](https://github.com/paritytech/host-rust-core/),
[polkadot-ios-community](https://github.com/paritytech/polkadot-ios-community),
[polkadot-android-community](https://github.com/paritytech/polkadot-android-community),
[polkadot-desktop-community](https://github.com/paritytech/polkadot-desktop-community),
[dotli-community](https://github.com/paritytech/dotli-community),
[epoca](https://github.com/paritytech/epoca),
[product-sdk](https://github.com/paritytech/product-sdk): none calls a
renamed selector, so nothing is affected in this release.

## Type

- [ ] Bug fix
- [x] Feature
- [x] Breaking change
- [x] Documentation
- [ ] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [x] Resolver
- [ ] Store
- [x] Proof of Personhood
- [ ] Deployment scripts
- [x] Tests

## Related Issues

#319
#324

## Fixes

Closes #319
Closes #324

## Checklist

### Code

- [x] Follows project style
- [x] `forge build` passes
- [x] `forge test` passes
- [ ] No new compiler warnings

### Testing

- [x] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [x] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [x] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [ ] No breaking changes
- [x] Breaking changes documented below

**Breaking changes:**

- **ABI callers and indexers:** renamed functions and errors get new
selectors, and renamed events a new topic0 (see What changes). The three
legacy entrypoints and `InvalidLiteLabel` / `InvalidBaseLabel` keep
theirs.
- **Decoded struct fields:** clients that decode structs by field name
(viem, ethers) must read the new names: `NameDetail.tier`, `liteLink`,
`fullClaim` become `requiredTier`, `deviceLabelhash`, `personhoodNode`,
and the controller's request structs rename their fields too.
- **`PopStatus`:** values stay `uint8` 0 to 3, so nothing on the wire
changes. Member names are not part of the ABI, so the break is limited
to Solidity code importing `IPopRules` and clients that hardcode the old
labels (`PopLite`, `PopFull`); they need `Devicehood`, `Personhood`. The
same applies to `LinkKind.LiteUsername`, now `LinkKind.DeviceName`.
- **`PopRules` revert strings:** the `PopError` messages changed
wording, so anything matching on the text breaks.
- **Lens listings:** `liteNamesOf` / `fullNamesOf` and their counts are
replaced by `namesOf` / `nameCountOf`, with a single offset, and `Name`
drops `deadline`.

## How to test

```bash
forge test
```

## Notes

Once the dotNS gateway pallet will be updated to the new end points, we
can stop supporting the legacy ones.
…in release notes (#325)

## Description

Fixes the release-pipeline problems hit while publishing v1.0.0.

**Dispatch runs could not publish.** The `release tags` ruleset lets
only the dotns team create `v*` tags. A `workflow_dispatch` run built
and tested everything, created the draft, and then
[failed](https://github.com/paritytech/dotns/actions/runs/36723620824)
at "Publish release": publishing a draft is the moment GitHub creates
its tag, and the workflow token is not allowed to (`Cannot create ref
due to creations being restricted`).

Both publish workflows now run only on a tag push:
  
- `workflow_dispatch` is removed from `publish-release.yml` and
`publish-prerelease.yml`.
- "Resolve release tag" reads the tag that started the run. The
dispatch-only guard against an existing tag, and its token, are gone.
- The concurrency group keys on `github.ref_name`, which is now always
the tag.

**Release body fixes**

- The Usage snippet imported `Store.json`, which no release ships. It
now imports `LabelStore.json` (both workflows).
- The Deployments section implied the listed networks run the release
being published. It now says a network can still run an earlier release
until it is upgraded, and points to how to tell: the protocol registry's
`protocolVersion()`

Docs are also fixed accordingly.

## Type

- [x] Bug fix
- [ ] Feature
- [ ] Breaking change
- [x] Documentation
- [ ] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [ ] Deployment scripts
- [ ] Tests

## Related Issues

## Fixes

Issues during the v1.0.0 release process.

## Checklist

### Code

- [x] Follows project style
- [ ] `forge build` passes
- [ ] `forge test` passes
- [ ] No new compiler warnings

### Testing

- [ ] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [ ] NatSpec updated on changed interfaces
- [x] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

**Breaking changes:**

## How to test

You could test it by triggering a new pre-release.

## Notes

- Repo setting to update after merge: the `releases` environment still
allows `master` as a deployment ref, which only the dispatch path used.
Remove it so the environment matches RELEASE_ARTIFACTS.
- The v1.0.0 release notes were corrected by hand for the same two body
issues; this PR stops later releases from repeating them.
Brings v1.0.0 onto the upgrade branch. Conflicts resolved keeping the
branch's retained storage in DotnsRegistrarController (whitelist slot,
AccessControl namespace) and DotnsNameWhitelist (AccessControl
namespace), and the dedicated fork-test job in push_checking.yml.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…om chain

Removes the v0.7.0 to v0.8.0 campaign (snapshots, store-factory migrator,
ownership rotation, ten upgrade scripts and fork tests, runbook); it stays
in history under upgrades/paseo-nv2-v0.8.0.

Adds snapshots of the four contracts this campaign upgrades (DotnsRegistry,
PopRules, DotnsPopResolver, DotnsPopController), copied from
upgrades/paseo-nv2-v0.8.0 with the code-changed files of their import
closure. verify-snapshots.sh reproduces all five deployed implementations
on Paseo, DotnsRegistrar included. LayoutCompatibility covers the four.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
UpgradePopResolverAndController swaps the PoP resolver and controller in
consecutive transactions, validating both layouts first and skipping a
proxy already upgraded. RedeployPopLens deploys the lens at a
release-scoped CREATE3 salt (the default one is spent on Paseo), rewires
popLens and declares its codehash. UpgradeRegistry and UpgradePopRules
are kept with v1.0.0 docs.

BaseDeployer gains a salt-taking _broadcastDeployCreate3, and the store
verification compares runtime code without its metadata trailer, since
v1.0.0 rewords store docs only.

Fork tests cover each step, re-runs, the state between steps, and the
whole campaign ending on a verified 1.0.0 declaration.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Allowlists the five steps and checks, before each upgrade step, the
snapshots of the contracts that step upgrades (SNAPSHOT_SUBJECTS in
verify-snapshots.sh). Drops the rotation and migration plumbing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

CI Summary

Check Result
Contract Tests (Unit + Fuzz) Failed
Contract Tests (Invariant) Failed
Upgrade Fork Tests Passed
Format & Lint Passed - Code formatted correctly
PR Title PR Title Valid
Labels Unknown

Labels

dependencies, smartcontracts, other, scope: registration, scope: resolver, type: test, type: docs, scope: store, scope: pop

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file smartcontracts Any issue relating to smart contracts other scope: registration scope: resolver type: test type: docs scope: store labels Oct 5, 2026
@re-gius
re-gius marked this pull request as ready for review October 5, 2026 14:21
@re-gius
re-gius merged commit e1f180a into dev/testnet-upgrades Oct 5, 2026
11 of 14 checks passed
@re-gius
re-gius deleted the chore/paseo-v1.0.0-upgrade branch October 5, 2026 15:34
github-actions Bot added a commit that referenced this pull request Oct 5, 2026
re-gius added a commit that referenced this pull request Oct 6, 2026
re-gius added a commit that referenced this pull request Oct 6, 2026
## Description

Paseo Asset Hub Next was upgraded in place from v0.8.0 to v1.0.0 on
2026-10-06 (content #331, broadcast via #332). The four upgraded
contracts kept their proxies; the only address that moved is the PoP
lens, redeployed at a release-scoped CREATE3 salt.

| Key | Before | After |
|---|---|---|
| `DotnsPopLens` | `0xAE374b07c7e6f473CBa21d57e36AC15C631Abc51` |
`0x309C5ff21f9082A53211500c6f33cA2a21024Ae4` |

This brings master's manifest in line with the chain.

## Type

- [ ] Bug fix
- [ ] Feature
- [ ] Breaking change
- [ ] Documentation
- [x] Chore
- [ ] Refactor
- [ ] Security

## Scope

- [ ] Registration
- [ ] Resolver
- [ ] Store
- [ ] Proof of Personhood
- [x] Deployment scripts
- [ ] Tests

## Related Issues

See #331, #332

## Fixes

## Checklist

### Code

- [x] Follows project style
- [ ] `forge build` passes
- [ ] `forge test` passes
- [ ] No new compiler warnings

### Testing

- [ ] New tests added for changed behavior
- [ ] Fuzz tests added where applicable
- [ ] Invariant tests verified

### Security

- [x] No new `selfdestruct` or `delegatecall`
- [x] Access control reviewed
- [x] No storage layout conflicts (for upgradeable contracts)

### Documentation

- [ ] NatSpec updated on changed interfaces
- [ ] README updated if needed

### Breaking Changes

- [x] No breaking changes
- [ ] Breaking changes documented below

**Breaking changes:**

## How to test

```bash
node scripts/js/release-metadata.mjs verify --network paseo-assethub \
  --rpc https://eth-rpc-paseo-next.polkadot.io --tag v1.0.0
```

## Notes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants