@openzeppelin/wizard 0.5.4 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +13 -3
  2. package/dist/account.d.ts +20 -0
  3. package/dist/account.d.ts.map +1 -0
  4. package/dist/account.js +256 -0
  5. package/dist/account.js.map +1 -0
  6. package/dist/api.d.ts +12 -7
  7. package/dist/api.d.ts.map +1 -1
  8. package/dist/api.js +6 -1
  9. package/dist/api.js.map +1 -1
  10. package/dist/build-generic.d.ts +4 -0
  11. package/dist/build-generic.d.ts.map +1 -1
  12. package/dist/build-generic.js +3 -0
  13. package/dist/build-generic.js.map +1 -1
  14. package/dist/environments/hardhat/package-lock.json +3 -3
  15. package/dist/environments/hardhat/upgradeable/package-lock.json +7 -7
  16. package/dist/erc20.js +1 -1
  17. package/dist/erc20.js.map +1 -1
  18. package/dist/generate/account.d.ts +3 -0
  19. package/dist/generate/account.d.ts.map +1 -0
  20. package/dist/generate/account.js +21 -0
  21. package/dist/generate/account.js.map +1 -0
  22. package/dist/generate/sources.d.ts.map +1 -1
  23. package/dist/generate/sources.js +6 -0
  24. package/dist/generate/sources.js.map +1 -1
  25. package/dist/governor.d.ts +1 -1
  26. package/dist/governor.d.ts.map +1 -1
  27. package/dist/governor.js +10 -10
  28. package/dist/governor.js.map +1 -1
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/kind.js +2 -1
  34. package/dist/kind.js.map +1 -1
  35. package/dist/print.d.ts.map +1 -1
  36. package/dist/print.js +2 -1
  37. package/dist/print.js.map +1 -1
  38. package/dist/set-upgradeable.d.ts +1 -0
  39. package/dist/set-upgradeable.d.ts.map +1 -1
  40. package/dist/set-upgradeable.js +13 -2
  41. package/dist/set-upgradeable.js.map +1 -1
  42. package/dist/signer.d.ts +39 -0
  43. package/dist/signer.d.ts.map +1 -0
  44. package/dist/signer.js +115 -0
  45. package/dist/signer.js.map +1 -0
  46. package/dist/solidity-version.json +1 -1
  47. package/dist/stablecoin.js +2 -2
  48. package/dist/stablecoin.js.map +1 -1
  49. package/dist/test.js +17 -6
  50. package/dist/test.js.map +1 -1
  51. package/dist/utils/sanitize.d.ts +2 -0
  52. package/dist/utils/sanitize.d.ts.map +1 -0
  53. package/dist/utils/sanitize.js +9 -0
  54. package/dist/utils/sanitize.js.map +1 -0
  55. package/dist/zip-foundry.js +4 -4
  56. package/package.json +6 -7
  57. package/src/account.ts +296 -0
  58. package/src/api.ts +16 -7
  59. package/src/build-generic.ts +6 -0
  60. package/src/environments/hardhat/package-lock.json +3 -3
  61. package/src/environments/hardhat/upgradeable/package-lock.json +7 -7
  62. package/src/erc20.ts +1 -1
  63. package/src/generate/account.ts +20 -0
  64. package/src/generate/sources.ts +7 -0
  65. package/src/governor.ts +13 -12
  66. package/src/index.ts +1 -1
  67. package/src/kind.ts +2 -1
  68. package/src/print.ts +2 -1
  69. package/src/set-upgradeable.ts +18 -2
  70. package/src/signer.ts +124 -0
  71. package/src/solidity-version.json +1 -1
  72. package/src/stablecoin.ts +2 -2
  73. package/src/test.ts +17 -5
  74. package/src/utils/sanitize.ts +6 -0
  75. package/src/zip-foundry.ts +4 -4
package/src/governor.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { supportsInterface } from './common-functions';
2
2
  import type { CommonOptions } from './common-options';
3
3
  import { withCommonDefaults, defaults as commonDefaults } from './common-options';
4
- import type { Contract } from './contract';
4
+ import type { Contract, ImportContract } from './contract';
5
5
  import { ContractBuilder } from './contract';
6
6
  import { OptionsError } from './error';
7
7
  import { setAccessControl } from './set-access-control';
8
8
  import { printContract } from './print';
9
9
  import { setInfo } from './set-info';
10
- import { setUpgradeable } from './set-upgradeable';
10
+ import { setUpgradeableGovernor } from './set-upgradeable';
11
11
  import { defineFunctions } from './utils/define-functions';
12
12
  import { durationToBlocks, durationToTimestamp } from './utils/duration';
13
13
  import { clockModeDefault, type ClockMode } from './set-clock-mode';
@@ -61,8 +61,8 @@ export interface GovernorOptions extends CommonOptions {
61
61
  settings?: boolean;
62
62
  }
63
63
 
64
- export function isAccessControlRequired(opts: Partial<GovernorOptions>): boolean {
65
- return opts.upgradeable === 'uups';
64
+ export function isAccessControlRequired(_: Partial<GovernorOptions>): boolean {
65
+ return false;
66
66
  }
67
67
 
68
68
  function withDefaults(opts: GovernorOptions): Required<GovernorOptions> {
@@ -99,21 +99,19 @@ export function buildGovernor(opts: GovernorOptions): Contract {
99
99
  addTimelock(c, allOpts);
100
100
 
101
101
  setAccessControl(c, allOpts.access);
102
- setUpgradeable(c, allOpts.upgradeable, allOpts.access);
102
+ setUpgradeableGovernor(c, allOpts.upgradeable);
103
103
  setInfo(c, allOpts.info);
104
104
 
105
105
  return c;
106
106
  }
107
107
 
108
+ const Governor: ImportContract = {
109
+ name: 'Governor',
110
+ path: '@openzeppelin/contracts/governance/Governor.sol',
111
+ };
112
+
108
113
  function addBase(c: ContractBuilder, { name }: GovernorOptions) {
109
- const Governor = {
110
- name: 'Governor',
111
- path: '@openzeppelin/contracts/governance/Governor.sol',
112
- };
113
114
  c.addParent(Governor, [name]);
114
- c.addOverride(Governor, functions.votingDelay);
115
- c.addOverride(Governor, functions.votingPeriod);
116
- c.addOverride(Governor, functions.quorum);
117
115
  c.addOverride(Governor, functions.state);
118
116
  c.addOverride(Governor, functions.propose);
119
117
  c.addOverride(Governor, functions.proposalNeedsQueuing);
@@ -221,6 +219,7 @@ function setVotingParameters(c: ContractBuilder, opts: Required<GovernorOptions>
221
219
  } else {
222
220
  c.setFunctionBody([`return ${delayBlocks.value}; // ${delayBlocks.note}`], functions.votingDelay);
223
221
  }
222
+ c.addOverride(Governor, functions.votingDelay);
224
223
 
225
224
  const periodBlocks = getVotingPeriod(opts);
226
225
  if ('lit' in periodBlocks) {
@@ -228,6 +227,7 @@ function setVotingParameters(c: ContractBuilder, opts: Required<GovernorOptions>
228
227
  } else {
229
228
  c.setFunctionBody([`return ${periodBlocks.value}; // ${periodBlocks.note}`], functions.votingPeriod);
230
229
  }
230
+ c.addOverride(Governor, functions.votingPeriod);
231
231
  }
232
232
 
233
233
  function setProposalThreshold(c: ContractBuilder, opts: Required<GovernorOptions>) {
@@ -308,6 +308,7 @@ function addQuorum(c: ContractBuilder, opts: Required<GovernorOptions>) {
308
308
  : `return ${opts.quorumAbsolute}e${opts.decimals};`;
309
309
 
310
310
  c.setFunctionBody([returnStatement], functions.quorum, 'pure');
311
+ c.addOverride(Governor, functions.quorum);
311
312
  }
312
313
  }
313
314
 
package/src/index.ts CHANGED
@@ -19,6 +19,6 @@ export { OptionsError } from './error';
19
19
  export type { Kind } from './kind';
20
20
  export { sanitizeKind } from './kind';
21
21
 
22
- export { erc20, erc721, erc1155, stablecoin, realWorldAsset, governor, custom } from './api';
22
+ export { erc20, erc721, erc1155, stablecoin, realWorldAsset, account, governor, custom } from './api';
23
23
 
24
24
  export { compatibleContractsSemver } from './utils/version';
package/src/kind.ts CHANGED
@@ -4,7 +4,7 @@ export type Kind = GenericOptions['kind'];
4
4
 
5
5
  export function sanitizeKind(kind: unknown): Kind {
6
6
  if (typeof kind === 'string') {
7
- const sanitized = kind.replace(/^(ERC|.)/i, c => c.toUpperCase());
7
+ const sanitized = kind.replace(/^(ERC|.)/i, c => c.toUpperCase()).replace(/^(RealWorldAsset)$/i, 'RealWorldAsset');
8
8
  if (isKind(sanitized)) {
9
9
  return sanitized;
10
10
  }
@@ -19,6 +19,7 @@ function isKind<T>(value: Kind | T): value is Kind {
19
19
  case 'ERC721':
20
20
  case 'Stablecoin':
21
21
  case 'RealWorldAsset':
22
+ case 'Account':
22
23
  case 'Governor':
23
24
  case 'Custom':
24
25
  return true;
package/src/print.ts CHANGED
@@ -16,6 +16,7 @@ import { mapValues } from './utils/map-values';
16
16
  import SOLIDITY_VERSION from './solidity-version.json';
17
17
  import { inferTranspiled } from './infer-transpiled';
18
18
  import { compatibleContractsSemver } from './utils/version';
19
+ import { stringifyUnicodeSafe } from './utils/sanitize';
19
20
 
20
21
  export function printContract(contract: Contract, opts?: Options): string {
21
22
  const helpers = withHelpers(contract, opts);
@@ -148,7 +149,7 @@ export function printValue(value: Value): string {
148
149
  throw new Error(`Number not representable (${value})`);
149
150
  }
150
151
  } else {
151
- return JSON.stringify(value);
152
+ return stringifyUnicodeSafe(value);
152
153
  }
153
154
  }
154
155
 
@@ -7,7 +7,11 @@ export const upgradeableOptions = [false, 'transparent', 'uups'] as const;
7
7
 
8
8
  export type Upgradeable = (typeof upgradeableOptions)[number];
9
9
 
10
- export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, access: Access) {
10
+ function setUpgradeableBase(
11
+ c: ContractBuilder,
12
+ upgradeable: Upgradeable,
13
+ restrictAuthorizeUpgradeWhenUUPS: () => void,
14
+ ) {
11
15
  if (upgradeable === false) {
12
16
  return;
13
17
  }
@@ -24,7 +28,7 @@ export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, acc
24
28
  break;
25
29
 
26
30
  case 'uups': {
27
- requireAccessControl(c, functions._authorizeUpgrade, access, 'UPGRADER', 'upgrader');
31
+ restrictAuthorizeUpgradeWhenUUPS();
28
32
  const UUPSUpgradeable = {
29
33
  name: 'UUPSUpgradeable',
30
34
  path: '@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol',
@@ -42,6 +46,18 @@ export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, acc
42
46
  }
43
47
  }
44
48
 
49
+ export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, access: Access) {
50
+ setUpgradeableBase(c, upgradeable, () => {
51
+ requireAccessControl(c, functions._authorizeUpgrade, access, 'UPGRADER', 'upgrader');
52
+ });
53
+ }
54
+
55
+ export function setUpgradeableGovernor(c: ContractBuilder, upgradeable: Upgradeable) {
56
+ setUpgradeableBase(c, upgradeable, () => {
57
+ c.addModifier('onlyGovernance', functions._authorizeUpgrade);
58
+ });
59
+ }
60
+
45
61
  const functions = defineFunctions({
46
62
  _authorizeUpgrade: {
47
63
  args: [{ name: 'newImplementation', type: 'address' }],
package/src/signer.ts ADDED
@@ -0,0 +1,124 @@
1
+ import type { ContractBuilder } from './contract';
2
+ import { defineFunctions } from './utils/define-functions';
3
+
4
+ export const SignerOptions = [false, 'ERC7702', 'ECDSA', 'P256', 'RSA', 'Multisig', 'MultisigWeighted'] as const;
5
+ export type SignerOptions = (typeof SignerOptions)[number];
6
+
7
+ export function addSigner(c: ContractBuilder, signer: SignerOptions): void {
8
+ if (!signer) return;
9
+ const parent = signers[signer];
10
+ const name = parent.name;
11
+ c.addParent(parent);
12
+ c.addOverride(
13
+ { name: name === signers.MultisigWeighted.name ? signers.Multisig.name : name },
14
+ signerFunctions._rawSignatureValidation,
15
+ );
16
+
17
+ // ERC-7702 doesn't require initialization
18
+ if (signer === 'ERC7702') return;
19
+
20
+ c.addParent({
21
+ name: 'Initializable',
22
+ path: '@openzeppelin/contracts/proxy/utils/Initializable.sol',
23
+ });
24
+ const fn = signerFunctions[`initialize${signer}`];
25
+ c.addModifier('initializer', fn);
26
+
27
+ const args = fn.args;
28
+
29
+ switch (signer) {
30
+ case 'Multisig':
31
+ c.addFunctionCode(`_addSigners(${args[0]!.name});`, fn);
32
+ c.addFunctionCode(`_setThreshold(${args[1]!.name});`, fn);
33
+ break;
34
+ case 'MultisigWeighted':
35
+ c.addFunctionCode(`_addSigners(${args[0]!.name});`, fn);
36
+ c.addFunctionCode(`_setSignerWeights(${args[0]!.name}, ${args[1]!.name});`, fn);
37
+ c.addFunctionCode(`_setThreshold(${args[2]!.name});`, fn);
38
+ break;
39
+ case 'ECDSA':
40
+ case 'P256':
41
+ case 'RSA':
42
+ c.addFunctionCode(
43
+ `_setSigner(${fn.args
44
+ .map(({ name }) => name)
45
+ .join(', ')
46
+ .trimEnd()});`,
47
+ fn,
48
+ );
49
+ }
50
+ }
51
+
52
+ export const signers = {
53
+ ERC7702: {
54
+ name: 'SignerERC7702',
55
+ path: '@openzeppelin/community-contracts/utils/cryptography/SignerERC7702.sol',
56
+ },
57
+ ECDSA: {
58
+ name: 'SignerECDSA',
59
+ path: '@openzeppelin/community-contracts/utils/cryptography/SignerECDSA.sol',
60
+ },
61
+ P256: {
62
+ name: 'SignerP256',
63
+ path: '@openzeppelin/community-contracts/utils/cryptography/SignerP256.sol',
64
+ },
65
+ RSA: {
66
+ name: 'SignerRSA',
67
+ path: '@openzeppelin/community-contracts/utils/cryptography/SignerRSA.sol',
68
+ },
69
+ Multisig: {
70
+ name: 'MultiSignerERC7913',
71
+ path: '@openzeppelin/community-contracts/utils/cryptography/MultiSignerERC7913.sol',
72
+ },
73
+ MultisigWeighted: {
74
+ name: 'MultiSignerERC7913Weighted',
75
+ path: '@openzeppelin/community-contracts/utils/cryptography/MultiSignerERC7913Weighted.sol',
76
+ },
77
+ };
78
+
79
+ export const signerFunctions = {
80
+ ...defineFunctions({
81
+ initializeECDSA: {
82
+ kind: 'public' as const,
83
+ args: [{ name: 'signer', type: 'address' }],
84
+ },
85
+ initializeP256: {
86
+ kind: 'public' as const,
87
+ args: [
88
+ { name: 'qx', type: 'bytes32' },
89
+ { name: 'qy', type: 'bytes32' },
90
+ ],
91
+ },
92
+ initializeRSA: {
93
+ kind: 'public' as const,
94
+ args: [
95
+ { name: 'e', type: 'bytes memory' },
96
+ { name: 'n', type: 'bytes memory' },
97
+ ],
98
+ },
99
+ initializeMultisig: {
100
+ kind: 'public' as const,
101
+ args: [
102
+ { name: 'signers', type: 'bytes[] memory' },
103
+ { name: 'threshold', type: 'uint256' },
104
+ ],
105
+ },
106
+ initializeMultisigWeighted: {
107
+ kind: 'public' as const,
108
+ args: [
109
+ { name: 'signers', type: 'bytes[] memory' },
110
+ { name: 'weights', type: 'uint256[] memory' },
111
+ { name: 'threshold', type: 'uint256' },
112
+ ],
113
+ },
114
+ _rawSignatureValidation: {
115
+ kind: 'internal' as const,
116
+ args: [
117
+ { name: 'hash', type: 'bytes32' },
118
+ { name: 'signature', type: 'bytes calldata' },
119
+ ],
120
+ returns: ['bool'],
121
+ mutability: 'view' as const,
122
+ },
123
+ }),
124
+ };
@@ -1 +1 @@
1
- "0.8.22"
1
+ "0.8.27"
package/src/stablecoin.ts CHANGED
@@ -65,7 +65,7 @@ function addLimitations(c: ContractBuilder, access: Access, mode: boolean | 'all
65
65
  const type = mode === 'allowlist';
66
66
  const ERC20Limitation = {
67
67
  name: type ? 'ERC20Allowlist' : 'ERC20Blocklist',
68
- path: `@openzeppelin/community-contracts/contracts/token/ERC20/extensions/${type ? 'ERC20Allowlist' : 'ERC20Blocklist'}.sol`,
68
+ path: `@openzeppelin/community-contracts/token/ERC20/extensions/${type ? 'ERC20Allowlist' : 'ERC20Blocklist'}.sol`,
69
69
  };
70
70
 
71
71
  c.addParent(ERC20Limitation);
@@ -86,7 +86,7 @@ function addLimitations(c: ContractBuilder, access: Access, mode: boolean | 'all
86
86
  function addCustodian(c: ContractBuilder, access: Access) {
87
87
  const ERC20Custodian = {
88
88
  name: 'ERC20Custodian',
89
- path: '@openzeppelin/community-contracts/contracts/token/ERC20/extensions/ERC20Custodian.sol',
89
+ path: '@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Custodian.sol',
90
90
  };
91
91
 
92
92
  c.addParent(ERC20Custodian);
package/src/test.ts CHANGED
@@ -30,6 +30,10 @@ test.serial('stablecoin result compiles', async t => {
30
30
  await testCompile(t, 'Stablecoin');
31
31
  });
32
32
 
33
+ test.serial('account result compiles', async t => {
34
+ await testCompile(t, 'Account');
35
+ });
36
+
33
37
  test.serial('governor result compiles', async t => {
34
38
  await testCompile(t, 'Governor');
35
39
  });
@@ -66,6 +70,8 @@ function isAccessControlRequired(opts: GenericOptions) {
66
70
  return stablecoin.isAccessControlRequired(opts);
67
71
  case 'RealWorldAsset':
68
72
  return stablecoin.isAccessControlRequired(opts);
73
+ case 'Account':
74
+ throw new Error(`Not applicable for ${opts.kind}`);
69
75
  case 'Governor':
70
76
  return governor.isAccessControlRequired(opts);
71
77
  case 'Custom':
@@ -79,11 +85,17 @@ test('is access control required', async t => {
79
85
  for (const contract of generateSources('all')) {
80
86
  const regexOwnable = /import.*Ownable(Upgradeable)?.sol.*/gm;
81
87
 
82
- if (!contract.options.access) {
83
- if (isAccessControlRequired(contract.options)) {
84
- t.regex(contract.source, regexOwnable, JSON.stringify(contract.options));
85
- } else {
86
- t.notRegex(contract.source, regexOwnable, JSON.stringify(contract.options));
88
+ switch (contract.options.kind) {
89
+ case 'Account':
90
+ break;
91
+ default: {
92
+ if (!contract.options.access) {
93
+ if (isAccessControlRequired(contract.options)) {
94
+ t.regex(contract.source, regexOwnable, JSON.stringify(contract.options));
95
+ } else {
96
+ t.notRegex(contract.source, regexOwnable, JSON.stringify(contract.options));
97
+ }
98
+ }
87
99
  }
88
100
  }
89
101
  }
@@ -0,0 +1,6 @@
1
+ export function stringifyUnicodeSafe(str: string): string {
2
+ // eslint-disable-next-line no-control-regex
3
+ const containsUnicode = /[^\x00-\x7F]/.test(str);
4
+
5
+ return containsUnicode ? `unicode"${str.replace(/"/g, '\\"')}"` : JSON.stringify(str);
6
+ }
@@ -202,18 +202,18 @@ then
202
202
  mv README.md README-oz.md
203
203
 
204
204
  # Initialize sample Foundry project
205
- forge init --force --no-commit --quiet
205
+ forge init --force --quiet
206
206
 
207
207
  ${
208
208
  c.upgradeable
209
209
  ? `\
210
210
  # Install OpenZeppelin Contracts and Upgrades
211
- forge install OpenZeppelin/openzeppelin-contracts-upgradeable@v${contracts.version} --no-commit --quiet
212
- forge install OpenZeppelin/openzeppelin-foundry-upgrades --no-commit --quiet\
211
+ forge install OpenZeppelin/openzeppelin-contracts-upgradeable@v${contracts.version} --quiet
212
+ forge install OpenZeppelin/openzeppelin-foundry-upgrades --quiet\
213
213
  `
214
214
  : `\
215
215
  # Install OpenZeppelin Contracts
216
- forge install OpenZeppelin/openzeppelin-contracts@v${contracts.version} --no-commit --quiet\
216
+ forge install OpenZeppelin/openzeppelin-contracts@v${contracts.version} --quiet\
217
217
  `
218
218
  }
219
219