From 468913b3e4db124a3523e40f4cf3617c6840ad56 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 12 Sep 2025 16:15:28 +0200 Subject: [PATCH 01/14] stateless & transpiler config --- contracts/proxy/utils/UUPSUpgradeable.sol | 2 ++ contracts/token/ERC1155/utils/ERC1155Holder.sol | 2 ++ contracts/token/ERC721/utils/ERC721Holder.sol | 2 ++ scripts/upgradeable/transpile.sh | 5 ----- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/contracts/proxy/utils/UUPSUpgradeable.sol b/contracts/proxy/utils/UUPSUpgradeable.sol index d0f58427f9b..6be78251d96 100644 --- a/contracts/proxy/utils/UUPSUpgradeable.sol +++ b/contracts/proxy/utils/UUPSUpgradeable.sol @@ -15,6 +15,8 @@ import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. + * + * @custom:stateless */ abstract contract UUPSUpgradeable is IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable diff --git a/contracts/token/ERC1155/utils/ERC1155Holder.sol b/contracts/token/ERC1155/utils/ERC1155Holder.sol index 19d79631aee..d79c7b56611 100644 --- a/contracts/token/ERC1155/utils/ERC1155Holder.sol +++ b/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -11,6 +11,8 @@ import {IERC1155Receiver} from "../IERC1155Receiver.sol"; * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. + * + * @custom:stateless */ abstract contract ERC1155Holder is ERC165, IERC1155Receiver { /// @inheritdoc IERC165 diff --git a/contracts/token/ERC721/utils/ERC721Holder.sol b/contracts/token/ERC721/utils/ERC721Holder.sol index 6bb23ace5b7..fd8c1b17aa1 100644 --- a/contracts/token/ERC721/utils/ERC721Holder.sol +++ b/contracts/token/ERC721/utils/ERC721Holder.sol @@ -11,6 +11,8 @@ import {IERC721Receiver} from "../IERC721Receiver.sol"; * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or * {IERC721-setApprovalForAll}. + * + * @custom:stateless */ abstract contract ERC721Holder is IERC721Receiver { /** diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index f7c848c1320..6d9e39c35d7 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -33,11 +33,6 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -i contracts/proxy/utils/Initializable.sol \ -x 'contracts-exposed/**/*' \ -x 'contracts/proxy/**/*' \ - -x '!contracts/proxy/Clones.sol' \ - -x '!contracts/proxy/ERC1967/ERC1967Storage.sol' \ - -x '!contracts/proxy/ERC1967/ERC1967Utils.sol' \ - -x '!contracts/proxy/utils/UUPSUpgradeable.sol' \ - -x '!contracts/proxy/beacon/IBeacon.sol' \ -p 'contracts/access/manager/AccessManager.sol' \ -p 'contracts/finance/VestingWallet.sol' \ -p 'contracts/governance/TimelockController.sol' \ From ea26b1684f01a16dff880a2765746e7e8ee2b133 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 12 Sep 2025 16:16:14 +0200 Subject: [PATCH 02/14] local dep --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index d454e9303a4..f9146035b34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.13", "@openzeppelin/docs-utils": "^0.1.5", "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrade-safe-transpiler": "file:../openzeppelin-transpiler/openzeppelin-upgrade-safe-transpiler-v0.3.33.tgz", "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^9.0.0", @@ -2009,8 +2009,8 @@ }, "node_modules/@openzeppelin/upgrade-safe-transpiler": { "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.3.33.tgz", - "integrity": "sha512-yKdnfZtfDw0ivonZmDx1YgFJXLNHz/5+XPN7bx/9ObQYKUawmTiOcGC6BKezpphL+witvHQbMhmQbwGIyEoR8g==", + "resolved": "file:../openzeppelin-transpiler/openzeppelin-upgrade-safe-transpiler-v0.3.33.tgz", + "integrity": "sha512-Ja8Hga/A/joc4T4vXCU73NVaEYDVS5nvBcX5fhiUV4fphYzANEfFl+zaNhN7yfKUEY4Z449KZiKCCnClGclHJA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 285a074ed63..ea61a8c1262 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.13", "@openzeppelin/docs-utils": "^0.1.5", "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrade-safe-transpiler": "file:../openzeppelin-transpiler/openzeppelin-upgrade-safe-transpiler-v0.3.33.tgz", "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^9.0.0", From b5f802b3b4538965aff8106c06730dae2e9d7bec Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 12 Sep 2025 16:37:58 +0200 Subject: [PATCH 03/14] rewrite transpilation rules --- scripts/upgradeable/transpile.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index 6d9e39c35d7..02743c6de22 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -23,7 +23,7 @@ fi # -D: delete original and excluded files # -b: use this build info file # -i: use included Initializable -# -x: exclude proxy-related contracts with a few exceptions +# -x: exclude some proxy-related contracts # -p: emit public initializer # -n: use namespaces # -N: exclude from namespaces transformation @@ -32,7 +32,12 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -b "$build_info" \ -i contracts/proxy/utils/Initializable.sol \ -x 'contracts-exposed/**/*' \ - -x 'contracts/proxy/**/*' \ + -x 'contracts/proxy/beacon/BeaconProxy.sol' \ + -x 'contracts/proxy/beacon/UpgradeableBeacon.sol' \ + -x 'contracts/proxy/ERC1967/ERC1967Proxy.sol' \ + -x 'contracts/proxy/Proxy.sol' \ + -x 'contracts/proxy/transparent/ProxyAdmin.sol' \ + -x 'contracts/proxy/transparent/TransparentUpgradeableProxy.sol' \ -p 'contracts/access/manager/AccessManager.sol' \ -p 'contracts/finance/VestingWallet.sol' \ -p 'contracts/governance/TimelockController.sol' \ From a09fde062775386be6bf3804821840b57af2c437 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 17:55:11 +0200 Subject: [PATCH 04/14] use @openzeppelin/upgrade-safe-transpiler v0.4.0 --- package-lock.json | 113 +++++++++++++++------------------------------- package.json | 2 +- 2 files changed, 38 insertions(+), 77 deletions(-) diff --git a/package-lock.json b/package-lock.json index f9146035b34..d235f990c01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.13", "@openzeppelin/docs-utils": "^0.1.5", "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "file:../openzeppelin-transpiler/openzeppelin-upgrade-safe-transpiler-v0.3.33.tgz", + "@openzeppelin/upgrade-safe-transpiler": "^0.4.0", "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^9.0.0", @@ -1427,6 +1427,29 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -2008,17 +2031,17 @@ } }, "node_modules/@openzeppelin/upgrade-safe-transpiler": { - "version": "0.3.33", - "resolved": "file:../openzeppelin-transpiler/openzeppelin-upgrade-safe-transpiler-v0.3.33.tgz", - "integrity": "sha512-Ja8Hga/A/joc4T4vXCU73NVaEYDVS5nvBcX5fhiUV4fphYzANEfFl+zaNhN7yfKUEY4Z449KZiKCCnClGclHJA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.4.0.tgz", + "integrity": "sha512-Ru0se7+dkuREpjqHxs6E+fCIBZwifuXoM5OXA6G/uSySWM2GLa9irAueavXVSMxuGvaCV6vlT+K1DuXrjCIHRg==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0", "compare-versions": "^6.0.0", - "ethereum-cryptography": "^2.0.0", + "ethereum-cryptography": "^3.0.0", "lodash": "^4.17.20", - "minimatch": "^9.0.0", + "minimatch": "^10.0.3", "minimist": "^1.2.5", "solidity-ast": "^0.4.51" }, @@ -2026,82 +2049,20 @@ "upgrade-safe-transpiler": "dist/cli.js" } }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@noble/hashes": "1.4.0" + "@isaacs/brace-expansion": "^5.0.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" + "node": "20 || >=22" }, "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@openzeppelin/upgrades-core": { diff --git a/package.json b/package.json index ea61a8c1262..bdbb93dec6f 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.13", "@openzeppelin/docs-utils": "^0.1.5", "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "file:../openzeppelin-transpiler/openzeppelin-upgrade-safe-transpiler-v0.3.33.tgz", + "@openzeppelin/upgrade-safe-transpiler": "^0.4.0", "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^9.0.0", From 7b34af76adcbfeb58ad9bed359055ddafd2fa304 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 17:56:36 +0200 Subject: [PATCH 05/14] transpile rules --- scripts/upgradeable/transpile.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index 02743c6de22..fe14beefb65 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -32,12 +32,8 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -b "$build_info" \ -i contracts/proxy/utils/Initializable.sol \ -x 'contracts-exposed/**/*' \ - -x 'contracts/proxy/beacon/BeaconProxy.sol' \ + -x 'contracts/proxy/**/*Proxy*.sol' \ -x 'contracts/proxy/beacon/UpgradeableBeacon.sol' \ - -x 'contracts/proxy/ERC1967/ERC1967Proxy.sol' \ - -x 'contracts/proxy/Proxy.sol' \ - -x 'contracts/proxy/transparent/ProxyAdmin.sol' \ - -x 'contracts/proxy/transparent/TransparentUpgradeableProxy.sol' \ -p 'contracts/access/manager/AccessManager.sol' \ -p 'contracts/finance/VestingWallet.sol' \ -p 'contracts/governance/TimelockController.sol' \ From da2197bf18966e1ff8d5f399f7f0c3281ce40e3f Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 18:08:22 +0200 Subject: [PATCH 06/14] Add changelog notice --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4891ed39a91..4ad05d955a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Breaking changes +- `Initializable` and `UUPSUpgradeable` are no longer transpiled, and are now absent from the `@openzeppelin/contracts-upgradeable` package. Imports must be updated to get these files from `@openzeppelin/contracts` instead. - `SignerERC7702` is renamed as `SignerEIP7702`. Imports and inheritance must be updated to that new name and path. Behavior is unmodified. - Update minimum pragma to 0.8.24 in `Votes`, `VotesExtended`, `ERC20Votes`, `Strings`, `ERC1155URIStorage`, `MessageHashUtils`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721Wrapper`, `EIP712`, and `ERC7739`. ([#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726)) From 258e110a09b0fe077e61fbf491336624a3e26262 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 18:11:52 +0200 Subject: [PATCH 07/14] keep upgradeable version of ERC721Holder and ERC1155Holder --- contracts/token/ERC1155/utils/ERC1155Holder.sol | 2 -- contracts/token/ERC721/utils/ERC721Holder.sol | 2 -- 2 files changed, 4 deletions(-) diff --git a/contracts/token/ERC1155/utils/ERC1155Holder.sol b/contracts/token/ERC1155/utils/ERC1155Holder.sol index d79c7b56611..19d79631aee 100644 --- a/contracts/token/ERC1155/utils/ERC1155Holder.sol +++ b/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -11,8 +11,6 @@ import {IERC1155Receiver} from "../IERC1155Receiver.sol"; * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. - * - * @custom:stateless */ abstract contract ERC1155Holder is ERC165, IERC1155Receiver { /// @inheritdoc IERC165 diff --git a/contracts/token/ERC721/utils/ERC721Holder.sol b/contracts/token/ERC721/utils/ERC721Holder.sol index fd8c1b17aa1..6bb23ace5b7 100644 --- a/contracts/token/ERC721/utils/ERC721Holder.sol +++ b/contracts/token/ERC721/utils/ERC721Holder.sol @@ -11,8 +11,6 @@ import {IERC721Receiver} from "../IERC721Receiver.sol"; * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or * {IERC721-setApprovalForAll}. - * - * @custom:stateless */ abstract contract ERC721Holder is IERC721Receiver { /** From 1257b39da557790a72e7ab5bf5ab3c6637d76236 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 21:40:47 +0200 Subject: [PATCH 08/14] use transpiler v0.4.1 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d235f990c01..8e6df71f0d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.13", "@openzeppelin/docs-utils": "^0.1.5", "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "^0.4.0", + "@openzeppelin/upgrade-safe-transpiler": "^0.4.1", "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^9.0.0", @@ -2031,9 +2031,9 @@ } }, "node_modules/@openzeppelin/upgrade-safe-transpiler": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.4.0.tgz", - "integrity": "sha512-Ru0se7+dkuREpjqHxs6E+fCIBZwifuXoM5OXA6G/uSySWM2GLa9irAueavXVSMxuGvaCV6vlT+K1DuXrjCIHRg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.4.1.tgz", + "integrity": "sha512-IxNqDuHLBUp7WcTtrfNrl7ccHzaKLB0Pn9YLE6HyMdzppbBiKls47cHFIC/uLI91cvZP0cheIyvtA3g/3FEdOA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index bdbb93dec6f..f6960972ad5 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.13", "@openzeppelin/docs-utils": "^0.1.5", "@openzeppelin/merkle-tree": "^1.0.7", - "@openzeppelin/upgrade-safe-transpiler": "^0.4.0", + "@openzeppelin/upgrade-safe-transpiler": "^0.4.1", "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^9.0.0", From d17b86c38f69f060ed06ef5c91f95258882a32dd Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 22:19:23 +0200 Subject: [PATCH 09/14] fix imports post transpilation --- scripts/upgradeable/transpile.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index fe14beefb65..ddc6e22373e 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -42,5 +42,8 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -N 'contracts/mocks/**/*' \ -q '@openzeppelin/' +# Fix import from initializable mocks (skipped by the transpiler) +sed -i -e 's/..\/proxy\/utils\/Initializable.sol/@openzeppelin\/contracts\/proxy\/utils\/Initializable.sol/g' contracts/mocks/**/*.sol + # delete compilation artifacts of vanilla code npm run clean From 19bbc622e5f8519c79353f182ab433e2a66bf55a Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 22:22:13 +0200 Subject: [PATCH 10/14] up --- scripts/upgradeable/transpile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index ddc6e22373e..85fbaeb90f1 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -43,7 +43,7 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -q '@openzeppelin/' # Fix import from initializable mocks (skipped by the transpiler) -sed -i -e 's/..\/proxy\/utils\/Initializable.sol/@openzeppelin\/contracts\/proxy\/utils\/Initializable.sol/g' contracts/mocks/**/*.sol +sed -i -e 's/..\/proxy\/utils\/Initializable.sol/@openzeppelin\/contracts\/proxy\/utils\/Initializable.sol/g' contracts/**/*.sol # delete compilation artifacts of vanilla code npm run clean From 80af5d53e2362441be2a03b7483ab1585ca3bee9 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 22:25:15 +0200 Subject: [PATCH 11/14] up --- scripts/upgradeable/transpile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index 85fbaeb90f1..dc735de1f17 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -43,7 +43,7 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -q '@openzeppelin/' # Fix import from initializable mocks (skipped by the transpiler) -sed -i -e 's/..\/proxy\/utils\/Initializable.sol/@openzeppelin\/contracts\/proxy\/utils\/Initializable.sol/g' contracts/**/*.sol +find contracts/mocks -type f -print0 | xargs -0 sed -i 's/\.\.\/proxy\/utils\/Initializable.sol/@openzeppelin\/contracts\/proxy\/utils\/Initializable.sol/g' # delete compilation artifacts of vanilla code npm run clean From 2c047d08aa4e6929778158d6524b7fdc4f21627a Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 23:17:00 +0200 Subject: [PATCH 12/14] set alias --- CHANGELOG.md | 1 - scripts/upgradeable/alias.patch | 400 +++++++++++++++++++++++++++++++ scripts/upgradeable/transpile.sh | 4 +- 3 files changed, 402 insertions(+), 3 deletions(-) create mode 100644 scripts/upgradeable/alias.patch diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ad05d955a3..4891ed39a91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,6 @@ ### Breaking changes -- `Initializable` and `UUPSUpgradeable` are no longer transpiled, and are now absent from the `@openzeppelin/contracts-upgradeable` package. Imports must be updated to get these files from `@openzeppelin/contracts` instead. - `SignerERC7702` is renamed as `SignerEIP7702`. Imports and inheritance must be updated to that new name and path. Behavior is unmodified. - Update minimum pragma to 0.8.24 in `Votes`, `VotesExtended`, `ERC20Votes`, `Strings`, `ERC1155URIStorage`, `MessageHashUtils`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721Wrapper`, `EIP712`, and `ERC7739`. ([#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726)) diff --git a/scripts/upgradeable/alias.patch b/scripts/upgradeable/alias.patch new file mode 100644 index 00000000000..8d17ba38105 --- /dev/null +++ b/scripts/upgradeable/alias.patch @@ -0,0 +1,400 @@ +diff --git a/contracts/proxy/utils/Initializable.sol b/contracts/proxy/utils/Initializable.sol +index 0d05fdb0e..e5927c938 100644 +--- a/contracts/proxy/utils/Initializable.sol ++++ b/contracts/proxy/utils/Initializable.sol +@@ -1,238 +1,5 @@ + // SPDX-License-Identifier: MIT +-// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol) + + pragma solidity ^0.8.20; + +-/** +- * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed +- * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an +- * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer +- * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. +- * +- * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be +- * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in +- * case an upgrade adds a module that needs to be initialized. +- * +- * For example: +- * +- * [.hljs-theme-light.nopadding] +- * ```solidity +- * contract MyToken is ERC20Upgradeable { +- * function initialize() initializer public { +- * __ERC20_init("MyToken", "MTK"); +- * } +- * } +- * +- * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { +- * function initializeV2() reinitializer(2) public { +- * __ERC20Permit_init("MyToken"); +- * } +- * } +- * ``` +- * +- * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as +- * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. +- * +- * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure +- * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. +- * +- * [CAUTION] +- * ==== +- * Avoid leaving a contract uninitialized. +- * +- * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation +- * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke +- * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: +- * +- * [.hljs-theme-light.nopadding] +- * ``` +- * /// @custom:oz-upgrades-unsafe-allow constructor +- * constructor() { +- * _disableInitializers(); +- * } +- * ``` +- * ==== +- */ +-abstract contract Initializable { +- /** +- * @dev Storage of the initializable contract. +- * +- * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions +- * when using with upgradeable contracts. +- * +- * @custom:storage-location erc7201:openzeppelin.storage.Initializable +- */ +- struct InitializableStorage { +- /** +- * @dev Indicates that the contract has been initialized. +- */ +- uint64 _initialized; +- /** +- * @dev Indicates that the contract is in the process of being initialized. +- */ +- bool _initializing; +- } +- +- // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) +- bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; +- +- /** +- * @dev The contract is already initialized. +- */ +- error InvalidInitialization(); +- +- /** +- * @dev The contract is not initializing. +- */ +- error NotInitializing(); +- +- /** +- * @dev Triggered when the contract has been initialized or reinitialized. +- */ +- event Initialized(uint64 version); +- +- /** +- * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, +- * `onlyInitializing` functions can be used to initialize parent contracts. +- * +- * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any +- * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in +- * production. +- * +- * Emits an {Initialized} event. +- */ +- modifier initializer() { +- // solhint-disable-next-line var-name-mixedcase +- InitializableStorage storage $ = _getInitializableStorage(); +- +- // Cache values to avoid duplicated sloads +- bool isTopLevelCall = !$._initializing; +- uint64 initialized = $._initialized; +- +- // Allowed calls: +- // - initialSetup: the contract is not in the initializing state and no previous version was +- // initialized +- // - construction: the contract is initialized at version 1 (no reinitialization) and the +- // current contract is just being deployed +- bool initialSetup = initialized == 0 && isTopLevelCall; +- bool construction = initialized == 1 && address(this).code.length == 0; +- +- if (!initialSetup && !construction) { +- revert InvalidInitialization(); +- } +- $._initialized = 1; +- if (isTopLevelCall) { +- $._initializing = true; +- } +- _; +- if (isTopLevelCall) { +- $._initializing = false; +- emit Initialized(1); +- } +- } +- +- /** +- * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the +- * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be +- * used to initialize parent contracts. +- * +- * A reinitializer may be used after the original initialization step. This is essential to configure modules that +- * are added through upgrades and that require initialization. +- * +- * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` +- * cannot be nested. If one is invoked in the context of another, execution will revert. +- * +- * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in +- * a contract, executing them in the right order is up to the developer or operator. +- * +- * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. +- * +- * Emits an {Initialized} event. +- */ +- modifier reinitializer(uint64 version) { +- // solhint-disable-next-line var-name-mixedcase +- InitializableStorage storage $ = _getInitializableStorage(); +- +- if ($._initializing || $._initialized >= version) { +- revert InvalidInitialization(); +- } +- $._initialized = version; +- $._initializing = true; +- _; +- $._initializing = false; +- emit Initialized(version); +- } +- +- /** +- * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the +- * {initializer} and {reinitializer} modifiers, directly or indirectly. +- */ +- modifier onlyInitializing() { +- _checkInitializing(); +- _; +- } +- +- /** +- * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. +- */ +- function _checkInitializing() internal view virtual { +- if (!_isInitializing()) { +- revert NotInitializing(); +- } +- } +- +- /** +- * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. +- * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized +- * to any version. It is recommended to use this to lock implementation contracts that are designed to be called +- * through proxies. +- * +- * Emits an {Initialized} event the first time it is successfully executed. +- */ +- function _disableInitializers() internal virtual { +- // solhint-disable-next-line var-name-mixedcase +- InitializableStorage storage $ = _getInitializableStorage(); +- +- if ($._initializing) { +- revert InvalidInitialization(); +- } +- if ($._initialized != type(uint64).max) { +- $._initialized = type(uint64).max; +- emit Initialized(type(uint64).max); +- } +- } +- +- /** +- * @dev Returns the highest version that has been initialized. See {reinitializer}. +- */ +- function _getInitializedVersion() internal view returns (uint64) { +- return _getInitializableStorage()._initialized; +- } +- +- /** +- * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. +- */ +- function _isInitializing() internal view returns (bool) { +- return _getInitializableStorage()._initializing; +- } +- +- /** +- * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location. +- * +- * NOTE: Consider following the ERC-7201 formula to derive storage locations. +- */ +- function _initializableStorageSlot() internal pure virtual returns (bytes32) { +- return INITIALIZABLE_STORAGE; +- } +- +- /** +- * @dev Returns a pointer to the storage namespace. +- */ +- // solhint-disable-next-line var-name-mixedcase +- function _getInitializableStorage() private pure returns (InitializableStorage storage $) { +- bytes32 slot = _initializableStorageSlot(); +- assembly { +- $.slot := slot +- } +- } +-} ++import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +\ No newline at end of file +diff --git a/contracts/proxy/utils/UUPSUpgradeable.sol b/contracts/proxy/utils/UUPSUpgradeable.sol +index 6be78251d..94448dee7 100644 +--- a/contracts/proxy/utils/UUPSUpgradeable.sol ++++ b/contracts/proxy/utils/UUPSUpgradeable.sol +@@ -1,148 +1,5 @@ + // SPDX-License-Identifier: MIT +-// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol) + + pragma solidity ^0.8.22; + +-import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol"; +-import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; +- +-/** +- * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an +- * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. +- * +- * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is +- * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing +- * `UUPSUpgradeable` with a custom implementation of upgrades. +- * +- * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. +- * +- * @custom:stateless +- */ +-abstract contract UUPSUpgradeable is IERC1822Proxiable { +- /// @custom:oz-upgrades-unsafe-allow state-variable-immutable +- address private immutable __self = address(this); +- +- /** +- * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` +- * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, +- * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. +- * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must +- * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function +- * during an upgrade. +- */ +- string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; +- +- /** +- * @dev The call is from an unauthorized context. +- */ +- error UUPSUnauthorizedCallContext(); +- +- /** +- * @dev The storage `slot` is unsupported as a UUID. +- */ +- error UUPSUnsupportedProxiableUUID(bytes32 slot); +- +- /** +- * @dev Check that the execution is being performed through a delegatecall call and that the execution context is +- * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case +- * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a +- * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to +- * fail. +- */ +- modifier onlyProxy() { +- _checkProxy(); +- _; +- } +- +- /** +- * @dev Check that the execution is not being performed through a delegate call. This allows a function to be +- * callable on the implementing contract but not through proxies. +- */ +- modifier notDelegated() { +- _checkNotDelegated(); +- _; +- } +- +- /** +- * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the +- * implementation. It is used to validate the implementation's compatibility when performing an upgrade. +- * +- * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks +- * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this +- * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. +- */ +- function proxiableUUID() external view virtual notDelegated returns (bytes32) { +- return ERC1967Utils.IMPLEMENTATION_SLOT; +- } +- +- /** +- * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call +- * encoded in `data`. +- * +- * Calls {_authorizeUpgrade}. +- * +- * Emits an {Upgraded} event. +- * +- * @custom:oz-upgrades-unsafe-allow-reachable delegatecall +- */ +- function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { +- _authorizeUpgrade(newImplementation); +- _upgradeToAndCallUUPS(newImplementation, data); +- } +- +- /** +- * @dev Reverts if the execution is not performed via delegatecall or the execution +- * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. +- */ +- function _checkProxy() internal view virtual { +- if ( +- address(this) == __self || // Must be called through delegatecall +- ERC1967Utils.getImplementation() != __self // Must be called through an active proxy +- ) { +- revert UUPSUnauthorizedCallContext(); +- } +- } +- +- /** +- * @dev Reverts if the execution is performed via delegatecall. +- * See {notDelegated}. +- */ +- function _checkNotDelegated() internal view virtual { +- if (address(this) != __self) { +- // Must not be called through delegatecall +- revert UUPSUnauthorizedCallContext(); +- } +- } +- +- /** +- * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by +- * {upgradeToAndCall}. +- * +- * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. +- * +- * ```solidity +- * function _authorizeUpgrade(address) internal onlyOwner {} +- * ``` +- */ +- function _authorizeUpgrade(address newImplementation) internal virtual; +- +- /** +- * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. +- * +- * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value +- * is expected to be the implementation slot in ERC-1967. +- * +- * Emits an {IERC1967-Upgraded} event. +- */ +- function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { +- try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { +- if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { +- revert UUPSUnsupportedProxiableUUID(slot); +- } +- ERC1967Utils.upgradeToAndCall(newImplementation, data); +- } catch { +- // The implementation is not UUPS +- revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); +- } +- } +-} ++import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; +\ No newline at end of file diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index dc735de1f17..afa1c2d9067 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -42,8 +42,8 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -N 'contracts/mocks/**/*' \ -q '@openzeppelin/' -# Fix import from initializable mocks (skipped by the transpiler) -find contracts/mocks -type f -print0 | xargs -0 sed -i 's/\.\.\/proxy\/utils\/Initializable.sol/@openzeppelin\/contracts\/proxy\/utils\/Initializable.sol/g' +# create alias to initializable and uups upgradeable +git apply -3 "$DIRNAME/alias.patch" # delete compilation artifacts of vanilla code npm run clean From 8dc409476ad217f883d81c77de9fe976e9ee7d3b Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 18 Sep 2025 23:42:49 +0200 Subject: [PATCH 13/14] cp alias directly --- scripts/upgradeable/alias.patch | 400 ------------------ scripts/upgradeable/alias/Initializable.sol | 5 + scripts/upgradeable/alias/UUPSUpgradeable.sol | 5 + scripts/upgradeable/transpile.sh | 4 +- 4 files changed, 12 insertions(+), 402 deletions(-) delete mode 100644 scripts/upgradeable/alias.patch create mode 100644 scripts/upgradeable/alias/Initializable.sol create mode 100644 scripts/upgradeable/alias/UUPSUpgradeable.sol diff --git a/scripts/upgradeable/alias.patch b/scripts/upgradeable/alias.patch deleted file mode 100644 index 8d17ba38105..00000000000 --- a/scripts/upgradeable/alias.patch +++ /dev/null @@ -1,400 +0,0 @@ -diff --git a/contracts/proxy/utils/Initializable.sol b/contracts/proxy/utils/Initializable.sol -index 0d05fdb0e..e5927c938 100644 ---- a/contracts/proxy/utils/Initializable.sol -+++ b/contracts/proxy/utils/Initializable.sol -@@ -1,238 +1,5 @@ - // SPDX-License-Identifier: MIT --// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol) - - pragma solidity ^0.8.20; - --/** -- * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed -- * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an -- * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer -- * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. -- * -- * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be -- * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in -- * case an upgrade adds a module that needs to be initialized. -- * -- * For example: -- * -- * [.hljs-theme-light.nopadding] -- * ```solidity -- * contract MyToken is ERC20Upgradeable { -- * function initialize() initializer public { -- * __ERC20_init("MyToken", "MTK"); -- * } -- * } -- * -- * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { -- * function initializeV2() reinitializer(2) public { -- * __ERC20Permit_init("MyToken"); -- * } -- * } -- * ``` -- * -- * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as -- * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. -- * -- * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure -- * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. -- * -- * [CAUTION] -- * ==== -- * Avoid leaving a contract uninitialized. -- * -- * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation -- * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke -- * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: -- * -- * [.hljs-theme-light.nopadding] -- * ``` -- * /// @custom:oz-upgrades-unsafe-allow constructor -- * constructor() { -- * _disableInitializers(); -- * } -- * ``` -- * ==== -- */ --abstract contract Initializable { -- /** -- * @dev Storage of the initializable contract. -- * -- * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions -- * when using with upgradeable contracts. -- * -- * @custom:storage-location erc7201:openzeppelin.storage.Initializable -- */ -- struct InitializableStorage { -- /** -- * @dev Indicates that the contract has been initialized. -- */ -- uint64 _initialized; -- /** -- * @dev Indicates that the contract is in the process of being initialized. -- */ -- bool _initializing; -- } -- -- // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) -- bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; -- -- /** -- * @dev The contract is already initialized. -- */ -- error InvalidInitialization(); -- -- /** -- * @dev The contract is not initializing. -- */ -- error NotInitializing(); -- -- /** -- * @dev Triggered when the contract has been initialized or reinitialized. -- */ -- event Initialized(uint64 version); -- -- /** -- * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, -- * `onlyInitializing` functions can be used to initialize parent contracts. -- * -- * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any -- * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in -- * production. -- * -- * Emits an {Initialized} event. -- */ -- modifier initializer() { -- // solhint-disable-next-line var-name-mixedcase -- InitializableStorage storage $ = _getInitializableStorage(); -- -- // Cache values to avoid duplicated sloads -- bool isTopLevelCall = !$._initializing; -- uint64 initialized = $._initialized; -- -- // Allowed calls: -- // - initialSetup: the contract is not in the initializing state and no previous version was -- // initialized -- // - construction: the contract is initialized at version 1 (no reinitialization) and the -- // current contract is just being deployed -- bool initialSetup = initialized == 0 && isTopLevelCall; -- bool construction = initialized == 1 && address(this).code.length == 0; -- -- if (!initialSetup && !construction) { -- revert InvalidInitialization(); -- } -- $._initialized = 1; -- if (isTopLevelCall) { -- $._initializing = true; -- } -- _; -- if (isTopLevelCall) { -- $._initializing = false; -- emit Initialized(1); -- } -- } -- -- /** -- * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the -- * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be -- * used to initialize parent contracts. -- * -- * A reinitializer may be used after the original initialization step. This is essential to configure modules that -- * are added through upgrades and that require initialization. -- * -- * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` -- * cannot be nested. If one is invoked in the context of another, execution will revert. -- * -- * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in -- * a contract, executing them in the right order is up to the developer or operator. -- * -- * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. -- * -- * Emits an {Initialized} event. -- */ -- modifier reinitializer(uint64 version) { -- // solhint-disable-next-line var-name-mixedcase -- InitializableStorage storage $ = _getInitializableStorage(); -- -- if ($._initializing || $._initialized >= version) { -- revert InvalidInitialization(); -- } -- $._initialized = version; -- $._initializing = true; -- _; -- $._initializing = false; -- emit Initialized(version); -- } -- -- /** -- * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the -- * {initializer} and {reinitializer} modifiers, directly or indirectly. -- */ -- modifier onlyInitializing() { -- _checkInitializing(); -- _; -- } -- -- /** -- * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. -- */ -- function _checkInitializing() internal view virtual { -- if (!_isInitializing()) { -- revert NotInitializing(); -- } -- } -- -- /** -- * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. -- * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized -- * to any version. It is recommended to use this to lock implementation contracts that are designed to be called -- * through proxies. -- * -- * Emits an {Initialized} event the first time it is successfully executed. -- */ -- function _disableInitializers() internal virtual { -- // solhint-disable-next-line var-name-mixedcase -- InitializableStorage storage $ = _getInitializableStorage(); -- -- if ($._initializing) { -- revert InvalidInitialization(); -- } -- if ($._initialized != type(uint64).max) { -- $._initialized = type(uint64).max; -- emit Initialized(type(uint64).max); -- } -- } -- -- /** -- * @dev Returns the highest version that has been initialized. See {reinitializer}. -- */ -- function _getInitializedVersion() internal view returns (uint64) { -- return _getInitializableStorage()._initialized; -- } -- -- /** -- * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. -- */ -- function _isInitializing() internal view returns (bool) { -- return _getInitializableStorage()._initializing; -- } -- -- /** -- * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location. -- * -- * NOTE: Consider following the ERC-7201 formula to derive storage locations. -- */ -- function _initializableStorageSlot() internal pure virtual returns (bytes32) { -- return INITIALIZABLE_STORAGE; -- } -- -- /** -- * @dev Returns a pointer to the storage namespace. -- */ -- // solhint-disable-next-line var-name-mixedcase -- function _getInitializableStorage() private pure returns (InitializableStorage storage $) { -- bytes32 slot = _initializableStorageSlot(); -- assembly { -- $.slot := slot -- } -- } --} -+import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -\ No newline at end of file -diff --git a/contracts/proxy/utils/UUPSUpgradeable.sol b/contracts/proxy/utils/UUPSUpgradeable.sol -index 6be78251d..94448dee7 100644 ---- a/contracts/proxy/utils/UUPSUpgradeable.sol -+++ b/contracts/proxy/utils/UUPSUpgradeable.sol -@@ -1,148 +1,5 @@ - // SPDX-License-Identifier: MIT --// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol) - - pragma solidity ^0.8.22; - --import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol"; --import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; -- --/** -- * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an -- * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. -- * -- * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is -- * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing -- * `UUPSUpgradeable` with a custom implementation of upgrades. -- * -- * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. -- * -- * @custom:stateless -- */ --abstract contract UUPSUpgradeable is IERC1822Proxiable { -- /// @custom:oz-upgrades-unsafe-allow state-variable-immutable -- address private immutable __self = address(this); -- -- /** -- * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` -- * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, -- * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. -- * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must -- * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function -- * during an upgrade. -- */ -- string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; -- -- /** -- * @dev The call is from an unauthorized context. -- */ -- error UUPSUnauthorizedCallContext(); -- -- /** -- * @dev The storage `slot` is unsupported as a UUID. -- */ -- error UUPSUnsupportedProxiableUUID(bytes32 slot); -- -- /** -- * @dev Check that the execution is being performed through a delegatecall call and that the execution context is -- * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case -- * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a -- * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to -- * fail. -- */ -- modifier onlyProxy() { -- _checkProxy(); -- _; -- } -- -- /** -- * @dev Check that the execution is not being performed through a delegate call. This allows a function to be -- * callable on the implementing contract but not through proxies. -- */ -- modifier notDelegated() { -- _checkNotDelegated(); -- _; -- } -- -- /** -- * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the -- * implementation. It is used to validate the implementation's compatibility when performing an upgrade. -- * -- * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks -- * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this -- * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. -- */ -- function proxiableUUID() external view virtual notDelegated returns (bytes32) { -- return ERC1967Utils.IMPLEMENTATION_SLOT; -- } -- -- /** -- * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call -- * encoded in `data`. -- * -- * Calls {_authorizeUpgrade}. -- * -- * Emits an {Upgraded} event. -- * -- * @custom:oz-upgrades-unsafe-allow-reachable delegatecall -- */ -- function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { -- _authorizeUpgrade(newImplementation); -- _upgradeToAndCallUUPS(newImplementation, data); -- } -- -- /** -- * @dev Reverts if the execution is not performed via delegatecall or the execution -- * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. -- */ -- function _checkProxy() internal view virtual { -- if ( -- address(this) == __self || // Must be called through delegatecall -- ERC1967Utils.getImplementation() != __self // Must be called through an active proxy -- ) { -- revert UUPSUnauthorizedCallContext(); -- } -- } -- -- /** -- * @dev Reverts if the execution is performed via delegatecall. -- * See {notDelegated}. -- */ -- function _checkNotDelegated() internal view virtual { -- if (address(this) != __self) { -- // Must not be called through delegatecall -- revert UUPSUnauthorizedCallContext(); -- } -- } -- -- /** -- * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by -- * {upgradeToAndCall}. -- * -- * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. -- * -- * ```solidity -- * function _authorizeUpgrade(address) internal onlyOwner {} -- * ``` -- */ -- function _authorizeUpgrade(address newImplementation) internal virtual; -- -- /** -- * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. -- * -- * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value -- * is expected to be the implementation slot in ERC-1967. -- * -- * Emits an {IERC1967-Upgraded} event. -- */ -- function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { -- try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { -- if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { -- revert UUPSUnsupportedProxiableUUID(slot); -- } -- ERC1967Utils.upgradeToAndCall(newImplementation, data); -- } catch { -- // The implementation is not UUPS -- revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); -- } -- } --} -+import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; -\ No newline at end of file diff --git a/scripts/upgradeable/alias/Initializable.sol b/scripts/upgradeable/alias/Initializable.sol new file mode 100644 index 00000000000..b5f26b5e2f7 --- /dev/null +++ b/scripts/upgradeable/alias/Initializable.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; diff --git a/scripts/upgradeable/alias/UUPSUpgradeable.sol b/scripts/upgradeable/alias/UUPSUpgradeable.sol new file mode 100644 index 00000000000..e869ba6ba96 --- /dev/null +++ b/scripts/upgradeable/alias/UUPSUpgradeable.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.22; + +import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh index afa1c2d9067..daf4da7270a 100644 --- a/scripts/upgradeable/transpile.sh +++ b/scripts/upgradeable/transpile.sh @@ -42,8 +42,8 @@ npx @openzeppelin/upgrade-safe-transpiler -D \ -N 'contracts/mocks/**/*' \ -q '@openzeppelin/' -# create alias to initializable and uups upgradeable -git apply -3 "$DIRNAME/alias.patch" +# create alias to Initializable and UUPSUpgradeable +cp $DIRNAME/alias/*.sol contracts/proxy/utils/. # delete compilation artifacts of vanilla code npm run clean From 4c473b5ef60607e7ec5d8cb5950faa0e970483c5 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 19 Sep 2025 09:22:17 +0200 Subject: [PATCH 14/14] add deprecation notice to the changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4891ed39a91..f96956e0c1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Deprecation +- `Initializable` and `UUPSUpgradeable` are no longer transpiled. An alias is present in the `@openzeppelin/contracts-upgradeable` package that redirect to the corresponding file in `@openzeppelin/contracts`. These alias will be removed in the next major release. Developers are advised to update their imports to get these files directly from the `@openzeppelin/contracts` package. - `ECDSA` signature malleability protection is partly deprecated. See documentation for more details. ## 5.4.0 (2025-07-17)