|
| 1 | +--- |
| 2 | +eip: 8303 |
| 3 | +title: Contract Version |
| 4 | +description: Interface for exposing a contract implementation version string |
| 5 | +author: Ryan Sauge (@rya-sge) |
| 6 | +discussions-to: https://ethereum-magicians.org/t/erc-8303-contract-version/28795 |
| 7 | +status: Draft |
| 8 | +type: Standards Track |
| 9 | +category: ERC |
| 10 | +created: 2026-02-12 |
| 11 | +--- |
| 12 | + |
| 13 | +## Abstract |
| 14 | + |
| 15 | +This ERC defines a minimal interface to expose a contract version string through a standardized `version()` view function. The design is based on the version pattern used by [ERC-3643](./eip-3643.md), while remaining token-agnostic and applicable to other smart contract domains, including DeFi applications such as lending protocols. |
| 16 | + |
| 17 | +## Motivation |
| 18 | + |
| 19 | +Integrators frequently need a simple, on-chain way to identify which contract implementation they interact with. A standardized version function improves: |
| 20 | + |
| 21 | +- integration safety (feature gating by version), |
| 22 | +- operations (faster incident triage), |
| 23 | +- governance and migration tracking (upgrade visibility), |
| 24 | +- ecosystem tooling interoperability. |
| 25 | + |
| 26 | +It is also useful for end-users, developers, and security auditors to identify which version of a codebase is currently used by a deployed contract. |
| 27 | + |
| 28 | +The same requirement appears in permissioned token systems ([ERC-3643](./eip-3643.md)) and in DeFi systems where contracts evolve over time. |
| 29 | + |
| 30 | +## Specification |
| 31 | + |
| 32 | +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174). |
| 33 | + |
| 34 | +### Interface |
| 35 | + |
| 36 | +```solidity |
| 37 | +interface IERC8303 { |
| 38 | + /// @notice Returns the implementation version string. |
| 39 | + /// @return The version value (for example "1.0.0"). |
| 40 | + function version() external view returns (string memory); |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +### Required Behavior |
| 45 | + |
| 46 | +1. **Version read** |
| 47 | + - `version()` MUST be a view function. |
| 48 | + - `version()` MUST NOT revert under normal operation. |
| 49 | + - `version()` MUST return a non-empty string. |
| 50 | + |
| 51 | +2. **Version meaning** |
| 52 | + - Returned values SHOULD be stable and machine-comparable by off-chain tooling. |
| 53 | + - Returned values SHOULD follow a Semantic Versioning 2.0.0-like format: `MAJOR.MINOR.PATCH` using decimal integers (for example `1.0.0`, `3.2.1`). |
| 54 | + - The canonical recommended pattern is `^[0-9]+\.[0-9]+\.[0-9]+$`. |
| 55 | + - Implementations MAY define their own versioning policy, but SHOULD document it publicly. |
| 56 | + |
| 57 | +3. **Deployment model compatibility** |
| 58 | + - This interface is compatible with immutable deployments and proxy-based upgradeable deployments. |
| 59 | + - In upgradeable systems, `version()` SHOULD reflect the active implementation seen by users and integrators. |
| 60 | + |
| 61 | +### [ERC-165](./eip-165.md) |
| 62 | + |
| 63 | +Implementations SHOULD support [ERC-165](./eip-165.md) interface discovery for this interface. |
| 64 | + |
| 65 | +If an implementation supports [ERC-165](./eip-165.md), `supportsInterface(type(IERC8303).interfaceId)` MUST return `true`. |
| 66 | + |
| 67 | +- The interface id for `IERC8303` is `0x54fd4d50`. |
| 68 | + |
| 69 | +### Compatibility Note for ERC-3643 Integrations |
| 70 | + |
| 71 | +Integrators MAY treat legacy ERC-3643 token contracts exposing a compatible `version()` function as implementing this ERC even if they do not advertise ERC-165 support. |
| 72 | + |
| 73 | +## Rationale |
| 74 | + |
| 75 | +- **Minimal scope**: A single function maximizes adoption and keeps gas/runtime complexity negligible. |
| 76 | +- **ERC-3643 alignment**: Reuses a proven pattern already used in regulated token implementations. |
| 77 | +- **Token-agnostic design**: The interface applies to token contracts and non-token contracts alike. |
| 78 | +- **Optional ERC-165**: ERC-165 support is recommended but not required, lowering the adoption barrier for contracts that do not implement interface discovery. When ERC-165 is supported, advertising this interface is mandatory to ensure consistent detection by integrators. |
| 79 | +- **`string` over `bytes32`**: A human-readable string is preferred to a fixed-size bytes32 for legibility in explorers and tooling, at the cost of marginally higher gas for the return value. |
| 80 | + |
| 81 | +## Backwards Compatibility |
| 82 | + |
| 83 | +This ERC is fully additive. Contracts already exposing `version()` are naturally compatible if they match the interface signature. |
| 84 | + |
| 85 | +## Test Cases |
| 86 | + |
| 87 | +The following test cases apply to any conforming implementation. |
| 88 | + |
| 89 | +1. `version()` MUST NOT revert. |
| 90 | +2. `version()` MUST return a non-empty string. |
| 91 | +3. `version()` MUST return the version string declared by the implementation (e.g. `"1.0.0"`). |
| 92 | +4. If the contract supports [ERC-165](./eip-165.md), `supportsInterface(0x54fd4d50)` MUST return `true`. |
| 93 | +5. If the contract supports [ERC-165](./eip-165.md), `supportsInterface(0xffffffff)` MUST return `false`. |
| 94 | + |
| 95 | +## Reference Implementation |
| 96 | + |
| 97 | +Reference implementations are provided in the assets folder: the [interface](../assets/erc-8303/src/IERC8303.sol) and a [base implementation](../assets/erc-8303/src/ERC8303.sol), along with usage examples for [ERC-20](../assets/erc-8303/src/examples/ERC20VersionedExample.sol) and [ERC-721](../assets/erc-8303/src/examples/ERC721VersionedExample.sol) tokens. These examples are provided for educational purposes only and are not audited. |
| 98 | + |
| 99 | +```solidity |
| 100 | +// SPDX-License-Identifier: CC0-1.0 |
| 101 | +pragma solidity ^0.8.0; |
| 102 | +
|
| 103 | +import "./IERC8303.sol"; |
| 104 | +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; |
| 105 | +
|
| 106 | +contract ERC8303Example is IERC8303, ERC165 { |
| 107 | + function version() external pure override returns (string memory) { |
| 108 | + return "1.0.0"; |
| 109 | + } |
| 110 | +
|
| 111 | + function supportsInterface(bytes4 interfaceId) |
| 112 | + public |
| 113 | + view |
| 114 | + override |
| 115 | + returns (bool) |
| 116 | + { |
| 117 | + return interfaceId == type(IERC8303).interfaceId |
| 118 | + || super.supportsInterface(interfaceId); |
| 119 | + } |
| 120 | +} |
| 121 | +``` |
| 122 | + |
| 123 | +## Security Considerations |
| 124 | + |
| 125 | +- `version()` is metadata and must not be used as a sole authorization primitive. |
| 126 | +- In upgradeable systems, governance controls remain the trust anchor; version reporting does not prevent malicious upgrades. |
| 127 | +- Integrators should combine version checks with other trust signals (governance model, audits, deployment provenance). |
| 128 | + |
| 129 | +## Copyright |
| 130 | + |
| 131 | +Copyright and related rights waived via [CC0](../LICENSE.md). |
0 commit comments