@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.
- package/README.md +15 -16
- package/access/AccessControl.compact +3 -35
- package/access/Ownable.compact +47 -60
- package/access/ShieldedAccessControl.compact +43 -10
- package/access/ZOwnablePK.compact +45 -10
- package/crypto/ElGamal.compact +473 -0
- package/multisig/ForwarderPrivate.compact +229 -0
- package/multisig/ForwarderShielded.compact +149 -0
- package/multisig/ForwarderUnshielded.compact +152 -0
- package/multisig/ProposalManager.compact +328 -0
- package/multisig/ShieldedTreasury.compact +201 -0
- package/multisig/ShieldedTreasuryStateless.compact +76 -0
- package/multisig/Signer.compact +312 -0
- package/multisig/SignerManager.compact +205 -0
- package/multisig/UnshieldedTreasury.compact +114 -0
- package/multisig/presets/ShieldedMultiSig.compact +236 -0
- package/multisig/presets/ShieldedMultiSigV2.compact +280 -0
- package/multisig/presets/ShieldedMultiSigV3.compact +368 -0
- package/multisig/presets/forwarder/ForwarderPrivate.compact +125 -0
- package/multisig/presets/forwarder/ForwarderShielded.compact +62 -0
- package/multisig/presets/forwarder/ForwarderUnshielded.compact +64 -0
- package/package.json +12 -6
- package/security/Allowlist.compact +101 -0
- package/security/Blocklist.compact +99 -0
- package/security/Initializable.compact +18 -2
- package/security/Pausable.compact +2 -2
- package/token/FungibleToken.compact +79 -103
- package/token/MultiToken.compact +67 -93
- package/token/NativeShieldedToken.compact +285 -0
- package/token/NativeShieldedTokenCore.compact +343 -0
- package/token/NativeShieldedTokenFamily.compact +287 -0
- package/token/NonFungibleToken.compact +85 -110
- package/utils/Utils.compact +86 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://docs.midnight.network/relnotes/compact/minokawa-0-18-26-0)
|
|
2
2
|
[](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.
|
|
41
|
-
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
|
-
|
|
217
|
+
yarn compact
|
|
219
218
|
```
|
|
220
219
|
|
|
221
220
|
### Run tests
|
|
222
221
|
|
|
223
222
|
```bash
|
|
224
|
-
|
|
223
|
+
yarn test
|
|
225
224
|
```
|
|
226
225
|
|
|
227
226
|
### Check/apply Biome formatter
|
|
228
227
|
|
|
229
228
|
```bash
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
240
|
-
|
|
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
|
|
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
|
-
|
|
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: `
|
|
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.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-alpha (access/AccessControl.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 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
|
|
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
|
}
|
package/access/Ownable.compact
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-alpha (access/Ownable.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 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
|
-
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
220
|
+
assertInitialized();
|
|
188
221
|
assertOnlyOwner();
|
|
189
|
-
assert(!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-alpha (access/ShieldedAccessControl.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-alpha (access/ZOwnablePK.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
334
|
+
assertInitialized();
|
|
300
335
|
|
|
301
336
|
_counter.increment(1);
|
|
302
337
|
_ownerCommitment = disclose(_computeOwnerCommitment(newOwnerId, _counter));
|