Enable partial transpilation for upgradeable package (#4628)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
pull/4637/head
Francisco 1 year ago committed by GitHub
parent 970a7184ad
commit 58463a9823
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .changeset/grumpy-poets-rush.md
  2. 2
      .github/actions/setup/action.yml
  3. 3
      .github/workflows/checks.yml
  4. 36
      contracts/mocks/Stateless.sol
  5. 2
      contracts/package.json
  6. 2
      contracts/proxy/utils/UUPSUpgradeable.sol
  7. 2
      contracts/token/ERC1155/utils/ERC1155Holder.sol
  8. 2
      contracts/token/ERC721/utils/ERC721Holder.sol
  9. 2
      contracts/utils/Context.sol
  10. 2
      contracts/utils/Multicall.sol
  11. 2
      contracts/utils/introspection/ERC165.sol
  12. 1
      hardhat.config.js
  13. 97
      package-lock.json
  14. 6
      package.json
  15. 17
      scripts/prepack.sh
  16. 15
      scripts/prepare-contracts-package.sh
  17. 10
      scripts/prepare.sh
  18. 2
      scripts/remove-ignored-artifacts.js
  19. 9
      scripts/upgradeable/transpile.sh
  20. 24
      scripts/upgradeable/upgradeable.patch

@ -0,0 +1,5 @@
---
'openzeppelin-solidity': major
---
Upgradeable Contracts: No longer transpile interfaces, libraries, and stateless contracts.

@ -15,5 +15,3 @@ runs:
run: npm ci
shell: bash
if: steps.cache.outputs.cache-hit != 'true'
env:
SKIP_COMPILE: true

@ -56,6 +56,9 @@ jobs:
fetch-depth: 0 # Include history so patch conflicts are resolved automatically
- name: Set up environment
uses: ./.github/actions/setup
- name: Copy non-upgradeable contracts as dependency
run:
cp -rnT contracts node_modules/@openzeppelin/contracts
- name: Transpile to upgradeable
run: bash scripts/upgradeable/transpile.sh
- name: Run tests

@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// We keep these imports and a dummy contract just to we can run the test suite after transpilation.
import {Address} from "../utils/Address.sol";
import {Arrays} from "../utils/Arrays.sol";
import {AuthorityUtils} from "../access/manager/AuthorityUtils.sol";
import {Base64} from "../utils/Base64.sol";
import {BitMaps} from "../utils/structs/BitMaps.sol";
import {Checkpoints} from "../utils/structs/Checkpoints.sol";
import {Clones} from "../proxy/Clones.sol";
import {Create2} from "../utils/Create2.sol";
import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol";
import {ECDSA} from "../utils/cryptography/ECDSA.sol";
import {EnumerableMap} from "../utils/structs/EnumerableMap.sol";
import {EnumerableSet} from "../utils/structs/EnumerableSet.sol";
import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
import {ERC165Checker} from "../utils/introspection/ERC165Checker.sol";
import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol";
import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol";
import {Math} from "../utils/math/Math.sol";
import {MerkleProof} from "../utils/cryptography/MerkleProof.sol";
import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol";
import {SafeCast} from "../utils/math/SafeCast.sol";
import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol";
import {ShortStrings} from "../utils/ShortStrings.sol";
import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol";
import {SignedMath} from "../utils/math/SignedMath.sol";
import {StorageSlot} from "../utils/StorageSlot.sol";
import {Strings} from "../utils/Strings.sol";
import {Time} from "../utils/types/Time.sol";
contract Dummy1234 {}

@ -8,7 +8,7 @@
"!/mocks/**/*"
],
"scripts": {
"prepare": "bash ../scripts/prepare-contracts-package.sh",
"prepack": "bash ../scripts/prepack.sh",
"prepare-docs": "cd ..; npm run prepare-docs"
},
"repository": {

@ -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

@ -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 {
/**

@ -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 {
/**

@ -12,6 +12,8 @@ pragma solidity ^0.8.20;
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*
* @custom:stateless
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {

@ -7,6 +7,8 @@ import {Address} from "./Address.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* @custom:stateless
*/
abstract contract Multicall {
/**

@ -16,6 +16,8 @@ import {IERC165} from "./IERC165.sol";
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* @custom:stateless
*/
abstract contract ERC165 is IERC165 {
/**

@ -93,6 +93,7 @@ module.exports = {
},
},
exposed: {
imports: true,
initializers: true,
exclude: ['vendor/**/*'],
},

97
package-lock.json generated

@ -18,6 +18,7 @@
"@nomiclabs/hardhat-web3": "^2.0.0",
"@openzeppelin/docs-utils": "^0.1.4",
"@openzeppelin/test-helpers": "^0.5.13",
"@openzeppelin/upgrade-safe-transpiler": "^0.3.30",
"@openzeppelin/upgrades-core": "^1.20.6",
"array.prototype.at": "^1.1.1",
"chai": "^4.2.0",
@ -29,7 +30,7 @@
"glob": "^10.3.5",
"graphlib": "^2.1.8",
"hardhat": "^2.9.1",
"hardhat-exposed": "^0.3.11",
"hardhat-exposed": "^0.3.12-1",
"hardhat-gas-reporter": "^1.0.4",
"hardhat-ignore-warnings": "^0.2.0",
"keccak256": "^1.0.2",
@ -2407,6 +2408,91 @@
"semver": "bin/semver"
}
},
"node_modules/@openzeppelin/upgrade-safe-transpiler": {
"version": "0.3.30",
"resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.3.30.tgz",
"integrity": "sha512-nkJ4r+W+FUp0eAvE18uHh/smwD1NS3KLAGJ59+Vgmx3VlCvCDNaS0rTJ1FpwxDYD3J0Whx0ZVtHz2ySq4YsnNQ==",
"dev": true,
"dependencies": {
"ajv": "^8.0.0",
"compare-versions": "^6.0.0",
"ethereum-cryptography": "^2.0.0",
"lodash": "^4.17.20",
"minimatch": "^9.0.0",
"minimist": "^1.2.5",
"solidity-ast": "^0.4.51"
},
"bin": {
"upgrade-safe-transpiler": "dist/cli.js"
}
},
"node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/ethereum-cryptography": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz",
"integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==",
"dev": true,
"dependencies": {
"@noble/curves": "1.1.0",
"@noble/hashes": "1.3.1",
"@scure/bip32": "1.3.1",
"@scure/bip39": "1.2.1"
}
},
"node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
"node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@openzeppelin/upgrades-core": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.29.0.tgz",
@ -8564,13 +8650,13 @@
}
},
"node_modules/hardhat-exposed": {
"version": "0.3.12",
"resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.12.tgz",
"integrity": "sha512-op/shZ6YQcQzPzxT4h0oD3x7M6fBna2rM/YUuhZLzJOtsu/DF9xK2o2thPSR1LAz8enx3wbjJZxl7b2+QXyDYw==",
"version": "0.3.12-1",
"resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.12-1.tgz",
"integrity": "sha512-hDhh+wC6usu/OPT4v6hi+JdBxZJDgi6gVAw/45ApY7rgODCqpan7+8GuVwOtu0YK/9wPN9Y065MzAVFqJtylgA==",
"dev": true,
"dependencies": {
"micromatch": "^4.0.4",
"solidity-ast": "^0.4.25"
"solidity-ast": "^0.4.52"
},
"peerDependencies": {
"hardhat": "^2.3.0"
@ -16919,6 +17005,7 @@
},
"scripts/solhint-custom": {
"name": "solhint-plugin-openzeppelin",
"version": "0.0.0",
"dev": true
}
}

@ -2,9 +2,9 @@
"name": "openzeppelin-solidity",
"description": "Secure Smart Contract library for Solidity",
"version": "4.9.2",
"private": true,
"files": [
"/contracts/**/*.sol",
"/build/contracts/*.json",
"!/contracts/mocks/**/*"
],
"scripts": {
@ -20,7 +20,6 @@
"lint:sol": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --check && solhint '{contracts,test}/**/*.sol'",
"lint:sol:fix": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write",
"clean": "hardhat clean && rimraf build contracts/build",
"prepare": "scripts/prepare.sh",
"prepack": "scripts/prepack.sh",
"generate": "scripts/generate/run.js",
"release": "scripts/release/release.sh",
@ -59,6 +58,7 @@
"@nomiclabs/hardhat-web3": "^2.0.0",
"@openzeppelin/docs-utils": "^0.1.4",
"@openzeppelin/test-helpers": "^0.5.13",
"@openzeppelin/upgrade-safe-transpiler": "^0.3.30",
"@openzeppelin/upgrades-core": "^1.20.6",
"array.prototype.at": "^1.1.1",
"chai": "^4.2.0",
@ -70,7 +70,7 @@
"glob": "^10.3.5",
"graphlib": "^2.1.8",
"hardhat": "^2.9.1",
"hardhat-exposed": "^0.3.11",
"hardhat-exposed": "^0.3.12-1",
"hardhat-gas-reporter": "^1.0.4",
"hardhat-ignore-warnings": "^0.2.0",
"keccak256": "^1.0.2",

@ -4,9 +4,20 @@ set -euo pipefail
shopt -s globstar
# cross platform `mkdir -p`
node -e 'fs.mkdirSync("build/contracts", { recursive: true })'
mkdirp() {
node -e "fs.mkdirSync('$1', { recursive: true })"
}
cp artifacts/contracts/**/*.json build/contracts
rm build/contracts/*.dbg.json
# cd to the root of the repo
cd "$(git rev-parse --show-toplevel)"
npm run clean
env COMPILE_MODE=production npm run compile
mkdirp contracts/build/contracts
cp artifacts/contracts/**/*.json contracts/build/contracts
rm contracts/build/contracts/*.dbg.json
node scripts/remove-ignored-artifacts.js
cp README.md contracts/

@ -1,15 +0,0 @@
#!/usr/bin/env bash
# cd to the root of the repo
cd "$(git rev-parse --show-toplevel)"
# avoids re-compilation during publishing of both packages
if [[ ! -v ALREADY_COMPILED ]]; then
npm run clean
npm run prepare
npm run prepack
fi
cp README.md contracts/
mkdir contracts/build contracts/build/contracts
cp -r build/contracts/*.json contracts/build/contracts

@ -1,10 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
if [ "${SKIP_COMPILE:-}" == true ]; then
exit
fi
npm run clean
env COMPILE_MODE=production npm run compile

@ -23,7 +23,7 @@ const ignorePatternsSubtrees = ignorePatterns
.concat(ignorePatterns.map(pat => path.join(pat, '**/*')))
.map(p => p.replace(/^\//, ''));
const artifactsDir = 'build/contracts';
const artifactsDir = 'contracts/build/contracts';
const buildinfo = 'artifacts/build-info';
const filenames = fs.readdirSync(buildinfo);

@ -2,9 +2,12 @@
set -euo pipefail -x
VERSION="$(jq -r .version contracts/package.json)"
DIRNAME="$(dirname -- "${BASH_SOURCE[0]}")"
bash "$DIRNAME/patch-apply.sh"
sed -i "s/<package-version>/$VERSION/g" contracts/package.json
git add contracts/package.json
npm run clean
npm run compile
@ -24,7 +27,8 @@ fi
# -p: emit public initializer
# -n: use namespaces
# -N: exclude from namespaces transformation
npx @openzeppelin/upgrade-safe-transpiler@latest -D \
# -q: partial transpilation using @openzeppelin/contracts as peer project
npx @openzeppelin/upgrade-safe-transpiler -D \
-b "$build_info" \
-i contracts/proxy/utils/Initializable.sol \
-x 'contracts-exposed/**/*' \
@ -36,7 +40,8 @@ npx @openzeppelin/upgrade-safe-transpiler@latest -D \
-x '!contracts/proxy/beacon/IBeacon.sol' \
-p 'contracts/**/presets/**/*' \
-n \
-N 'contracts/mocks/**/*'
-N 'contracts/mocks/**/*' \
-q '@openzeppelin/'
# delete compilation artifacts of vanilla code
npm run clean

@ -59,7 +59,7 @@ index ff596b0c3..000000000
-<!-- Make sure that you have reviewed the OpenZeppelin Contracts Contributor Guidelines. -->
-<!-- https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md -->
diff --git a/README.md b/README.md
index 53c29e5f8..666a667d3 100644
index 549891e3f..a6b24078e 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,9 @@
@ -81,8 +81,8 @@ index 53c29e5f8..666a667d3 100644
```
#### Foundry (git)
@@ -40,10 +43,10 @@ $ npm install @openzeppelin/contracts
> **Warning** Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch.
@@ -42,10 +45,10 @@ $ npm install @openzeppelin/contracts
> Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch.
```
-$ forge install OpenZeppelin/openzeppelin-contracts
@ -94,7 +94,7 @@ index 53c29e5f8..666a667d3 100644
### Usage
@@ -52,10 +55,11 @@ Once installed, you can use the contracts in the library by importing them:
@@ -54,10 +57,11 @@ Once installed, you can use the contracts in the library by importing them:
```solidity
pragma solidity ^0.8.20;
@ -110,7 +110,7 @@ index 53c29e5f8..666a667d3 100644
}
```
diff --git a/contracts/package.json b/contracts/package.json
index df141192d..1cf90ad14 100644
index 9017953ca..f51c1d38b 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -1,5 +1,5 @@
@ -129,6 +129,16 @@ index df141192d..1cf90ad14 100644
},
"keywords": [
"solidity",
@@ -28,5 +28,8 @@
"bugs": {
"url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues"
},
- "homepage": "https://openzeppelin.com/contracts/"
+ "homepage": "https://openzeppelin.com/contracts/",
+ "peerDependencies": {
+ "@openzeppelin/contracts": "<package-version>"
+ }
}
diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol
index 644f6f531..ab8ba05ff 100644
--- a/contracts/utils/cryptography/EIP712.sol
@ -297,10 +307,10 @@ index 644f6f531..ab8ba05ff 100644
}
}
diff --git a/package.json b/package.json
index e6804c4cd..612ec513e 100644
index 3a1617c09..97e59c2d9 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,7 @@
@@ -32,7 +32,7 @@
},
"repository": {
"type": "git",

Loading…
Cancel
Save