@openzeppelin/compact-contracts 0.1.0 → 0.3.0-alpha

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 (33) hide show
  1. package/README.md +15 -16
  2. package/access/AccessControl.compact +3 -35
  3. package/access/Ownable.compact +47 -60
  4. package/access/ShieldedAccessControl.compact +43 -10
  5. package/access/ZOwnablePK.compact +45 -10
  6. package/crypto/ElGamal.compact +473 -0
  7. package/multisig/ForwarderPrivate.compact +229 -0
  8. package/multisig/ForwarderShielded.compact +149 -0
  9. package/multisig/ForwarderUnshielded.compact +152 -0
  10. package/multisig/ProposalManager.compact +328 -0
  11. package/multisig/ShieldedTreasury.compact +201 -0
  12. package/multisig/ShieldedTreasuryStateless.compact +76 -0
  13. package/multisig/Signer.compact +312 -0
  14. package/multisig/SignerManager.compact +205 -0
  15. package/multisig/UnshieldedTreasury.compact +114 -0
  16. package/multisig/presets/ShieldedMultiSig.compact +236 -0
  17. package/multisig/presets/ShieldedMultiSigV2.compact +280 -0
  18. package/multisig/presets/ShieldedMultiSigV3.compact +368 -0
  19. package/multisig/presets/forwarder/ForwarderPrivate.compact +125 -0
  20. package/multisig/presets/forwarder/ForwarderShielded.compact +62 -0
  21. package/multisig/presets/forwarder/ForwarderUnshielded.compact +64 -0
  22. package/package.json +12 -6
  23. package/security/Allowlist.compact +101 -0
  24. package/security/Blocklist.compact +99 -0
  25. package/security/Initializable.compact +18 -2
  26. package/security/Pausable.compact +2 -2
  27. package/token/FungibleToken.compact +79 -103
  28. package/token/MultiToken.compact +67 -93
  29. package/token/NativeShieldedToken.compact +285 -0
  30. package/token/NativeShieldedTokenCore.compact +343 -0
  31. package/token/NativeShieldedTokenFamily.compact +287 -0
  32. package/token/NonFungibleToken.compact +85 -110
  33. package/utils/Utils.compact +86 -2
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Generic badge](https://img.shields.io/badge/Compact%20Compiler-0.29.0-1abc9c.svg)](https://docs.midnight.network/relnotes/compact/minokawa-0-18-26-0)
1
+ [![Generic badge](https://img.shields.io/badge/Compact%20Compiler-0.31.0-1abc9c.svg)](https://docs.midnight.network/relnotes/compact/minokawa-0-18-26-0)
2
2
  [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)
3
3
 
4
4
  This project is built on the Midnight Network.
@@ -37,8 +37,8 @@ Follow Midnight's [Compact Developer Tools installation guide](https://docs.midn
37
37
  ```bash
38
38
  $ compact compile --version
39
39
 
40
- Compactc version: 0.29.0
41
- 0.29.0
40
+ Compactc version: 0.31.0
41
+ 0.31.0
42
42
  ```
43
43
 
44
44
  ### Installation
@@ -199,7 +199,6 @@ make sure to check out the [contribution guide](CONTRIBUTING.md) in advance.
199
199
  >
200
200
  > - [Node.js](https://nodejs.org/)
201
201
  > - [Yarn](https://yarnpkg.com/getting-started/install)
202
- > - [Turbo](https://turborepo.com/docs/getting-started/installation)
203
202
  > - [Compact](https://docs.midnight.network/blog/compact-developer-tools)
204
203
 
205
204
  ### Set up the project
@@ -215,20 +214,20 @@ git clone git@github.com:OpenZeppelin/compact-contracts.git
215
214
  ```bash
216
215
  nvm install && \
217
216
  yarn && \
218
- turbo compact
217
+ yarn compact
219
218
  ```
220
219
 
221
220
  ### Run tests
222
221
 
223
222
  ```bash
224
- turbo test
223
+ yarn test
225
224
  ```
226
225
 
227
226
  ### Check/apply Biome formatter
228
227
 
229
228
  ```bash
230
- turbo fmt-and-lint
231
- turbo fmt-and-lint:fix
229
+ yarn fmt-and-lint
230
+ yarn fmt-and-lint:fix
232
231
  ```
233
232
 
234
233
  ### Advanced
@@ -236,8 +235,8 @@ turbo fmt-and-lint:fix
236
235
  #### Targeted compilation
237
236
 
238
237
  ```bash
239
- turbo compact:access
240
- turbo compact:archive
238
+ yarn compact:access
239
+ yarn compact:archive
241
240
  ...
242
241
  ```
243
242
 
@@ -246,11 +245,11 @@ turbo compact:archive
246
245
  ZK key generation is slow and usually unnecessary during development.
247
246
 
248
247
  ```bash
249
- # Individual module compilation (recommended for development)
250
- turbo compact:token --filter=@openzeppelin/compact-contracts -- --skip-zk
251
-
252
248
  # Full compilation with skip-zk (use environment variable)
253
- SKIP_ZK=true turbo compact
249
+ SKIP_ZK=true yarn compact
250
+
251
+ # Access compilation with skip-zk (this compiles security first as a dependency)
252
+ SKIP_ZK=true yarn compact:access
254
253
  ```
255
254
 
256
255
  #### Clean environment
@@ -258,13 +257,13 @@ SKIP_ZK=true turbo compact
258
257
  ```bash
259
258
  # WARNING!
260
259
  # These are destructive commands
261
- turbo clean
260
+ yarn clean
262
261
  rm -rf .turbo/
263
262
  ```
264
263
 
265
264
  ### Troubleshooting
266
265
 
267
- - **Issues with turbo's cache?** Try cleaning: `turbo clean && rm -rf .turbo/`
266
+ - **Issues with turbo's cache?** Try cleaning: `yarn clean && rm -rf .turbo/`
268
267
  - **Node version issues?** Use `nvm use` to switch to the correct version
269
268
 
270
269
  ## Security
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Compact Contracts v0.1.0 (access/AccessControl.compact)
2
+ // OpenZeppelin Compact Contracts v0.3.0-alpha (access/AccessControl.compact)
3
3
 
4
- pragma language_version >= 0.21.0;
4
+ pragma language_version >= 0.23.0;
5
5
 
6
6
  /**
7
7
  * @module AccessControl
@@ -442,38 +442,6 @@ module AccessControl {
442
442
  * @returns {Bytes<32>} accountId - The computed account identifier.
443
443
  */
444
444
  circuit _computeAccountId(): Bytes<32> {
445
- return computeAccountId(wit_AccessControlSK());
446
- }
447
-
448
- /**
449
- * @description Computes an account identifier without on-chain state, allowing a user to derive
450
- * their identity commitment before submitting it in a grant or revoke operation.
451
- * This is the off-chain counterpart to {_computeAccountId} and produces an identical result
452
- * given the same inputs.
453
- *
454
- * @warning OpSec: The `secretKey` parameter is a sensitive secret. Mishandling it can
455
- * permanently compromise the privacy guarantees of this system:
456
- *
457
- * - **Never log or persist** the `secretKey` in plaintext — avoid browser devtools,
458
- * application logs, analytics pipelines, or any observable side-channel.
459
- * - **Store offline or in secure enclaves** — hardware security modules (HSMs),
460
- * air-gapped devices, or encrypted vaults are strongly preferred over hot storage.
461
- * - **Use cryptographically secure randomness** — generate keys with `crypto.getRandomValues()`
462
- * or equivalent; weak or predictable keys can be brute-forced to reveal your identity.
463
- * - **Treat key loss as identity loss** — a lost key cannot be recovered. Back up
464
- * keys securely before using them in role commitments.
465
- * - **Avoid calling this circuit in untrusted environments** — executing this in an
466
- * unverified browser extension, compromised runtime, or shared machine may expose
467
- * the key to a malicious observer.
468
- *
469
- * ## ID Derivation
470
- * `accountId = persistentHash(secretKey)`
471
- *
472
- * @param {Bytes<32>} secretKey - A 32-byte cryptographically secure random value.
473
- *
474
- * @returns {Bytes<32>} accountId - The computed account identifier.
475
- */
476
- export pure circuit computeAccountId(secretKey: Bytes<32>): Bytes<32> {
477
- return persistentHash<Vector<1, Bytes<32>>>([secretKey]);
445
+ return Utils_computeAccountId(wit_AccessControlSK());
478
446
  }
479
447
  }
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Compact Contracts v0.1.0 (access/Ownable.compact)
2
+ // OpenZeppelin Compact Contracts v0.3.0-alpha (access/Ownable.compact)
3
3
 
4
- pragma language_version >= 0.21.0;
4
+ pragma language_version >= 0.23.0;
5
5
 
6
6
  /**
7
7
  * @module Ownable
@@ -85,9 +85,15 @@ pragma language_version >= 0.21.0;
85
85
  */
86
86
  module Ownable {
87
87
  import CompactStandardLibrary;
88
- import "../security/Initializable" prefix Initializable_;
89
88
  import "../utils/Utils" prefix Utils_;
90
89
 
90
+ /**
91
+ * @description Initialization flag, tracked per-module to avoid the compiler's
92
+ * shared transitive-dependency state bug (LFDT-Minokawa/compact#270). See the
93
+ * Initializable module for rationale.
94
+ */
95
+ export ledger _isInitialized: Boolean;
96
+
91
97
  export ledger _owner: Either<Bytes<32>, ContractAddress>;
92
98
 
93
99
  /**
@@ -117,11 +123,38 @@ module Ownable {
117
123
  * @returns {[]} Empty tuple.
118
124
  */
119
125
  export circuit initialize(initialOwner: Either<Bytes<32>, ContractAddress>): [] {
120
- Initializable_initialize();
121
- assert(!_isTargetZero(initialOwner), "Ownable: invalid initial owner");
126
+ assertNotInitialized();
127
+ _isInitialized = true;
128
+ assert(!Utils_isTargetZero(initialOwner), "Ownable: invalid initial owner");
122
129
  _transferOwnership(initialOwner);
123
130
  }
124
131
 
132
+ /**
133
+ * @description Asserts that the contract has been initialized, throwing an error if not.
134
+ *
135
+ * Requirements:
136
+ *
137
+ * - Contract must be initialized.
138
+ *
139
+ * @return {[]} - Empty tuple.
140
+ */
141
+ circuit assertInitialized(): [] {
142
+ assert(_isInitialized, "Ownable: contract not initialized");
143
+ }
144
+
145
+ /**
146
+ * @description Asserts that the contract has not been initialized, throwing an error if it has.
147
+ *
148
+ * Requirements:
149
+ *
150
+ * - Contract must not be initialized.
151
+ *
152
+ * @return {[]} - Empty tuple.
153
+ */
154
+ circuit assertNotInitialized(): [] {
155
+ assert(!_isInitialized, "Ownable: contract already initialized");
156
+ }
157
+
125
158
  /**
126
159
  * @description Returns the current contract owner.
127
160
  *
@@ -134,7 +167,7 @@ module Ownable {
134
167
  * @returns {Either<Bytes<32>, ContractAddress>} - The contract owner.
135
168
  */
136
169
  export circuit owner(): Either<Bytes<32>, ContractAddress> {
137
- Initializable_assertInitialized();
170
+ assertInitialized();
138
171
  return _owner;
139
172
  }
140
173
 
@@ -158,7 +191,7 @@ module Ownable {
158
191
  * @returns {[]} Empty tuple.
159
192
  */
160
193
  export circuit transferOwnership(newOwner: Either<Bytes<32>, ContractAddress>): [] {
161
- Initializable_assertInitialized();
194
+ assertInitialized();
162
195
  const isContractAddr = !newOwner.is_left;
163
196
  assert(!isContractAddr, "Ownable: unsafe ownership transfer");
164
197
  _unsafeTransferOwnership(newOwner);
@@ -184,9 +217,9 @@ module Ownable {
184
217
  * @returns {[]} Empty tuple.
185
218
  */
186
219
  export circuit _unsafeTransferOwnership(newOwner: Either<Bytes<32>, ContractAddress>): [] {
187
- Initializable_assertInitialized();
220
+ assertInitialized();
188
221
  assertOnlyOwner();
189
- assert(!_isTargetZero(newOwner), "Ownable: invalid new owner");
222
+ assert(!Utils_isTargetZero(newOwner), "Ownable: invalid new owner");
190
223
  _unsafeUncheckedTransferOwnership(newOwner);
191
224
  }
192
225
 
@@ -205,7 +238,7 @@ module Ownable {
205
238
  * @returns {[]} Empty tuple.
206
239
  */
207
240
  export circuit renounceOwnership(): [] {
208
- Initializable_assertInitialized();
241
+ assertInitialized();
209
242
  assertOnlyOwner();
210
243
 
211
244
  // We use `left` here because `assertOnlyOwner` would return a misleading
@@ -233,7 +266,7 @@ module Ownable {
233
266
  * @returns {[]} Empty tuple.
234
267
  */
235
268
  export circuit assertOnlyOwner(): [] {
236
- Initializable_assertInitialized();
269
+ assertInitialized();
237
270
  if (_owner.is_left) {
238
271
  assert(_computeAccountId() == _owner.left, "Ownable: caller is not the owner");
239
272
  } else {
@@ -260,7 +293,7 @@ module Ownable {
260
293
  * @returns {[]} Empty tuple.
261
294
  */
262
295
  export circuit _transferOwnership(newOwner: Either<Bytes<32>, ContractAddress>): [] {
263
- Initializable_assertInitialized();
296
+ assertInitialized();
264
297
  const isContractAddr = !newOwner.is_left;
265
298
  assert(!isContractAddr, "Ownable: unsafe ownership transfer");
266
299
  _unsafeUncheckedTransferOwnership(newOwner);
@@ -286,7 +319,7 @@ module Ownable {
286
319
  export circuit _unsafeUncheckedTransferOwnership(
287
320
  newOwner: Either<Bytes<32>, ContractAddress>
288
321
  ): [] {
289
- Initializable_assertInitialized();
322
+ assertInitialized();
290
323
  const canonAcct = Utils_canonicalize<Bytes<32>, ContractAddress>(newOwner);
291
324
  _owner = disclose(canonAcct);
292
325
  }
@@ -302,52 +335,6 @@ module Ownable {
302
335
  * @returns {Bytes<32>} accountId - The computed account identifier.
303
336
  */
304
337
  circuit _computeAccountId(): Bytes<32> {
305
- return computeAccountId(wit_OwnableSK());
306
- }
307
-
308
- /**
309
- * @description Computes an account identifier without on-chain state, allowing a user to derive
310
- * their identity commitment before submitting it in an ownership transfer.
311
- * This is the off-chain counterpart to {_computeAccountId} and produces an identical result
312
- * given the same inputs.
313
- *
314
- * @warning OpSec: The `secretKey` parameter is a sensitive secret. Mishandling it can
315
- * permanently compromise the security of this system:
316
- *
317
- * - **Never log or persist** the `secretKey` in plaintext — avoid browser devtools,
318
- * application logs, analytics pipelines, or any observable side-channel.
319
- * - **Store offline or in secure enclaves** — hardware security modules (HSMs),
320
- * air-gapped devices, or encrypted vaults are strongly preferred over hot storage.
321
- * - **Use cryptographically secure randomness** — generate keys with `crypto.getRandomValues()`
322
- * or equivalent; weak or predictable keys can be brute-forced to reveal your identity.
323
- * - **Treat key loss as identity loss** — a lost key cannot be recovered.
324
- * - **Avoid calling this circuit in untrusted environments** — executing this in an
325
- * unverified browser extension, compromised runtime, or shared machine may expose
326
- * the key to a malicious observer.
327
- *
328
- * ## ID Derivation
329
- * `accountId = persistentHash(secretKey)`
330
- *
331
- * @param {Bytes<32>} secretKey - A 32-byte cryptographically secure random value.
332
- *
333
- * @returns {Bytes<32>} accountId - The computed account identifier.
334
- */
335
- export pure circuit computeAccountId(secretKey: Bytes<32>): Bytes<32> {
336
- return persistentHash<Vector<1, Bytes<32>>>([secretKey]);
337
- }
338
-
339
- /**
340
- * @description Returns `true` if `target`'s active branch (as indicated by `is_left`)
341
- * holds the zero value.
342
- *
343
- * @param {Either<Bytes<32>, ContractAddress>} target - The value to check.
344
- * @returns {Boolean} - `true` if the active branch is zero, `false` otherwise.
345
- */
346
- circuit _isTargetZero(target: Either<Bytes<32>, ContractAddress>): Boolean {
347
- if (target.is_left) {
348
- return target.left == default<Bytes<32>>;
349
- } else {
350
- return target.right == default<ContractAddress>;
351
- }
338
+ return Utils_computeAccountId(wit_OwnableSK());
352
339
  }
353
340
  }
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Compact Contracts v0.1.0 (access/ShieldedAccessControl.compact)
2
+ // OpenZeppelin Compact Contracts v0.3.0-alpha (access/ShieldedAccessControl.compact)
3
3
 
4
- pragma language_version >= 0.21.0;
4
+ pragma language_version >= 0.23.0;
5
5
 
6
6
  /**
7
7
  * @module ShieldedAccessControl
@@ -168,7 +168,6 @@ pragma language_version >= 0.21.0;
168
168
  module ShieldedAccessControl {
169
169
  import CompactStandardLibrary;
170
170
  import "../utils/Utils" prefix Utils_;
171
- import "../security/Initializable" prefix Initializable_;
172
171
 
173
172
  export enum UpdateType {
174
173
  Grant,
@@ -181,6 +180,13 @@ module ShieldedAccessControl {
181
180
  export new type AccountIdentifier = Bytes<32>;
182
181
  export new type RoleNullifier = Bytes<32>;
183
182
 
183
+ /**
184
+ * @description Initialization flag, tracked per-module to avoid the compiler's
185
+ * shared transitive-dependency state bug (LFDT-Minokawa/compact#270). See the
186
+ * Initializable module for rationale.
187
+ */
188
+ export ledger _isInitialized: Boolean;
189
+
184
190
  /**
185
191
  * @ledger _operatorRoles
186
192
  * @description A Merkle tree of role commitments stored as SHA256(role | accountId | instanceSalt | commitmentDomain)
@@ -259,11 +265,38 @@ module ShieldedAccessControl {
259
265
  */
260
266
  export circuit initialize(instanceSalt: Bytes<32>): [] {
261
267
  assert(instanceSalt != default<Bytes<32>>, "ShieldedAccessControl: Instance salt must not be 0");
262
- Initializable_initialize();
268
+ assertNotInitialized();
269
+ _isInitialized = true;
263
270
 
264
271
  _instanceSalt = disclose(instanceSalt);
265
272
  }
266
273
 
274
+ /**
275
+ * @description Asserts that the contract has been initialized, throwing an error if not.
276
+ *
277
+ * Requirements:
278
+ *
279
+ * - Contract must be initialized.
280
+ *
281
+ * @return {[]} - Empty tuple.
282
+ */
283
+ circuit assertInitialized(): [] {
284
+ assert(_isInitialized, "ShieldedAccessControl: contract not initialized");
285
+ }
286
+
287
+ /**
288
+ * @description Asserts that the contract has not been initialized, throwing an error if it has.
289
+ *
290
+ * Requirements:
291
+ *
292
+ * - Contract must not be initialized.
293
+ *
294
+ * @return {[]} - Empty tuple.
295
+ */
296
+ circuit assertNotInitialized(): [] {
297
+ assert(!_isInitialized, "ShieldedAccessControl: contract already initialized");
298
+ }
299
+
267
300
  /**
268
301
  * @description The default admin role for all roles. Only accounts with this role will be able to grant or revoke other roles
269
302
  * unless custom admin roles are created.
@@ -295,7 +328,7 @@ module ShieldedAccessControl {
295
328
  * @return {[]} - Empty tuple.
296
329
  */
297
330
  export circuit assertOnlyRole(role: RoleIdentifier): [] {
298
- Initializable_assertInitialized();
331
+ assertInitialized();
299
332
  assert(_uncheckedCanProveRole(role), "ShieldedAccessControl: unauthorized account");
300
333
  }
301
334
 
@@ -320,7 +353,7 @@ module ShieldedAccessControl {
320
353
  * @return {Boolean} - A boolean determining if a caller successfully proved ownership of `role`
321
354
  */
322
355
  export circuit canProveRole(role: RoleIdentifier): Boolean {
323
- Initializable_assertInitialized();
356
+ assertInitialized();
324
357
  return _uncheckedCanProveRole(role);
325
358
  }
326
359
 
@@ -417,7 +450,7 @@ module ShieldedAccessControl {
417
450
  * @return {[]} - Empty tuple.
418
451
  */
419
452
  export circuit _grantRole(role: RoleIdentifier, accountId: AccountIdentifier): [] {
420
- Initializable_assertInitialized();
453
+ assertInitialized();
421
454
  _updateRole(role, accountId, UpdateType.Grant);
422
455
  }
423
456
 
@@ -449,7 +482,7 @@ module ShieldedAccessControl {
449
482
  * @return {[]} - Empty tuple.
450
483
  */
451
484
  export circuit renounceRole(role: RoleIdentifier, accountIdConfirmation: AccountIdentifier): [] {
452
- Initializable_assertInitialized();
485
+ assertInitialized();
453
486
 
454
487
  assert(accountIdConfirmation == _computeAccountId(),
455
488
  "ShieldedAccessControl: bad confirmation"
@@ -515,7 +548,7 @@ module ShieldedAccessControl {
515
548
  * @return {[]} - Empty tuple.
516
549
  */
517
550
  export circuit _revokeRole(role: RoleIdentifier, accountId: AccountIdentifier): [] {
518
- Initializable_assertInitialized();
551
+ assertInitialized();
519
552
  _updateRole(role, accountId, UpdateType.Revoke);
520
553
  }
521
554
 
@@ -599,7 +632,7 @@ module ShieldedAccessControl {
599
632
  * @return {[]} - Empty tuple.
600
633
  */
601
634
  export circuit _setRoleAdmin(role: RoleIdentifier, adminId: RoleIdentifier): [] {
602
- Initializable_assertInitialized();
635
+ assertInitialized();
603
636
  _adminRoles.insert(disclose(role), disclose(adminId));
604
637
  }
605
638
 
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Compact Contracts v0.1.0 (access/ZOwnablePK.compact)
2
+ // OpenZeppelin Compact Contracts v0.3.0-alpha (access/ZOwnablePK.compact)
3
3
 
4
- pragma language_version >= 0.21.0;
4
+ pragma language_version >= 0.23.0;
5
5
 
6
6
  /**
7
7
  * @module ZOwnablePK
@@ -45,7 +45,13 @@ pragma language_version >= 0.21.0;
45
45
  */
46
46
  module ZOwnablePK {
47
47
  import CompactStandardLibrary;
48
- import "../security/Initializable" prefix Initializable_;
48
+
49
+ /**
50
+ * @description Initialization flag, tracked per-module to avoid the compiler's
51
+ * shared transitive-dependency state bug (LFDT-Minokawa/compact#270). See the
52
+ * Initializable module for rationale.
53
+ */
54
+ export ledger _isInitialized: Boolean;
49
55
 
50
56
  /**
51
57
  * @ledger _ownerCommitment
@@ -56,6 +62,7 @@ module ZOwnablePK {
56
62
  * A commitment of `default<Bytes<32>>` (i.e., zero) indicates the contract is unowned.
57
63
  */
58
64
  export ledger _ownerCommitment: Bytes<32>;
65
+
59
66
  /**
60
67
  * @ledger _counter
61
68
  * @description Internal transfer counter used to prevent commitment reuse.
@@ -64,6 +71,7 @@ module ZOwnablePK {
64
71
  * `instanceSalt` to compute unique owner commitments over time.
65
72
  */
66
73
  export ledger _counter: Counter;
74
+
67
75
  /**
68
76
  * @sealed @ledger _instanceSalt
69
77
  * @description A per-instance value provided at initialization used to namespace
@@ -104,13 +112,40 @@ module ZOwnablePK {
104
112
  * @returns {[]} Empty tuple.
105
113
  */
106
114
  export circuit initialize(ownerId: Bytes<32>, instanceSalt: Bytes<32>): [] {
107
- Initializable_initialize();
115
+ assertNotInitialized();
116
+ _isInitialized = true;
108
117
 
109
118
  assert(ownerId != default<Bytes<32>>, "ZOwnablePK: invalid id");
110
119
  _instanceSalt = disclose(instanceSalt);
111
120
  _transferOwnership(ownerId);
112
121
  }
113
122
 
123
+ /**
124
+ * @description Asserts that the contract has been initialized, throwing an error if not.
125
+ *
126
+ * Requirements:
127
+ *
128
+ * - Contract must be initialized.
129
+ *
130
+ * @return {[]} - Empty tuple.
131
+ */
132
+ circuit assertInitialized(): [] {
133
+ assert(_isInitialized, "ZOwnablePK: contract not initialized");
134
+ }
135
+
136
+ /**
137
+ * @description Asserts that the contract has not been initialized, throwing an error if it has.
138
+ *
139
+ * Requirements:
140
+ *
141
+ * - Contract must not be initialized.
142
+ *
143
+ * @return {[]} - Empty tuple.
144
+ */
145
+ circuit assertNotInitialized(): [] {
146
+ assert(!_isInitialized, "ZOwnablePK: contract already initialized");
147
+ }
148
+
114
149
  /**
115
150
  * @description Returns the current commitment representing the contract owner.
116
151
  * The full commitment is: `SHA256(SHA256(pk, nonce), instanceSalt, counter, domain)`.
@@ -124,7 +159,7 @@ module ZOwnablePK {
124
159
  * @returns {Bytes<32>} The current owner's commitment.
125
160
  */
126
161
  export circuit owner(): Bytes<32> {
127
- Initializable_assertInitialized();
162
+ assertInitialized();
128
163
  return _ownerCommitment;
129
164
  }
130
165
 
@@ -144,7 +179,7 @@ module ZOwnablePK {
144
179
  * @returns {[]} Empty tuple.
145
180
  */
146
181
  export circuit transferOwnership(newOwnerId: Bytes<32>): [] {
147
- Initializable_assertInitialized();
182
+ assertInitialized();
148
183
 
149
184
  assertOnlyOwner();
150
185
  assert(newOwnerId != default<Bytes<32>>, "ZOwnablePK: invalid id");
@@ -166,7 +201,7 @@ module ZOwnablePK {
166
201
  * @returns {[]} Empty tuple.
167
202
  */
168
203
  export circuit renounceOwnership(): [] {
169
- Initializable_assertInitialized();
204
+ assertInitialized();
170
205
 
171
206
  assertOnlyOwner();
172
207
  _ownerCommitment.resetToDefault();
@@ -188,7 +223,7 @@ module ZOwnablePK {
188
223
  * @returns {[]} Empty tuple.
189
224
  */
190
225
  export circuit assertOnlyOwner(): [] {
191
- Initializable_assertInitialized();
226
+ assertInitialized();
192
227
 
193
228
  const nonce = wit_secretNonce();
194
229
  const callerAsEither =
@@ -234,7 +269,7 @@ module ZOwnablePK {
234
269
  * @returns {Bytes<32>} The commitment derived from `id` and `counter`.
235
270
  */
236
271
  export circuit _computeOwnerCommitment(id: Bytes<32>, counter: Uint<64>,): Bytes<32> {
237
- Initializable_assertInitialized();
272
+ assertInitialized();
238
273
  return persistentHash<Vector<4, Bytes<32>>>(
239
274
  [id, _instanceSalt, counter as Field as Bytes<32>, pad(32, "ZOwnablePK:shield:")]
240
275
  );
@@ -296,7 +331,7 @@ module ZOwnablePK {
296
331
  * @returns {[]} Empty tuple.
297
332
  */
298
333
  export circuit _transferOwnership(newOwnerId: Bytes<32>): [] {
299
- Initializable_assertInitialized();
334
+ assertInitialized();
300
335
 
301
336
  _counter.increment(1);
302
337
  _ownerCommitment = disclose(_computeOwnerCommitment(newOwnerId, _counter));