@openzeppelin/wizard 0.5.2 → 0.5.4

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 (161) hide show
  1. package/dist/add-pausable.d.ts +1 -1
  2. package/dist/add-pausable.d.ts.map +1 -1
  3. package/dist/add-pausable.js.map +1 -1
  4. package/dist/api.d.ts +6 -6
  5. package/dist/api.d.ts.map +1 -1
  6. package/dist/api.js +7 -7
  7. package/dist/api.js.map +1 -1
  8. package/dist/build-generic.d.ts +7 -7
  9. package/dist/build-generic.d.ts.map +1 -1
  10. package/dist/build-generic.js +2 -1
  11. package/dist/build-generic.js.map +1 -1
  12. package/dist/common-functions.d.ts.map +1 -1
  13. package/dist/common-functions.js +1 -3
  14. package/dist/common-functions.js.map +1 -1
  15. package/dist/common-options.d.ts +3 -3
  16. package/dist/contract.d.ts +1 -1
  17. package/dist/contract.d.ts.map +1 -1
  18. package/dist/contract.js +10 -6
  19. package/dist/contract.js.map +1 -1
  20. package/dist/custom.d.ts +2 -2
  21. package/dist/custom.d.ts.map +1 -1
  22. package/dist/custom.js.map +1 -1
  23. package/dist/environments/hardhat/package-lock.json +368 -246
  24. package/dist/environments/hardhat/upgradeable/package-lock.json +824 -1506
  25. package/dist/erc1155.d.ts +2 -2
  26. package/dist/erc1155.d.ts.map +1 -1
  27. package/dist/erc1155.js +2 -4
  28. package/dist/erc1155.js.map +1 -1
  29. package/dist/erc20.d.ts +10 -3
  30. package/dist/erc20.d.ts.map +1 -1
  31. package/dist/erc20.js +175 -14
  32. package/dist/erc20.js.map +1 -1
  33. package/dist/erc721.d.ts +3 -3
  34. package/dist/erc721.d.ts.map +1 -1
  35. package/dist/erc721.js.map +1 -1
  36. package/dist/error.js +1 -1
  37. package/dist/error.js.map +1 -1
  38. package/dist/generate/alternatives.d.ts.map +1 -1
  39. package/dist/generate/alternatives.js.map +1 -1
  40. package/dist/generate/erc20.d.ts +1 -1
  41. package/dist/generate/erc20.d.ts.map +1 -1
  42. package/dist/generate/erc20.js +10 -1
  43. package/dist/generate/erc20.js.map +1 -1
  44. package/dist/generate/erc721.js.map +1 -1
  45. package/dist/generate/governor.d.ts +1 -1
  46. package/dist/generate/governor.d.ts.map +1 -1
  47. package/dist/generate/governor.js.map +1 -1
  48. package/dist/generate/sources.d.ts +1 -1
  49. package/dist/generate/sources.d.ts.map +1 -1
  50. package/dist/generate/sources.js +1 -5
  51. package/dist/generate/sources.js.map +1 -1
  52. package/dist/generate/stablecoin.d.ts.map +1 -1
  53. package/dist/generate/stablecoin.js +34 -15
  54. package/dist/generate/stablecoin.js.map +1 -1
  55. package/dist/get-imports.d.ts +4 -4
  56. package/dist/get-imports.js +4 -4
  57. package/dist/governor.d.ts +5 -5
  58. package/dist/governor.d.ts.map +1 -1
  59. package/dist/governor.js +19 -27
  60. package/dist/governor.js.map +1 -1
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +2 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/infer-transpiled.d.ts +1 -1
  66. package/dist/options.d.ts.map +1 -1
  67. package/dist/options.js.map +1 -1
  68. package/dist/print-versioned.d.ts +1 -1
  69. package/dist/print-versioned.js +1 -1
  70. package/dist/print-versioned.js.map +1 -1
  71. package/dist/print.d.ts +1 -1
  72. package/dist/print.d.ts.map +1 -1
  73. package/dist/print.js +6 -12
  74. package/dist/print.js.map +1 -1
  75. package/dist/scripts/prepare.js +4 -2
  76. package/dist/scripts/prepare.js.map +1 -1
  77. package/dist/set-access-control.d.ts +1 -1
  78. package/dist/set-access-control.d.ts.map +1 -1
  79. package/dist/set-access-control.js +3 -3
  80. package/dist/set-access-control.js.map +1 -1
  81. package/dist/set-clock-mode.d.ts +2 -2
  82. package/dist/set-clock-mode.d.ts.map +1 -1
  83. package/dist/set-clock-mode.js +1 -1
  84. package/dist/set-info.d.ts +1 -1
  85. package/dist/set-info.d.ts.map +1 -1
  86. package/dist/set-upgradeable.d.ts +2 -2
  87. package/dist/set-upgradeable.d.ts.map +1 -1
  88. package/dist/set-upgradeable.js +3 -4
  89. package/dist/set-upgradeable.js.map +1 -1
  90. package/dist/stablecoin.d.ts +3 -3
  91. package/dist/stablecoin.d.ts.map +1 -1
  92. package/dist/stablecoin.js +8 -18
  93. package/dist/stablecoin.js.map +1 -1
  94. package/dist/test.js +1 -1
  95. package/dist/test.js.map +1 -1
  96. package/dist/utils/convert-strings.d.ts +11 -0
  97. package/dist/utils/convert-strings.d.ts.map +1 -0
  98. package/dist/utils/convert-strings.js +30 -0
  99. package/dist/utils/convert-strings.js.map +1 -0
  100. package/dist/utils/define-functions.d.ts.map +1 -1
  101. package/dist/utils/define-functions.js +1 -4
  102. package/dist/utils/define-functions.js.map +1 -1
  103. package/dist/utils/format-lines.d.ts.map +1 -1
  104. package/dist/utils/format-lines.js.map +1 -1
  105. package/dist/utils/map-values.d.ts.map +1 -1
  106. package/dist/utils/map-values.js +1 -0
  107. package/dist/utils/map-values.js.map +1 -1
  108. package/dist/utils/to-identifier.d.ts.map +1 -1
  109. package/dist/utils/to-identifier.js +3 -2
  110. package/dist/utils/to-identifier.js.map +1 -1
  111. package/dist/zip-foundry.d.ts +3 -3
  112. package/dist/zip-foundry.d.ts.map +1 -1
  113. package/dist/zip-foundry.js +23 -76
  114. package/dist/zip-foundry.js.map +1 -1
  115. package/dist/zip-hardhat.d.ts +3 -3
  116. package/dist/zip-hardhat.d.ts.map +1 -1
  117. package/dist/zip-hardhat.js +13 -15
  118. package/dist/zip-hardhat.js.map +1 -1
  119. package/package.json +2 -2
  120. package/src/add-pausable.ts +2 -1
  121. package/src/api.ts +55 -25
  122. package/src/build-generic.ts +21 -14
  123. package/src/common-functions.ts +1 -3
  124. package/src/common-options.ts +4 -4
  125. package/src/contract.ts +21 -19
  126. package/src/custom.ts +4 -3
  127. package/src/environments/hardhat/package-lock.json +368 -246
  128. package/src/environments/hardhat/upgradeable/package-lock.json +824 -1506
  129. package/src/erc1155.ts +8 -7
  130. package/src/erc20.ts +234 -23
  131. package/src/erc721.ts +8 -4
  132. package/src/error.ts +1 -1
  133. package/src/generate/alternatives.ts +2 -8
  134. package/src/generate/erc20.ts +11 -3
  135. package/src/generate/erc721.ts +1 -1
  136. package/src/generate/governor.ts +2 -1
  137. package/src/generate/sources.ts +11 -8
  138. package/src/generate/stablecoin.ts +37 -16
  139. package/src/get-imports.ts +5 -5
  140. package/src/governor.ts +56 -58
  141. package/src/index.ts +2 -2
  142. package/src/infer-transpiled.ts +2 -2
  143. package/src/kind.ts +0 -1
  144. package/src/options.ts +4 -3
  145. package/src/print-versioned.ts +4 -6
  146. package/src/print.ts +40 -43
  147. package/src/scripts/prepare.ts +10 -6
  148. package/src/set-access-control.ts +15 -9
  149. package/src/set-clock-mode.ts +5 -5
  150. package/src/set-info.ts +3 -3
  151. package/src/set-upgradeable.ts +6 -6
  152. package/src/stablecoin.ts +23 -27
  153. package/src/test.ts +6 -5
  154. package/src/utils/convert-strings.ts +27 -0
  155. package/src/utils/define-functions.ts +3 -12
  156. package/src/utils/duration.ts +2 -2
  157. package/src/utils/format-lines.ts +1 -5
  158. package/src/utils/map-values.ts +2 -4
  159. package/src/utils/to-identifier.ts +3 -2
  160. package/src/zip-foundry.ts +40 -102
  161. package/src/zip-hardhat.ts +24 -30
package/src/erc1155.ts CHANGED
@@ -1,9 +1,12 @@
1
- import { Contract, ContractBuilder } from './contract';
2
- import { Access, setAccessControl, requireAccessControl } from './set-access-control';
1
+ import type { Contract } from './contract';
2
+ import { ContractBuilder } from './contract';
3
+ import type { Access } from './set-access-control';
4
+ import { setAccessControl, requireAccessControl } from './set-access-control';
3
5
  import { addPauseFunctions } from './add-pausable';
4
6
  import { supportsInterface } from './common-functions';
5
7
  import { defineFunctions } from './utils/define-functions';
6
- import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from './common-options';
8
+ import type { CommonOptions } from './common-options';
9
+ import { withCommonDefaults, defaults as commonDefaults } from './common-options';
7
10
  import { setUpgradeable } from './set-upgradeable';
8
11
  import { setInfo } from './set-info';
9
12
  import { printContract } from './print';
@@ -28,7 +31,7 @@ export const defaults: Required<ERC1155Options> = {
28
31
  updatableUri: true,
29
32
  access: commonDefaults.access,
30
33
  upgradeable: commonDefaults.upgradeable,
31
- info: commonDefaults.info
34
+ info: commonDefaults.info,
32
35
  } as const;
33
36
 
34
37
  function withDefaults(opts: ERC1155Options): Required<ERC1155Options> {
@@ -150,9 +153,7 @@ const functions = defineFunctions({
150
153
 
151
154
  setURI: {
152
155
  kind: 'public' as const,
153
- args: [
154
- { name: 'newuri', type: 'string memory' },
155
- ],
156
+ args: [{ name: 'newuri', type: 'string memory' }],
156
157
  },
157
158
 
158
159
  mint: {
package/src/erc20.ts CHANGED
@@ -1,12 +1,22 @@
1
- import { Contract, ContractBuilder } from './contract';
2
- import { Access, setAccessControl, requireAccessControl } from './set-access-control';
1
+ import { ContractBuilder } from './contract';
2
+ import type { Access } from './set-access-control';
3
+ import { setAccessControl, requireAccessControl } from './set-access-control';
3
4
  import { addPauseFunctions } from './add-pausable';
4
5
  import { defineFunctions } from './utils/define-functions';
5
- import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from './common-options';
6
+ import type { CommonOptions } from './common-options';
7
+ import { withCommonDefaults, defaults as commonDefaults } from './common-options';
8
+ import type { Upgradeable } from './set-upgradeable';
6
9
  import { setUpgradeable } from './set-upgradeable';
7
10
  import { setInfo } from './set-info';
8
11
  import { printContract } from './print';
9
- import { ClockMode, clockModeDefault, setClockMode } from './set-clock-mode';
12
+ import type { ClockMode } from './set-clock-mode';
13
+ import { clockModeDefault, setClockMode } from './set-clock-mode';
14
+ import { supportsInterface } from './common-functions';
15
+ import { OptionsError } from './error';
16
+ import { toUint256, UINT256_MAX } from './utils/convert-strings';
17
+
18
+ export const crossChainBridgingOptions = [false, 'custom', 'superchain'] as const;
19
+ export type CrossChainBridging = (typeof crossChainBridgingOptions)[number];
10
20
 
11
21
  export interface ERC20Options extends CommonOptions {
12
22
  name: string;
@@ -14,7 +24,9 @@ export interface ERC20Options extends CommonOptions {
14
24
  burnable?: boolean;
15
25
  pausable?: boolean;
16
26
  premint?: string;
27
+ premintChainId?: string;
17
28
  mintable?: boolean;
29
+ callback?: boolean;
18
30
  permit?: boolean;
19
31
  /**
20
32
  * Whether to keep track of historical balances for voting in on-chain governance, and optionally specify the clock mode.
@@ -22,6 +34,7 @@ export interface ERC20Options extends CommonOptions {
22
34
  */
23
35
  votes?: boolean | ClockMode;
24
36
  flashmint?: boolean;
37
+ crossChainBridging?: CrossChainBridging;
25
38
  }
26
39
 
27
40
  export const defaults: Required<ERC20Options> = {
@@ -30,10 +43,13 @@ export const defaults: Required<ERC20Options> = {
30
43
  burnable: false,
31
44
  pausable: false,
32
45
  premint: '0',
46
+ premintChainId: '',
33
47
  mintable: false,
48
+ callback: false,
34
49
  permit: true,
35
50
  votes: false,
36
51
  flashmint: false,
52
+ crossChainBridging: false,
37
53
  access: commonDefaults.access,
38
54
  upgradeable: commonDefaults.upgradeable,
39
55
  info: commonDefaults.info,
@@ -46,10 +62,13 @@ export function withDefaults(opts: ERC20Options): Required<ERC20Options> {
46
62
  burnable: opts.burnable ?? defaults.burnable,
47
63
  pausable: opts.pausable ?? defaults.pausable,
48
64
  premint: opts.premint || defaults.premint,
65
+ premintChainId: opts.premintChainId || defaults.premintChainId,
49
66
  mintable: opts.mintable ?? defaults.mintable,
67
+ callback: opts.callback ?? defaults.callback,
50
68
  permit: opts.permit ?? defaults.permit,
51
69
  votes: opts.votes ?? defaults.votes,
52
70
  flashmint: opts.flashmint ?? defaults.flashmint,
71
+ crossChainBridging: opts.crossChainBridging ?? defaults.crossChainBridging,
53
72
  };
54
73
  }
55
74
 
@@ -70,6 +89,14 @@ export function buildERC20(opts: ERC20Options): ContractBuilder {
70
89
 
71
90
  addBase(c, allOpts.name, allOpts.symbol);
72
91
 
92
+ if (allOpts.crossChainBridging) {
93
+ addCrossChainBridging(c, allOpts.crossChainBridging, allOpts.upgradeable, access);
94
+ }
95
+
96
+ if (allOpts.premint) {
97
+ addPremint(c, allOpts.premint, allOpts.premintChainId, allOpts.crossChainBridging);
98
+ }
99
+
73
100
  if (allOpts.burnable) {
74
101
  addBurnable(c);
75
102
  }
@@ -78,14 +105,14 @@ export function buildERC20(opts: ERC20Options): ContractBuilder {
78
105
  addPausableExtension(c, access);
79
106
  }
80
107
 
81
- if (allOpts.premint) {
82
- addPremint(c, allOpts.premint);
83
- }
84
-
85
108
  if (allOpts.mintable) {
86
109
  addMintable(c, access);
87
110
  }
88
111
 
112
+ if (allOpts.callback) {
113
+ addCallback(c);
114
+ }
115
+
89
116
  // Note: Votes requires Permit
90
117
  if (allOpts.permit || allOpts.votes) {
91
118
  addPermit(c, allOpts.name);
@@ -112,10 +139,7 @@ function addBase(c: ContractBuilder, name: string, symbol: string) {
112
139
  name: 'ERC20',
113
140
  path: '@openzeppelin/contracts/token/ERC20/ERC20.sol',
114
141
  };
115
- c.addParent(
116
- ERC20,
117
- [name, symbol],
118
- );
142
+ c.addParent(ERC20, [name, symbol]);
119
143
 
120
144
  c.addOverride(ERC20, functions._update);
121
145
  c.addOverride(ERC20, functions._approve); // allows override from stablecoin
@@ -141,7 +165,26 @@ function addBurnable(c: ContractBuilder) {
141
165
 
142
166
  export const premintPattern = /^(\d*)(?:\.(\d+))?(?:e(\d+))?$/;
143
167
 
144
- function addPremint(c: ContractBuilder, amount: string) {
168
+ export const chainIdPattern = /^(?!$)[1-9]\d*$/;
169
+
170
+ export function isValidChainId(str: string): boolean {
171
+ return chainIdPattern.test(str);
172
+ }
173
+
174
+ function scaleByPowerOfTen(base: bigint, exponent: number): bigint {
175
+ if (exponent < 0) {
176
+ return base / BigInt(10) ** BigInt(-exponent);
177
+ } else {
178
+ return base * BigInt(10) ** BigInt(exponent);
179
+ }
180
+ }
181
+
182
+ function addPremint(
183
+ c: ContractBuilder,
184
+ amount: string,
185
+ premintChainId: string,
186
+ crossChainBridging: CrossChainBridging,
187
+ ) {
145
188
  const m = amount.match(premintPattern);
146
189
  if (m) {
147
190
  const integer = m[1]?.replace(/^0+/, '') ?? '';
@@ -153,9 +196,56 @@ function addPremint(c: ContractBuilder, amount: string) {
153
196
  const zeroes = new Array(Math.max(0, -decimalPlace)).fill('0').join('');
154
197
  const units = integer + decimals + zeroes;
155
198
  const exp = decimalPlace <= 0 ? 'decimals()' : `(decimals() - ${decimalPlace})`;
156
- c.addConstructorArgument({type: 'address', name: 'recipient'});
157
- c.addConstructorCode(`_mint(recipient, ${units} * 10 ** ${exp});`);
199
+
200
+ const validatedBaseUnits = toUint256(units, 'premint');
201
+ checkPotentialPremintOverflow(validatedBaseUnits, decimalPlace);
202
+
203
+ c.addConstructorArgument({ type: 'address', name: 'recipient' });
204
+
205
+ const mintLine = `_mint(recipient, ${units} * 10 ** ${exp});`;
206
+
207
+ if (crossChainBridging) {
208
+ if (premintChainId === '') {
209
+ throw new OptionsError({
210
+ premintChainId: 'Chain ID is required when using Premint with Cross-Chain Bridging',
211
+ });
212
+ }
213
+
214
+ if (!isValidChainId(premintChainId)) {
215
+ throw new OptionsError({
216
+ premintChainId: 'Not a valid chain ID',
217
+ });
218
+ }
219
+
220
+ c.addConstructorCode(`if (block.chainid == ${premintChainId}) {`);
221
+ c.addConstructorCode(` ${mintLine}`);
222
+ c.addConstructorCode(`}`);
223
+ } else {
224
+ c.addConstructorCode(mintLine);
225
+ }
158
226
  }
227
+ } else {
228
+ throw new OptionsError({
229
+ premint: 'Not a valid number',
230
+ });
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Check for potential premint overflow assuming the user's contract has decimals() = 18
236
+ *
237
+ * @param baseUnits The base units of the token, before applying power of 10
238
+ * @param decimalPlace If positive, the number of assumed decimal places in the least significant digits of `validatedBaseUnits`. Ignored if <= 0.
239
+ * @throws OptionsError if the calculated value would overflow uint256
240
+ */
241
+ function checkPotentialPremintOverflow(baseUnits: bigint, decimalPlace: number) {
242
+ const assumedExp = decimalPlace <= 0 ? 18 : 18 - decimalPlace;
243
+ const calculatedValue = scaleByPowerOfTen(baseUnits, assumedExp);
244
+
245
+ if (calculatedValue > UINT256_MAX) {
246
+ throw new OptionsError({
247
+ premint: 'Amount would overflow uint256 after applying decimals',
248
+ });
159
249
  }
160
250
  }
161
251
 
@@ -164,6 +254,15 @@ function addMintable(c: ContractBuilder, access: Access) {
164
254
  c.addFunctionCode('_mint(to, amount);', functions.mint);
165
255
  }
166
256
 
257
+ function addCallback(c: ContractBuilder) {
258
+ const ERC1363 = {
259
+ name: 'ERC1363',
260
+ path: '@openzeppelin/contracts/token/ERC20/extensions/ERC1363.sol',
261
+ };
262
+ c.addParent(ERC1363);
263
+ c.addOverride(ERC1363, supportsInterface);
264
+ }
265
+
167
266
  function addPermit(c: ContractBuilder, name: string) {
168
267
  const ERC20Permit = {
169
268
  name: 'ERC20Permit',
@@ -171,7 +270,6 @@ function addPermit(c: ContractBuilder, name: string) {
171
270
  };
172
271
  c.addParent(ERC20Permit, [name]);
173
272
  c.addOverride(ERC20Permit, functions.nonces);
174
-
175
273
  }
176
274
 
177
275
  function addVotes(c: ContractBuilder, clockMode: ClockMode) {
@@ -190,9 +288,12 @@ function addVotes(c: ContractBuilder, clockMode: ClockMode) {
190
288
  name: 'Nonces',
191
289
  path: '@openzeppelin/contracts/utils/Nonces.sol',
192
290
  });
193
- c.addOverride({
194
- name: 'Nonces',
195
- }, functions.nonces);
291
+ c.addOverride(
292
+ {
293
+ name: 'Nonces',
294
+ },
295
+ functions.nonces,
296
+ );
196
297
 
197
298
  setClockMode(c, ERC20Votes, clockMode);
198
299
  }
@@ -204,6 +305,113 @@ function addFlashMint(c: ContractBuilder) {
204
305
  });
205
306
  }
206
307
 
308
+ function addCrossChainBridging(
309
+ c: ContractBuilder,
310
+ crossChainBridging: 'custom' | 'superchain',
311
+ upgradeable: Upgradeable,
312
+ access: Access,
313
+ ) {
314
+ const ERC20Bridgeable = {
315
+ name: 'ERC20Bridgeable',
316
+ path: `@openzeppelin/community-contracts/contracts/token/ERC20/extensions/ERC20Bridgeable.sol`,
317
+ };
318
+
319
+ c.addParent(ERC20Bridgeable);
320
+ c.addOverride(ERC20Bridgeable, supportsInterface);
321
+
322
+ if (upgradeable) {
323
+ throw new OptionsError({
324
+ crossChainBridging: 'Upgradeability is not currently supported with Cross-Chain Bridging',
325
+ });
326
+ }
327
+
328
+ c.addOverride(ERC20Bridgeable, functions._checkTokenBridge);
329
+ switch (crossChainBridging) {
330
+ case 'custom':
331
+ addCustomBridging(c, access);
332
+ break;
333
+ case 'superchain':
334
+ addSuperchainERC20(c);
335
+ break;
336
+ default: {
337
+ const _: never = crossChainBridging;
338
+ throw new Error('Unknown value for `crossChainBridging`');
339
+ }
340
+ }
341
+ c.addVariable('error Unauthorized();');
342
+ }
343
+
344
+ function addCustomBridging(c: ContractBuilder, access: Access) {
345
+ switch (access) {
346
+ case false:
347
+ case 'ownable': {
348
+ const addedBridgeImmutable = c.addVariable(`address public immutable TOKEN_BRIDGE;`);
349
+ if (addedBridgeImmutable) {
350
+ c.addConstructorArgument({ type: 'address', name: 'tokenBridge' });
351
+ c.addConstructorCode(`require(tokenBridge != address(0), "Invalid TOKEN_BRIDGE address");`);
352
+ c.addConstructorCode(`TOKEN_BRIDGE = tokenBridge;`);
353
+ }
354
+ c.setFunctionBody([`if (caller != TOKEN_BRIDGE) revert Unauthorized();`], functions._checkTokenBridge, 'view');
355
+ break;
356
+ }
357
+ case 'roles': {
358
+ setAccessControl(c, access);
359
+ const roleOwner = 'tokenBridge';
360
+ const roleId = 'TOKEN_BRIDGE_ROLE';
361
+ const addedRoleConstant = c.addVariable(`bytes32 public constant ${roleId} = keccak256("${roleId}");`);
362
+ if (addedRoleConstant) {
363
+ c.addConstructorArgument({ type: 'address', name: roleOwner });
364
+ c.addConstructorCode(`_grantRole(${roleId}, ${roleOwner});`);
365
+ }
366
+ c.setFunctionBody(
367
+ [`if (!hasRole(${roleId}, caller)) revert Unauthorized();`],
368
+ functions._checkTokenBridge,
369
+ 'view',
370
+ );
371
+ break;
372
+ }
373
+ case 'managed': {
374
+ setAccessControl(c, access);
375
+ c.addImportOnly({
376
+ name: 'AuthorityUtils',
377
+ path: `@openzeppelin/contracts/access/manager/AuthorityUtils.sol`,
378
+ });
379
+ c.setFunctionBody(
380
+ [
381
+ `(bool immediate,) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), bytes4(_msgData()[0:4]));`,
382
+ `if (!immediate) revert Unauthorized();`,
383
+ ],
384
+ functions._checkTokenBridge,
385
+ 'view',
386
+ );
387
+ break;
388
+ }
389
+ default: {
390
+ const _: never = access;
391
+ throw new Error('Unknown value for `access`');
392
+ }
393
+ }
394
+ }
395
+
396
+ function addSuperchainERC20(c: ContractBuilder) {
397
+ c.addVariable('address internal constant SUPERCHAIN_TOKEN_BRIDGE = 0x4200000000000000000000000000000000000028;');
398
+ c.setFunctionBody(
399
+ ['if (caller != SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized();'],
400
+ functions._checkTokenBridge,
401
+ 'pure',
402
+ );
403
+ c.setFunctionComments(
404
+ [
405
+ '/**',
406
+ ' * @dev Checks if the caller is the predeployed SuperchainTokenBridge. Reverts otherwise.',
407
+ ' *',
408
+ ' * IMPORTANT: The predeployed SuperchainTokenBridge is only available on chains in the Superchain.',
409
+ ' */',
410
+ ],
411
+ functions._checkTokenBridge,
412
+ );
413
+ }
414
+
207
415
  export const functions = defineFunctions({
208
416
  _update: {
209
417
  kind: 'internal' as const,
@@ -249,10 +457,13 @@ export const functions = defineFunctions({
249
457
 
250
458
  nonces: {
251
459
  kind: 'public' as const,
252
- args: [
253
- { name: 'owner', type: 'address' },
254
- ],
460
+ args: [{ name: 'owner', type: 'address' }],
255
461
  returns: ['uint256'],
256
462
  mutability: 'view' as const,
257
- }
463
+ },
464
+
465
+ _checkTokenBridge: {
466
+ kind: 'internal' as const,
467
+ args: [{ name: 'caller', type: 'address' }],
468
+ },
258
469
  });
package/src/erc721.ts CHANGED
@@ -1,13 +1,17 @@
1
- import { BaseFunction, Contract, ContractBuilder } from './contract';
2
- import { Access, setAccessControl, requireAccessControl } from './set-access-control';
1
+ import type { BaseFunction, Contract } from './contract';
2
+ import { ContractBuilder } from './contract';
3
+ import type { Access } from './set-access-control';
4
+ import { setAccessControl, requireAccessControl } from './set-access-control';
3
5
  import { addPauseFunctions } from './add-pausable';
4
6
  import { supportsInterface } from './common-functions';
5
7
  import { defineFunctions } from './utils/define-functions';
6
- import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from './common-options';
8
+ import type { CommonOptions } from './common-options';
9
+ import { withCommonDefaults, defaults as commonDefaults } from './common-options';
7
10
  import { setUpgradeable } from './set-upgradeable';
8
11
  import { setInfo } from './set-info';
9
12
  import { printContract } from './print';
10
- import { ClockMode, clockModeDefault, setClockMode } from './set-clock-mode';
13
+ import type { ClockMode } from './set-clock-mode';
14
+ import { clockModeDefault, setClockMode } from './set-clock-mode';
11
15
 
12
16
  export interface ERC721Options extends CommonOptions {
13
17
  name: string;
package/src/error.ts CHANGED
@@ -2,6 +2,6 @@ export type OptionsErrorMessages = { [prop in string]?: string };
2
2
 
3
3
  export class OptionsError extends Error {
4
4
  constructor(readonly messages: OptionsErrorMessages) {
5
- super("Invalid options for Governor");
5
+ super('Invalid options');
6
6
  }
7
7
  }
@@ -1,14 +1,10 @@
1
- import { mapValues } from "../utils/map-values";
2
-
3
1
  type Blueprint = Record<string, readonly unknown[]>;
4
2
 
5
3
  type Alternatives<B extends Blueprint> = {
6
4
  [k in keyof B]: B[k][number];
7
5
  };
8
6
 
9
- export function* generateAlternatives<B extends Blueprint>(
10
- blueprint: B,
11
- ): Generator<Alternatives<B>> {
7
+ export function* generateAlternatives<B extends Blueprint>(blueprint: B): Generator<Alternatives<B>> {
12
8
  const entries = Object.entries(blueprint).map(([key, values]) => ({
13
9
  key,
14
10
  values,
@@ -17,9 +13,7 @@ export function* generateAlternatives<B extends Blueprint>(
17
13
  }));
18
14
 
19
15
  for (; !done(); advance()) {
20
- yield Object.fromEntries(
21
- entries.map(e => [e.key, e.values[e.current % e.limit]]),
22
- ) as Alternatives<B>;
16
+ yield Object.fromEntries(entries.map(e => [e.key, e.values[e.current % e.limit]])) as Alternatives<B>;
23
17
  }
24
18
 
25
19
  function done() {
@@ -1,4 +1,4 @@
1
- import type { ERC20Options } from '../erc20';
1
+ import { crossChainBridgingOptions, type ERC20Options } from '../erc20';
2
2
  import { accessOptions } from '../set-access-control';
3
3
  import { clockModeOptions } from '../set-clock-mode';
4
4
  import { infoOptions } from '../set-info';
@@ -13,15 +13,23 @@ const blueprint = {
13
13
  burnable: booleans,
14
14
  pausable: booleans,
15
15
  mintable: booleans,
16
+ callback: booleans,
16
17
  permit: booleans,
17
- votes: [ ...booleans, ...clockModeOptions ] as const,
18
+ votes: [...booleans, ...clockModeOptions] as const,
18
19
  flashmint: booleans,
19
20
  premint: ['1'],
21
+ premintChainId: ['10'],
22
+ crossChainBridging: crossChainBridgingOptions,
20
23
  access: accessOptions,
21
24
  upgradeable: upgradeableOptions,
22
25
  info: infoOptions,
23
26
  };
24
27
 
25
28
  export function* generateERC20Options(): Generator<Required<ERC20Options>> {
26
- yield* generateAlternatives(blueprint);
29
+ for (const opts of generateAlternatives(blueprint)) {
30
+ // crossChainBridging does not currently support upgradeable
31
+ if (!(opts.crossChainBridging && opts.upgradeable)) {
32
+ yield opts;
33
+ }
34
+ }
27
35
  }
@@ -20,7 +20,7 @@ const blueprint = {
20
20
  access: accessOptions,
21
21
  upgradeable: upgradeableOptions,
22
22
  info: infoOptions,
23
- votes: [ ...booleans, ...clockModeOptions ] as const,
23
+ votes: [...booleans, ...clockModeOptions] as const,
24
24
  };
25
25
 
26
26
  export function* generateERC721Options(): Generator<Required<ERC721Options>> {
@@ -1,4 +1,5 @@
1
- import { defaults, GovernorOptions, timelockOptions, votesOptions } from '../governor';
1
+ import type { GovernorOptions } from '../governor';
2
+ import { defaults, timelockOptions, votesOptions } from '../governor';
2
3
  import { accessOptions } from '../set-access-control';
3
4
  import { clockModeOptions } from '../set-clock-mode';
4
5
  import { infoOptions } from '../set-info';
@@ -8,7 +8,8 @@ import { generateERC1155Options } from './erc1155';
8
8
  import { generateStablecoinOptions } from './stablecoin';
9
9
  import { generateGovernorOptions } from './governor';
10
10
  import { generateCustomOptions } from './custom';
11
- import { buildGeneric, GenericOptions, KindedOptions } from '../build-generic';
11
+ import type { GenericOptions, KindedOptions } from '../build-generic';
12
+ import { buildGeneric } from '../build-generic';
12
13
  import { printContract } from '../print';
13
14
  import { OptionsError } from '../error';
14
15
  import { findCover } from '../utils/find-cover';
@@ -76,11 +77,7 @@ function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[
76
77
  const contracts = [];
77
78
 
78
79
  for (const options of generateOptions(kind)) {
79
- const id = crypto
80
- .createHash('sha1')
81
- .update(JSON.stringify(options))
82
- .digest()
83
- .toString('hex');
80
+ const id = crypto.createHash('sha1').update(JSON.stringify(options)).digest().toString('hex');
84
81
 
85
82
  try {
86
83
  const contract = buildGeneric(options);
@@ -99,8 +96,14 @@ function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[
99
96
  } else {
100
97
  const getParents = (c: GeneratedContract) => c.contract.parents.map(p => p.contract.path);
101
98
  return [
102
- ...findCover(contracts.filter(c => c.options.upgradeable), getParents),
103
- ...findCover(contracts.filter(c => !c.options.upgradeable), getParents),
99
+ ...findCover(
100
+ contracts.filter(c => c.options.upgradeable),
101
+ getParents,
102
+ ),
103
+ ...findCover(
104
+ contracts.filter(c => !c.options.upgradeable),
105
+ getParents,
106
+ ),
104
107
  ];
105
108
  }
106
109
  }
@@ -1,31 +1,52 @@
1
- import type { StablecoinOptions } from '../stablecoin';
1
+ import { crossChainBridgingOptions } from '../erc20';
2
2
  import { accessOptions } from '../set-access-control';
3
- import { clockModeOptions } from '../set-clock-mode';
4
3
  import { infoOptions } from '../set-info';
5
- import { upgradeableOptions } from '../set-upgradeable';
4
+ import type { StablecoinOptions } from '../stablecoin';
6
5
  import { generateAlternatives } from './alternatives';
7
6
 
8
7
  const booleans = [true, false];
9
8
 
10
- const blueprint = {
9
+ const erc20Basic = {
11
10
  name: ['MyStablecoin'],
12
11
  symbol: ['MST'],
13
- burnable: booleans,
14
- pausable: booleans,
15
- mintable: booleans,
16
- permit: booleans,
17
- limitations: [false, 'allowlist', 'blocklist'] as const,
18
- votes: [ ...booleans, ...clockModeOptions ] as const,
19
- flashmint: booleans,
12
+ burnable: [false] as const,
13
+ pausable: [false] as const,
14
+ mintable: [false] as const,
15
+ callback: [false] as const,
16
+ permit: [false] as const,
17
+ votes: [false] as const,
18
+ flashmint: [false] as const,
20
19
  premint: ['1'],
21
- custodian: booleans,
20
+ premintChainId: [''],
21
+ crossChainBridging: [false] as const,
22
+ access: [false] as const,
23
+ info: [{}] as const,
24
+ };
25
+
26
+ const erc20Full = {
27
+ name: ['MyStablecoin'],
28
+ symbol: ['MST'],
29
+ burnable: [true] as const,
30
+ pausable: [true] as const,
31
+ mintable: [true] as const,
32
+ callback: [true] as const,
33
+ permit: [true] as const,
34
+ votes: ['timestamp'] as const,
35
+ flashmint: [true] as const,
36
+ premint: ['1'],
37
+ premintChainId: ['10'],
38
+ crossChainBridging: crossChainBridgingOptions,
22
39
  access: accessOptions,
23
- upgradeable: upgradeableOptions,
24
40
  info: infoOptions,
25
41
  };
26
42
 
43
+ const stablecoinExtensions = {
44
+ limitations: [false, 'allowlist', 'blocklist'] as const,
45
+ custodian: booleans,
46
+ upgradeable: [false] as const,
47
+ };
48
+
27
49
  export function* generateStablecoinOptions(): Generator<Required<StablecoinOptions>> {
28
- for (const opts of generateAlternatives(blueprint)) {
29
- yield { ...opts, upgradeable: false };
30
- }
50
+ yield* generateAlternatives({ ...erc20Basic, ...stablecoinExtensions });
51
+ yield* generateAlternatives({ ...erc20Full, ...stablecoinExtensions });
31
52
  }
@@ -11,10 +11,10 @@ export interface SolcInputSources {
11
11
  }
12
12
 
13
13
  /**
14
- * Gets the source code for all imports of a contract, including all transitive dependencies,
15
- * in a format compatible with the Solidity compiler input's `sources` field.
16
- *
17
- * Does not include the contract itself (use `printContract` for that if needed).
14
+ * Gets the source code for all imports of a contract, including all transitive dependencies,
15
+ * in a format compatible with the Solidity compiler input's `sources` field.
16
+ *
17
+ * Does not include the contract itself (use `printContract` for that if needed).
18
18
  *
19
19
  * @param c The contract to get imports for.
20
20
  * @returns A record of import paths to `content` that contains the source code for each contract.
@@ -42,4 +42,4 @@ export function getImports(c: Contract): SolcInputSources {
42
42
  }
43
43
 
44
44
  return result;
45
- }
45
+ }