@openzeppelin/compact-contracts 0.4.0-alpha.1 → 0.4.0-alpha.3

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 (46) hide show
  1. package/README.md +9 -5
  2. package/access/AccessControl.compact +13 -13
  3. package/access/Ownable.compact +15 -9
  4. package/access/ShieldedAccessControl.compact +25 -1
  5. package/access/ZOwnablePK.compact +8 -8
  6. package/crypto/EcdhMask.compact +1 -1
  7. package/crypto/Ecdsa.compact +4 -4
  8. package/crypto/Eip712.compact +168 -0
  9. package/crypto/ElGamal.compact +44 -3
  10. package/multisig/EcdsaSignerManager.compact +32 -15
  11. package/multisig/ForwarderPrivate.compact +11 -5
  12. package/multisig/ForwarderShielded.compact +2 -2
  13. package/multisig/ForwarderUnshielded.compact +2 -2
  14. package/multisig/ProposalManager.compact +194 -22
  15. package/multisig/ShieldedTreasury.compact +28 -1
  16. package/multisig/ShieldedTreasuryStateless.compact +1 -1
  17. package/multisig/Signer.compact +27 -79
  18. package/multisig/UnshieldedTreasury.compact +9 -1
  19. package/multisig/{presets/forwarder/ForwarderPrivate.compact → examples/ForwarderPrivateExample.compact} +3 -3
  20. package/multisig/{presets/forwarder/ForwarderShielded.compact → examples/ForwarderShieldedExample.compact} +3 -3
  21. package/multisig/{presets/forwarder/ForwarderUnshielded.compact → examples/ForwarderUnshieldedExample.compact} +3 -3
  22. package/multisig/examples/NativeShieldedTokenIssuerExample.compact +143 -0
  23. package/multisig/examples/ShieldedMultiSigV2Example.compact +77 -0
  24. package/multisig/presets/NativeShieldedTokenIssuer.compact +557 -0
  25. package/multisig/presets/ShieldedMultiSigV2.compact +251 -188
  26. package/package.json +15 -11
  27. package/security/Allowlist.compact +5 -5
  28. package/security/Blocklist.compact +5 -5
  29. package/security/Initializable.compact +8 -4
  30. package/security/Pausable.compact +10 -6
  31. package/token/ConfidentialFungibleToken.compact +337 -79
  32. package/token/FungibleToken.compact +35 -21
  33. package/token/MultiToken.compact +15 -15
  34. package/token/NativeShieldedToken.compact +65 -16
  35. package/token/NativeShieldedTokenCore.compact +57 -15
  36. package/token/NativeShieldedTokenFamily.compact +66 -16
  37. package/token/NonFungibleToken.compact +83 -34
  38. package/token/extensions/ConfidentialFungibleTokenPublicSupply.compact +11 -6
  39. package/token/extensions/NativeShieldedTokenDerivedNonce.compact +2 -2
  40. package/token/extensions/NativeShieldedTokenFamilyPublicSupply.compact +7 -7
  41. package/token/extensions/NativeShieldedTokenPublicSupply.compact +7 -7
  42. package/token/extensions/NativeShieldedTokenPublicSupplyCore.compact +5 -5
  43. package/utils/EvmAbi.compact +134 -0
  44. package/utils/Utils.compact +11 -1
  45. package/multisig/presets/ShieldedMultiSig.compact +0 -227
  46. package/multisig/presets/ShieldedMultiSigV3.compact +0 -311
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Compact Contracts v0.4.0-alpha.1 (token/NativeShieldedTokenCore.compact)
2
+ // OpenZeppelin Compact Contracts v0.4.0-alpha.3 (token/NativeShieldedTokenCore.compact)
3
3
 
4
4
  pragma language_version >= 0.26.0;
5
5
 
@@ -44,6 +44,18 @@ pragma language_version >= 0.26.0;
44
44
  * compose `NativeShieldedTokenDerivedNonce` and pass its `_deriveNonce()`
45
45
  * output, at the cost of making those mints recipient-public.
46
46
  *
47
+ * @notice A recipient may be any coin public key, or this contract's own
48
+ * address. Any other contract address is rejected.
49
+ *
50
+ * @dev Recipient arm
51
+ * The ledger accepts a contract-addressed commitment only if the recipient
52
+ * contract's own call claims it as a shielded receive in the same transaction,
53
+ * and no primitive claims a receive on another contract's behalf. So the
54
+ * address arm is accepted only for `kernel.self()`, where `_mint` / `_burn`
55
+ * claim the coin themselves in the same call. The flavors do not expose the
56
+ * arm at all: they take a `ZswapCoinPublicKey` and offer `_mintToSelf` for
57
+ * contract-held coins.
58
+ *
47
59
  * @dev Burn variants
48
60
  * `_burn` destroys value from a coin provided within the current transaction
49
61
  * (e.g. the caller's wallet pays the contract): it receives the coin and spends
@@ -70,8 +82,18 @@ module NativeShieldedTokenCore {
70
82
  */
71
83
  export ledger _isInitialized: Boolean;
72
84
 
85
+ /**
86
+ * @description The token's human-readable name, set once at construction.
87
+ */
73
88
  export sealed ledger _name: Opaque<"string">;
89
+ /**
90
+ * @description The token's ticker symbol, set once at construction.
91
+ */
74
92
  export sealed ledger _symbol: Opaque<"string">;
93
+ /**
94
+ * @description The number of decimals used to display balances, set once at
95
+ * construction. Purely presentational; no circuit scales by it.
96
+ */
75
97
  export sealed ledger _decimals: Uint<8>;
76
98
 
77
99
  /**
@@ -130,7 +152,7 @@ module NativeShieldedTokenCore {
130
152
  * @dev Does not gate on init (it reports it), so it is safe to call before
131
153
  * `initialize`.
132
154
  *
133
- * @circuitInfo k=6, rows=26
155
+ * @constraints k=6, rows=24
134
156
  *
135
157
  * @return {Boolean} - True once `initialize` has run.
136
158
  */
@@ -141,7 +163,7 @@ module NativeShieldedTokenCore {
141
163
  /**
142
164
  * @description Returns the token name.
143
165
  *
144
- * @circuitInfo k=6, rows=28
166
+ * @constraints k=6, rows=26
145
167
  *
146
168
  * Requirements:
147
169
  *
@@ -157,7 +179,7 @@ module NativeShieldedTokenCore {
157
179
  /**
158
180
  * @description Returns the symbol of the token.
159
181
  *
160
- * @circuitInfo k=6, rows=28
182
+ * @constraints k=6, rows=26
161
183
  *
162
184
  * Requirements:
163
185
  *
@@ -175,7 +197,7 @@ module NativeShieldedTokenCore {
175
197
  * @dev This is a display convention only. The protocol stores and operates
176
198
  * on integer values without reference to decimals.
177
199
  *
178
- * @circuitInfo k=6, rows=28
200
+ * @constraints k=6, rows=26
179
201
  *
180
202
  * Requirements:
181
203
  *
@@ -192,7 +214,7 @@ module NativeShieldedTokenCore {
192
214
  * @description Returns the coin color for `domain` under this contract's
193
215
  * address: `tokenType(domain, kernel.self())`, computed at call time.
194
216
  *
195
- * @circuitInfo k=13, rows=4248
217
+ * @constraints k=13, rows=4239
196
218
  *
197
219
  * Requirements:
198
220
  *
@@ -212,21 +234,26 @@ module NativeShieldedTokenCore {
212
234
  *
213
235
  * @dev The caller is fully responsible for nonce uniqueness. Reusing a
214
236
  * nonce for the same (domain, value, recipient) produces a duplicate
215
- * commitment, which the protocol rejects.
237
+ * commitment, which the protocol rejects. A `right(kernel.self())` recipient
238
+ * is claimed via `receiveShielded` in this same call, so the consumer SHOULD
239
+ * persist the returned coin info: it is the contract's holding and is not
240
+ * otherwise recoverable.
216
241
  *
217
242
  * @notice The returned coin info is the only copy available to the
218
243
  * recipient; callers SHOULD deliver it out of band. Wallets cannot detect
219
244
  * contract-minted coins by scanning the chain.
220
245
  *
221
- * @circuitInfo k=14, rows=11119
246
+ * @constraints k=15, rows=16980
222
247
  *
223
248
  * Requirements:
224
249
  *
225
250
  * - Contract is initialized.
226
251
  * - `recipient` is not zero.
252
+ * - `recipient`, if a contract address, is this contract's own address.
227
253
  *
228
254
  * @param {Bytes<32>} domain - 32-byte token discriminator.
229
- * @param {Either<ZswapCoinPublicKey, ContractAddress>} recipient - The coin recipient.
255
+ * @param {Either<ZswapCoinPublicKey, ContractAddress>} recipient - The coin
256
+ * recipient: any coin public key, or this contract's own address.
230
257
  * @param {Uint<64>} amount - Quantity to mint. Capped at `Uint<64>` by the protocol.
231
258
  * @param {Bytes<32>} nonce - Caller-supplied nonce. Must be unique per (domain, contract).
232
259
  * @return {ShieldedCoinInfo} - The newly created coin's info (nonce, color, value).
@@ -238,9 +265,16 @@ module NativeShieldedTokenCore {
238
265
  nonce: Bytes<32>
239
266
  ): ShieldedCoinInfo {
240
267
  assertInitialized();
268
+ const self = kernel.self();
241
269
  assert(!Utils_isKeyOrAddressZero(recipient), "NativeShieldedToken: invalid recipient");
270
+ assert(recipient.is_left || recipient.right == self, "NativeShieldedToken: recipient contract must be self");
242
271
 
243
- return mintShieldedToken(disclose(domain), disclose(amount), disclose(nonce), disclose(recipient));
272
+ const coin = mintShieldedToken(disclose(domain), disclose(amount), disclose(nonce), disclose(recipient));
273
+ if (disclose(!recipient.is_left)) {
274
+ receiveShielded(coin);
275
+ }
276
+
277
+ return coin;
244
278
  }
245
279
 
246
280
  /**
@@ -255,13 +289,14 @@ module NativeShieldedTokenCore {
255
289
  * @dev The coin is received by the contract and spent in the same
256
290
  * transaction, so the spend goes through `sendImmediateShielded` (the
257
291
  * transient path). For coins the contract already holds, use
258
- * `_burnFromSelf` instead.
292
+ * `_burnFromSelf` instead. A `right(kernel.self())` refund is claimed via
293
+ * `receiveShielded` in this same call.
259
294
  *
260
295
  * @notice The returned refund coin info is the only copy available to
261
296
  * `refundTo`; callers SHOULD deliver it out of band. Wallets cannot detect
262
297
  * contract-sent coins by scanning the chain.
263
298
  *
264
- * @circuitInfo k=16, rows=47932
299
+ * @constraints k=16, rows=53639
265
300
  *
266
301
  * Requirements:
267
302
  *
@@ -270,12 +305,14 @@ module NativeShieldedTokenCore {
270
305
  * - `amount` is less than or equal to `coin.value`.
271
306
  * - `refundTo` is not zero (the zero key is the burn address; a zero
272
307
  * `refundTo` would silently burn the change as well).
308
+ * - `refundTo`, if a contract address, is this contract's own address.
273
309
  *
274
310
  * @param {Bytes<32>} domain - 32-byte token discriminator.
275
311
  * @param {ShieldedCoinInfo} coin - The coin to burn from.
276
312
  * @param {Uint<128>} amount - Value to destroy. Must be <= `coin.value`.
277
313
  * @param {Either<ZswapCoinPublicKey, ContractAddress>} refundTo - Where to
278
- * route the unspent portion (`coin.value - amount`).
314
+ * route the unspent portion (`coin.value - amount`): any coin public key, or
315
+ * this contract's own address.
279
316
  * @return {Maybe<ShieldedCoinInfo>} - The refund coin created for `refundTo`,
280
317
  * or `none` if the coin was burned in full.
281
318
  */
@@ -286,9 +323,11 @@ module NativeShieldedTokenCore {
286
323
  refundTo: Either<ZswapCoinPublicKey, ContractAddress>
287
324
  ): Maybe<ShieldedCoinInfo> {
288
325
  assertInitialized();
289
- assert(coin.color == tokenType(disclose(domain), kernel.self()), "NativeShieldedToken: wrong token");
326
+ const self = kernel.self();
327
+ assert(coin.color == tokenType(disclose(domain), self), "NativeShieldedToken: wrong token");
290
328
  assert(coin.value >= amount, "NativeShieldedToken: insufficient coin value");
291
329
  assert(!Utils_isKeyOrAddressZero(refundTo), "NativeShieldedToken: invalid refund target");
330
+ assert(refundTo.is_left || refundTo.right == self, "NativeShieldedToken: refund contract must be self");
292
331
 
293
332
  receiveShielded(disclose(coin));
294
333
  const sendRes = sendImmediateShielded(disclose(coin), shieldedBurnAddress(), disclose(amount));
@@ -299,6 +338,9 @@ module NativeShieldedTokenCore {
299
338
  disclose(refundTo),
300
339
  disclose(sendRes.change.value.value)
301
340
  );
341
+ if (disclose(!refundTo.is_left)) {
342
+ receiveShielded(refundRes.sent);
343
+ }
302
344
  return some<ShieldedCoinInfo>(refundRes.sent);
303
345
  }
304
346
  return none<ShieldedCoinInfo>();
@@ -313,7 +355,7 @@ module NativeShieldedTokenCore {
313
355
  * ledger state: the change replaces `coin` as the contract's holding, and
314
356
  * its info is not otherwise recoverable.
315
357
  *
316
- * @circuitInfo k=15, rows=23583
358
+ * @constraints k=15, rows=23484
317
359
  *
318
360
  * Requirements:
319
361
  *
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Compact Contracts v0.4.0-alpha.1 (token/NativeShieldedTokenFamily.compact)
2
+ // OpenZeppelin Compact Contracts v0.4.0-alpha.3 (token/NativeShieldedTokenFamily.compact)
3
3
 
4
4
  pragma language_version >= 0.26.0;
5
5
 
@@ -26,6 +26,10 @@ pragma language_version >= 0.26.0;
26
26
  * set of core state (a single init flag and one name/symbol/decimals).
27
27
  * Pick one flavor per contract.
28
28
  *
29
+ * @notice Recipients must be coin public keys: contract-addressed recipients
30
+ * are not supported at this layer. For a coin the contract holds itself, use
31
+ * `_mintToSelf`, which mints to `kernel.self()` and claims it in the same call.
32
+ *
29
33
  * @notice This module exposes composable building blocks for minting and
30
34
  * burning native shielded coins. It does NOT include access control: consuming
31
35
  * contracts compose that via the module/contract pattern (Ownable,
@@ -97,7 +101,7 @@ module NativeShieldedTokenFamily {
97
101
  /**
98
102
  * @description Returns whether the contract has been initialized.
99
103
  *
100
- * @circuitInfo k=6, rows=26
104
+ * @constraints k=6, rows=24
101
105
  *
102
106
  * @return {Boolean} - True once `initialize` has run.
103
107
  */
@@ -110,7 +114,7 @@ module NativeShieldedTokenFamily {
110
114
  * contract. Per-type identity belongs in the consumer's own state; see the
111
115
  * module notes.
112
116
  *
113
- * @circuitInfo k=6, rows=28
117
+ * @constraints k=6, rows=26
114
118
  *
115
119
  * Requirements:
116
120
  *
@@ -126,7 +130,7 @@ module NativeShieldedTokenFamily {
126
130
  * @description Returns the family symbol shared by all token types of this
127
131
  * contract.
128
132
  *
129
- * @circuitInfo k=6, rows=28
133
+ * @constraints k=6, rows=26
130
134
  *
131
135
  * Requirements:
132
136
  *
@@ -142,7 +146,7 @@ module NativeShieldedTokenFamily {
142
146
  * @description Returns the family-wide number of decimals used to get the
143
147
  * user representation.
144
148
  *
145
- * @circuitInfo k=6, rows=28
149
+ * @constraints k=6, rows=26
146
150
  *
147
151
  * Requirements:
148
152
  *
@@ -158,7 +162,7 @@ module NativeShieldedTokenFamily {
158
162
  * @description Returns the coin color (token type) for `domain` under this
159
163
  * contract's address, so integrators do not have to re-derive it by hand.
160
164
  *
161
- * @circuitInfo k=13, rows=4248
165
+ * @constraints k=13, rows=4239
162
166
  *
163
167
  * Requirements:
164
168
  *
@@ -186,7 +190,7 @@ module NativeShieldedTokenFamily {
186
190
  * recipient; callers SHOULD deliver it out of band. Wallets cannot detect
187
191
  * contract-minted coins by scanning the chain.
188
192
  *
189
- * @circuitInfo k=14, rows=11119
193
+ * @constraints k=14, rows=10727
190
194
  *
191
195
  * Requirements:
192
196
  *
@@ -195,18 +199,59 @@ module NativeShieldedTokenFamily {
195
199
  *
196
200
  * @param {Bytes<32>} domain - 32-byte token discriminator. Same domain + same
197
201
  * contract address produces the same coin color (i.e. same token type).
198
- * @param {Either<ZswapCoinPublicKey, ContractAddress>} recipient - The coin recipient.
202
+ * @param {ZswapCoinPublicKey} recipient - The coin recipient.
199
203
  * @param {Uint<64>} amount - Quantity to mint. Capped at `Uint<64>` by the protocol.
200
204
  * @param {Bytes<32>} nonce - Caller-supplied nonce. Must be unique per (domain, contract).
201
205
  * @return {ShieldedCoinInfo} - The newly created coin's info (nonce, color, value).
202
206
  */
203
207
  export circuit _mint(
204
208
  domain: Bytes<32>,
205
- recipient: Either<ZswapCoinPublicKey, ContractAddress>,
209
+ recipient: ZswapCoinPublicKey,
210
+ amount: Uint<64>,
211
+ nonce: Bytes<32>
212
+ ): ShieldedCoinInfo {
213
+ return Core__mint(
214
+ domain,
215
+ left<ZswapCoinPublicKey, ContractAddress>(recipient),
216
+ amount,
217
+ nonce
218
+ );
219
+ }
220
+
221
+ /**
222
+ * @description Mints `amount` of the token identified by `domain` to this
223
+ * contract itself, claiming the coin in the same call. Forwards to
224
+ * `NativeShieldedTokenCore._mint` with `right(kernel.self())`.
225
+ *
226
+ * @dev Nonce uniqueness is the caller's responsibility, as in `_mint`. Spend
227
+ * the coin later with `_burnFromSelf`, once it carries an `mt_index`.
228
+ *
229
+ * @notice The consumer SHOULD persist the returned coin info in its own
230
+ * ledger state: it is the contract's holding and is not otherwise
231
+ * recoverable.
232
+ *
233
+ * @constraints k=14, rows=16309
234
+ *
235
+ * Requirements:
236
+ *
237
+ * - Contract is initialized.
238
+ *
239
+ * @param {Bytes<32>} domain - 32-byte token discriminator.
240
+ * @param {Uint<64>} amount - Quantity to mint. Capped at `Uint<64>` by the protocol.
241
+ * @param {Bytes<32>} nonce - Caller-supplied nonce. Must be unique per (domain, contract).
242
+ * @return {ShieldedCoinInfo} - The newly created coin's info (nonce, color, value).
243
+ */
244
+ export circuit _mintToSelf(
245
+ domain: Bytes<32>,
206
246
  amount: Uint<64>,
207
247
  nonce: Bytes<32>
208
248
  ): ShieldedCoinInfo {
209
- return Core__mint(domain, recipient, amount, nonce);
249
+ return Core__mint(
250
+ domain,
251
+ right<ZswapCoinPublicKey, ContractAddress>(kernel.self()),
252
+ amount,
253
+ nonce
254
+ );
210
255
  }
211
256
 
212
257
  /**
@@ -227,7 +272,7 @@ module NativeShieldedTokenFamily {
227
272
  * `refundTo`; callers SHOULD deliver it out of band. Wallets cannot detect
228
273
  * contract-sent coins by scanning the chain.
229
274
  *
230
- * @circuitInfo k=16, rows=47932
275
+ * @constraints k=16, rows=41603
231
276
  *
232
277
  * Requirements:
233
278
  *
@@ -240,8 +285,8 @@ module NativeShieldedTokenFamily {
240
285
  * @param {Bytes<32>} domain - 32-byte token discriminator.
241
286
  * @param {ShieldedCoinInfo} coin - The coin to burn from.
242
287
  * @param {Uint<128>} amount - Value to destroy. Must be <= `coin.value`.
243
- * @param {Either<ZswapCoinPublicKey, ContractAddress>} refundTo - Where to
244
- * route the unspent portion (`coin.value - amount`).
288
+ * @param {ZswapCoinPublicKey} refundTo - Where to route the unspent
289
+ * portion (`coin.value - amount`).
245
290
  * @return {Maybe<ShieldedCoinInfo>} - The refund coin created for `refundTo`,
246
291
  * or `none` if the coin was burned in full.
247
292
  */
@@ -249,9 +294,14 @@ module NativeShieldedTokenFamily {
249
294
  domain: Bytes<32>,
250
295
  coin: ShieldedCoinInfo,
251
296
  amount: Uint<128>,
252
- refundTo: Either<ZswapCoinPublicKey, ContractAddress>
297
+ refundTo: ZswapCoinPublicKey
253
298
  ): Maybe<ShieldedCoinInfo> {
254
- return Core__burn(domain, coin, amount, refundTo);
299
+ return Core__burn(
300
+ domain,
301
+ coin,
302
+ amount,
303
+ left<ZswapCoinPublicKey, ContractAddress>(refundTo)
304
+ );
255
305
  }
256
306
 
257
307
  /**
@@ -263,7 +313,7 @@ module NativeShieldedTokenFamily {
263
313
  * ledger state: the change replaces `coin` as the contract's holding, and
264
314
  * its info is not otherwise recoverable.
265
315
  *
266
- * @circuitInfo k=15, rows=23583
316
+ * @constraints k=15, rows=23484
267
317
  *
268
318
  * Requirements:
269
319
  *