Upgradeability: beacons and versions
The contracts that hold a register have to be able to change: to fix a defect, to follow a standard, to add a capability. They also have to change safely and visibly, because the assets they record outlive any version of the code. The protocol provides upgradeability through standard mechanisms that auditors and tooling already understand, and it is explicit about who can change the code of what.
What is upgradeable, and how
Token, TREXRegistry, IdentityRegistryStorage, ModularCompliance, TREXAccessManager
Beacon proxy
In a shared suite: the VERSION_MANAGER of the network. In an isolated suite: the Issuer.
Identity (every ONCHAINID)
Beacon proxy, one beacon for all identities
The beacon upgrader of the identity layer, after a delay
Compliance modules
UUPS proxy
The authority of the module
UtilityChecker, IdentityUtilities
UUPS proxy
The owner of UtilityChecker. The holder of DEFAULT_ADMIN_ROLE on IdentityUtilities
TREXFactory, TREXImplementationAuthority, TrustedGatewayRegistry
Not upgradeable
IdentityFactory, ReputationRegistry, EASClaimIssuer
Not upgradeable
ERC734Validator, KeyApprovalModule, RecoveryModule
Not upgradeable
A contract that is not upgradeable is replaced by deploying a new one and pointing to it. The factory, for instance, can be given a new implementation authority for the suites it deploys from then on.
Beacon proxies
A beacon holds the address of the current implementation for a family of proxies. Each proxy asks its beacon where the code is. Changing the address in the beacon changes the code of every proxy that points to it, in one transaction.
A token suite has five kinds of contract, and the authority holds one beacon for each. Every suite deployed in shared mode points to these five beacons.
Versions
The TREXImplementationAuthority does not upgrade one contract at a time. It moves a suite from one version to the next, where a version is a complete, coherent set of five implementations.
publish(version, implementations)
Archives the five implementations of a version. No beacon changes. No suite is affected.
upgrade(version)
Points the five beacons at the implementations of a published version. Every shared suite moves to that version in one transaction.
publishAndUpgrade(version, implementations)
Both at once.
All three require the VERSION_MANAGER platform role. A version upgrade is decided by a vote of Network governance, and the role carries an execution delay: the upgrade is scheduled, stays visible for the delay, and only then executes.
A version is a semantic version: major, minor, patch.
Versions are ordered.
A version is published once. Its implementations cannot be changed afterward.
What a version number designates never varies.
Publishing and upgrading are separate.
A version can be published, inspected and verified on-chain before any suite runs it.
An upgrade only moves forward. The target must be greater than the active version.
A beacon can never be rolled back onto older code.
The five contracts move together.
A suite never runs a token of one version against a compliance of another.
There is no rollback. The way back from a faulty version is a new version with a higher number.
currentVersion() returns the active version. implementations() returns the implementations it designates, implementationsFor(version) those of any published version, and beacons() the five beacon addresses, which never change. The events VersionPublished and SuiteUpgraded record every step.
Shared and isolated suites
An Issuer chooses at deployment who upgrades its suite.
Deployed with
deployTREXSuite
deployTREXSuiteIsolated
Beacons
The five beacons of the authority, common to all shared suites
Its own beacons, created for it from the active version
Owner of the beacons
The TREXImplementationAuthority
The suite's own AccessManager. The beacon of that manager belongs to the admin the Issuer named.
Who upgrades
The VERSION_MANAGER, for every shared suite at once
The Issuer, through its manager
Follows the network's versions
Automatically
Only when the Issuer upgrades its own beacons
Identity storage
Its own, or an existing shared one
Always its own
In an isolated suite, the Issuer upgrades a contract by having its manager point the corresponding beacon at a new implementation. By default only the admin of that manager can do so. The Issuer can assign the operation to a narrower role, with a delay.
An isolated suite always deploys its own identity storage. A storage reused from another suite would keep the beacon that deployed it, and shared upgrades would still reach it.
Trust statement. In a shared suite, the
VERSION_MANAGERcan replace the code of the token, the registry, the storage, the compliance and the access manager of every suite at once. It does so on a vote of Network governance and after a delay. An Issuer that does not accept this deploys an isolated suite and takes on the responsibility of upgrading it.
Identities
Every ONCHAINID points to one beacon, owned by the IdentityFactory. Upgrading that beacon changes the implementation of every identity.
The factory refuses a new implementation unless it:
names this same factory,
names the same key registry as the implementation it replaces,
has its own initialization locked,
reports the version that the upgrader announced.
The upgrade is gated by a dedicated role with an execution delay. It is scheduled first, stays visible during the delay, and can be cancelled before it takes effect.
Two things cannot change through an upgrade of identities. The key registry stays the same contract, so no upgrade can move an identity's keys. And the signing domain of identities is kept constant, because every stored claim is verified against it.
Compliance modules
A compliance module is one upgradeable contract, serving every compliance that binds it. Upgrading it changes the rule for all of them. The upgrade is authorized by the module's own authority, which is separate from any token suite.
If an upgrade changes the types a module declares, each compliance applies the change by calling resyncModuleTypes. See Modular compliance.
What keeps an upgrade safe
Namespaced storage. Every upgradeable contract keeps its state in a storage region derived from a name, not in sequential slots.
A new variable overwriting an old one, or the state of an inherited contract. This class of error has caused serious failures in upgradeable systems built without it.
Coordinated versions.
A suite running mismatched contracts.
Forward-only upgrades.
A return to code that was replaced for a reason.
Publish before upgrade.
Code that reaches suites without having been visible on-chain.
Continuity checks on identities.
An upgrade that silently points every identity at another key registry or another factory.
The compliance and the registry of a circulating token stay in place. They are upgraded, never swapped.
A token whose positions are attributed by a contract that has not seen them.
Role-gated and delayable. Every upgrade path is a role in an access manager.
An upgrade by an unauthorized party, or one that takes effect unseen.
Storage is described under Namespaced storage (ERC-7201).
Who can change the code
A shared suite
VERSION_MANAGER, after a vote of Network governance and a delay
The delay, during which the upgrade is visible. Or choose an isolated suite
An isolated suite
The Issuer's own manager
Its own governance
Identities
The beacon upgrader of the identity layer
The delay, during which the upgrade is visible
A compliance module
Network governance, for the shared modules
Deploy its own instance of the module
Reading versions
Token.version()
The version of the token implementation, for example 5.0.0.
Identity.version()
The version of the identity implementation.
TREXImplementationAuthority.currentVersion()
The version the shared beacons point to.
Last updated