Smart Contract Versioning and Release Process
The Smart Contract Versioning and Release Process closely follows a true semver for both individual contracts and monorepo releases. However, there are some changes to accommodate the unique nature of smart contract development and governance cycles.
There are five parts to the versioning and release process:
- Semver Rules: Follows the rules defined in the style guide for when to bump major, minor, and patch versions in individual contracts.
- Individual Contract Versioning: The versioning scheme for individual contracts and includes beta, release candidate, and feature tags.
- Monorepo Contracts Release Versioning: The versioning scheme for monorepo smart contract releases.
- Release Process: The process for deploying contracts, creating a governance proposal, and the required associated releases.
- Additional Release Candidates: How to handle additional release candidates after an initial
op-contracts/vX.Y.Z-rc.1release.
- Additional Release Candidates: How to handle additional release candidates after an initial
[!NOTE] The rules described in this document must be enforced manually. Ideally, a check can be added to CI to enforce the conventions defined here, but this is not currently implemented.
Semver Rules
Version increments follow the style guide rules for when to bump major, minor, and patch versions in individual contracts:
patchreleases are to be used only for changes that do NOT modify contract bytecode (such as updating comments).minorreleases are to be used for changes that modify bytecode OR changes that expand the contract ABI provided that these changes do NOT break the existing interface.majorreleases are to be used for changes that break the existing contract interface OR changes that modify the security model of a contract.Bumping the patch version does change the bytecode, so another exception is carved out for this. In other words, changing comments increments the patch version, which changes bytecode. This bytecode change implies a minor version increment is needed, but because it's just a version change, only a patch increment should be used.
Individual Contract Versioning
Individual contract versioning allows us to uniquely identify which version of a contract from the develop branch corresponds to each deployed contract instance.
Versioning for individual contracts works as follows:
- A contract on develop always has a version of X.Y.Z, regardless of whether is has been governance approved and meets our security bar. This DOES NOT indicate these contracts are always safe for production use. More on this below.
- For contracts with feature-specific changes, a
+feature-nameidentifier must be appended to the version number. See the Smart Contract Feature Development design document to learn more. - When making changes to a contract, always bump to the lowest possible version based on the specific change you are making. We do not want to e.g. optimistically bump to a major version, because protocol development sequencing may change unexpectedly. Use these examples to know how to bump the version:
- Example 1: A contract is currently on
1.2.3ondevelopand you are working on a new feature on yourfeaturebranch offdevelop.- We don't yet know when the next release of this contract will be. However, you are simply fixing typos in comments so you bump the version to
1.2.4. - The next commit to the
featurebranch clarifies some comments. We only consider the aggregatedfeaturechanges with regards todevelopwhen determining the version, so we stay at1.2.4. - The next commit to the
featurebranch introduces a breaking change, which bumps the version from1.2.4to2.0.0.
- We don't yet know when the next release of this contract will be. However, you are simply fixing typos in comments so you bump the version to
- Example 2: A contract is currently on
2.4.7.- We know the next release of this contract will be a breaking change. Regardless, as you start development by fixing typos in comments, bump the version to
2.4.8. This is because we may end up putting out a release before the breaking change is added. - Once you start working on the breaking change, bump the version to
3.0.0.
- We know the next release of this contract will be a breaking change. Regardless, as you start development by fixing typos in comments, bump the version to
- Example 1: A contract is currently on
- New contracts start at
1.0.0.
Versioning is enforced by CI checks:
- Any contract that differs from its version in the
developbranch must be bumped to a new semver value, or the build will fail. - Any branch with at least one modified contract must have its
semver-lock.jsonfile updated, or the build will fail. You can use thesemver-lockorpre-commitjust commands to do so.
Note: Previously, the versioning scheme included -beta.n and -rc.n qualifiers. These are no longer used to reduce the amount of work required to execute this versioning system.
Deprecating Individual Contract Versioning
Individual contract versioning could be deprecated when the following conditions are met:
- Every OPCM instance is registered in the superchain registry
- All contracts are implemented as either proxies or concrete singletons, allowing verification of governance approval through the
OPCM.Implementationsstruct - We have validated with engineering teams (such as the fault proofs team) and ecosystem partners (such as L2Beat) that removing
version()functions would not negatively impact their workflows
Monorepo Contracts Release Versioning
Versioning for monorepo releases works as follows:
- Monorepo releases continue to follow the
op-contracts/vX.Y.Znaming convention. - The version used for the next release is determined by the highest version bump of any individual contract in the release.
- Example 1: The monorepo is at
op-contracts/v1.5.0. Clarifying comments are made in contracts, so all contracts only bump the patch version. The next monorepo release will beop-contracts/v1.5.1. - Example 2: The monorepo is at
op-contracts/v1.5.1. Various tech debt and code is cleaned up in contracts, but no features are added, so at most, contracts bumped the minor version. The next monorepo release will beop-contracts/v1.6.0. - Example 3: The monorepo is at
op-contracts/v1.5.1. LegacyALL_CAPS()getter methods are removed from a contract, causing that contract to bump the major version. The next monorepo release will beop-contracts/v2.0.0.
- Example 1: The monorepo is at
- Feature specific monorepo releases (such as a release of the custom gas token feature) are supported, and should follow the guidelines in the Smart Contract Feature Development design doc. Bump the overall monorepo semver as required by the above rules. For example, if the last release before the custom gas token feature was
op-contracts/v1.5.1, because the custom gas token introduces breaking changes, its release will beop-contracts/v2.0.0.- A subsequent release of the custom gas token feature that fixes bugs and introduces an additional breaking change would be
op-contracts/v3.0.0. - This means
+feature-namenaming is not used for monorepo releases, only for individual contracts as described below.
- A subsequent release of the custom gas token feature that fixes bugs and introduces an additional breaking change would be
- A monorepo contracts release must map to an exact set of contract semvers, and this mapping must be defined in the contract release notes which are the source of truth. See
op-contracts/v1.4.0-rc.4for an example of what release notes should look like.
Optimism Contracts Manager (OPCM) Versioning
The OPCM is the contract that manages the deployment of all contracts on L1.
The OPCM is the source of truth for the contracts that belong in a release, available as on-chain addresses by querying the getImplementations function.