@openzeppelin/compact-contracts 0.3.0-alpha.2 → 0.3.0-rc.2
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/access/AccessControl.compact +1 -1
- package/access/Ownable.compact +1 -1
- package/access/ShieldedAccessControl.compact +1 -1
- package/access/ZOwnablePK.compact +12 -3
- package/crypto/EcdhMask.compact +1 -1
- package/crypto/ElGamal.compact +44 -3
- package/multisig/ForwarderPrivate.compact +1 -1
- package/multisig/ForwarderShielded.compact +1 -1
- package/multisig/ForwarderUnshielded.compact +1 -1
- package/multisig/ProposalManager.compact +1 -1
- package/multisig/ShieldedTreasury.compact +1 -1
- package/multisig/ShieldedTreasuryStateless.compact +1 -1
- package/multisig/Signer.compact +1 -1
- package/multisig/UnshieldedTreasury.compact +1 -1
- package/multisig/presets/ShieldedMultiSig.compact +1 -1
- package/multisig/presets/ShieldedMultiSigV2.compact +1 -1
- package/multisig/presets/forwarder/ForwarderPrivate.compact +1 -1
- package/multisig/presets/forwarder/ForwarderShielded.compact +1 -1
- package/multisig/presets/forwarder/ForwarderUnshielded.compact +1 -1
- package/package.json +1 -1
- package/security/Allowlist.compact +1 -1
- package/security/Blocklist.compact +1 -1
- package/security/Initializable.compact +1 -1
- package/security/Pausable.compact +1 -1
- package/token/ConfidentialFungibleToken.compact +253 -67
- package/token/FungibleToken.compact +1 -1
- package/token/MultiToken.compact +1 -1
- package/token/NativeShieldedToken.compact +59 -10
- package/token/NativeShieldedTokenCore.compact +41 -9
- package/token/NativeShieldedTokenFamily.compact +60 -10
- package/token/NonFungibleToken.compact +63 -19
- package/token/examples/ZOwnableNativeShieldedTokenExample.compact +109 -0
- package/token/extensions/ConfidentialFungibleTokenPublicSupply.compact +1 -1
- package/token/extensions/NativeShieldedTokenDerivedNonce.compact +1 -1
- package/token/extensions/NativeShieldedTokenFamilyPublicSupply.compact +2 -2
- package/token/extensions/NativeShieldedTokenPublicSupply.compact +2 -2
- package/token/presets/ZOwnableNativeShieldedToken.compact +314 -0
- package/utils/Utils.compact +11 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0-
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-rc.2 (token/NativeShieldedToken.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -20,6 +20,10 @@ pragma language_version >= 0.23.0;
|
|
|
20
20
|
* share one set of core state (a single init flag and one name/symbol/decimals).
|
|
21
21
|
* Pick one flavor per contract.
|
|
22
22
|
*
|
|
23
|
+
* @notice Recipients must be coin public keys: contract-addressed recipients
|
|
24
|
+
* are not supported at this layer. For a coin the contract holds itself, use
|
|
25
|
+
* `_mintToSelf`, which mints to `kernel.self()` and claims it in the same call.
|
|
26
|
+
*
|
|
23
27
|
* @notice This module exposes composable building blocks for minting and
|
|
24
28
|
* burning native shielded coins. It does NOT include access control: consuming
|
|
25
29
|
* contracts compose that via the module/contract pattern (Ownable,
|
|
@@ -190,25 +194,65 @@ module NativeShieldedToken {
|
|
|
190
194
|
* recipient; callers SHOULD deliver it out of band. Wallets cannot detect
|
|
191
195
|
* contract-minted coins by scanning the chain.
|
|
192
196
|
*
|
|
193
|
-
* @circuitInfo k=14, rows=
|
|
197
|
+
* @circuitInfo k=14, rows=10473
|
|
194
198
|
*
|
|
195
199
|
* Requirements:
|
|
196
200
|
*
|
|
197
201
|
* - Contract is initialized.
|
|
198
202
|
* - `recipient` is not zero.
|
|
199
203
|
*
|
|
200
|
-
* @param {
|
|
204
|
+
* @param {ZswapCoinPublicKey} recipient - The coin recipient.
|
|
201
205
|
* @param {Uint<64>} amount - Quantity to mint. Capped at `Uint<64>` by the protocol.
|
|
202
206
|
* @param {Bytes<32>} nonce - Caller-supplied nonce. Must be unique for this
|
|
203
207
|
* contract's color.
|
|
204
208
|
* @return {ShieldedCoinInfo} - The newly created coin's info (nonce, color, value).
|
|
205
209
|
*/
|
|
206
210
|
export circuit _mint(
|
|
207
|
-
recipient:
|
|
211
|
+
recipient: ZswapCoinPublicKey,
|
|
212
|
+
amount: Uint<64>,
|
|
213
|
+
nonce: Bytes<32>
|
|
214
|
+
): ShieldedCoinInfo {
|
|
215
|
+
return Core__mint(
|
|
216
|
+
_domain,
|
|
217
|
+
left<ZswapCoinPublicKey, ContractAddress>(recipient),
|
|
218
|
+
amount,
|
|
219
|
+
nonce
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @description Mints `amount` to this contract itself, claiming the coin in
|
|
225
|
+
* the same call. Forwards to `NativeShieldedTokenCore._mint` with
|
|
226
|
+
* `right(kernel.self())`.
|
|
227
|
+
*
|
|
228
|
+
* @dev Nonce uniqueness is the caller's responsibility, as in `_mint`. Spend
|
|
229
|
+
* the coin later with `_burnFromSelf`, once it carries an `mt_index`.
|
|
230
|
+
*
|
|
231
|
+
* @notice The consumer SHOULD persist the returned coin info in its own
|
|
232
|
+
* ledger state: it is the contract's holding and is not otherwise
|
|
233
|
+
* recoverable.
|
|
234
|
+
*
|
|
235
|
+
* @circuitInfo k=14, rows=16070
|
|
236
|
+
*
|
|
237
|
+
* Requirements:
|
|
238
|
+
*
|
|
239
|
+
* - Contract is initialized.
|
|
240
|
+
*
|
|
241
|
+
* @param {Uint<64>} amount - Quantity to mint. Capped at `Uint<64>` by the protocol.
|
|
242
|
+
* @param {Bytes<32>} nonce - Caller-supplied nonce. Must be unique for this
|
|
243
|
+
* contract's color.
|
|
244
|
+
* @return {ShieldedCoinInfo} - The newly created coin's info (nonce, color, value).
|
|
245
|
+
*/
|
|
246
|
+
export circuit _mintToSelf(
|
|
208
247
|
amount: Uint<64>,
|
|
209
248
|
nonce: Bytes<32>
|
|
210
249
|
): ShieldedCoinInfo {
|
|
211
|
-
return Core__mint(
|
|
250
|
+
return Core__mint(
|
|
251
|
+
_domain,
|
|
252
|
+
right<ZswapCoinPublicKey, ContractAddress>(kernel.self()),
|
|
253
|
+
amount,
|
|
254
|
+
nonce
|
|
255
|
+
);
|
|
212
256
|
}
|
|
213
257
|
|
|
214
258
|
/**
|
|
@@ -229,7 +273,7 @@ module NativeShieldedToken {
|
|
|
229
273
|
* `refundTo`; callers SHOULD deliver it out of band. Wallets cannot detect
|
|
230
274
|
* contract-sent coins by scanning the chain.
|
|
231
275
|
*
|
|
232
|
-
* @circuitInfo k=16, rows=
|
|
276
|
+
* @circuitInfo k=16, rows=41492
|
|
233
277
|
*
|
|
234
278
|
* Requirements:
|
|
235
279
|
*
|
|
@@ -241,17 +285,22 @@ module NativeShieldedToken {
|
|
|
241
285
|
*
|
|
242
286
|
* @param {ShieldedCoinInfo} coin - The coin to burn from.
|
|
243
287
|
* @param {Uint<128>} amount - Value to destroy. Must be <= `coin.value`.
|
|
244
|
-
* @param {
|
|
245
|
-
*
|
|
288
|
+
* @param {ZswapCoinPublicKey} refundTo - Where to route the unspent
|
|
289
|
+
* portion (`coin.value - amount`).
|
|
246
290
|
* @return {Maybe<ShieldedCoinInfo>} - The refund coin created for `refundTo`,
|
|
247
291
|
* or `none` if the coin was burned in full.
|
|
248
292
|
*/
|
|
249
293
|
export circuit _burn(
|
|
250
294
|
coin: ShieldedCoinInfo,
|
|
251
295
|
amount: Uint<128>,
|
|
252
|
-
refundTo:
|
|
296
|
+
refundTo: ZswapCoinPublicKey
|
|
253
297
|
): Maybe<ShieldedCoinInfo> {
|
|
254
|
-
return Core__burn(
|
|
298
|
+
return Core__burn(
|
|
299
|
+
_domain,
|
|
300
|
+
coin,
|
|
301
|
+
amount,
|
|
302
|
+
left<ZswapCoinPublicKey, ContractAddress>(refundTo)
|
|
303
|
+
);
|
|
255
304
|
}
|
|
256
305
|
|
|
257
306
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0-
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-rc.2 (token/NativeShieldedTokenCore.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -44,6 +44,18 @@ pragma language_version >= 0.23.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
|
|
@@ -212,21 +224,26 @@ module NativeShieldedTokenCore {
|
|
|
212
224
|
*
|
|
213
225
|
* @dev The caller is fully responsible for nonce uniqueness. Reusing a
|
|
214
226
|
* nonce for the same (domain, value, recipient) produces a duplicate
|
|
215
|
-
* commitment, which the protocol rejects.
|
|
227
|
+
* commitment, which the protocol rejects. A `right(kernel.self())` recipient
|
|
228
|
+
* is claimed via `receiveShielded` in this same call, so the consumer SHOULD
|
|
229
|
+
* persist the returned coin info: it is the contract's holding and is not
|
|
230
|
+
* otherwise recoverable.
|
|
216
231
|
*
|
|
217
232
|
* @notice The returned coin info is the only copy available to the
|
|
218
233
|
* recipient; callers SHOULD deliver it out of band. Wallets cannot detect
|
|
219
234
|
* contract-minted coins by scanning the chain.
|
|
220
235
|
*
|
|
221
|
-
* @circuitInfo k=
|
|
236
|
+
* @circuitInfo k=15, rows=17017
|
|
222
237
|
*
|
|
223
238
|
* Requirements:
|
|
224
239
|
*
|
|
225
240
|
* - Contract is initialized.
|
|
226
241
|
* - `recipient` is not zero.
|
|
242
|
+
* - `recipient`, if a contract address, is this contract's own address.
|
|
227
243
|
*
|
|
228
244
|
* @param {Bytes<32>} domain - 32-byte token discriminator.
|
|
229
|
-
* @param {Either<ZswapCoinPublicKey, ContractAddress>} recipient - The coin
|
|
245
|
+
* @param {Either<ZswapCoinPublicKey, ContractAddress>} recipient - The coin
|
|
246
|
+
* recipient: any coin public key, or this contract's own address.
|
|
230
247
|
* @param {Uint<64>} amount - Quantity to mint. Capped at `Uint<64>` by the protocol.
|
|
231
248
|
* @param {Bytes<32>} nonce - Caller-supplied nonce. Must be unique per (domain, contract).
|
|
232
249
|
* @return {ShieldedCoinInfo} - The newly created coin's info (nonce, color, value).
|
|
@@ -238,9 +255,16 @@ module NativeShieldedTokenCore {
|
|
|
238
255
|
nonce: Bytes<32>
|
|
239
256
|
): ShieldedCoinInfo {
|
|
240
257
|
assertInitialized();
|
|
258
|
+
const self = kernel.self();
|
|
241
259
|
assert(!Utils_isKeyOrAddressZero(recipient), "NativeShieldedToken: invalid recipient");
|
|
260
|
+
assert(recipient.is_left || recipient.right == self, "NativeShieldedToken: recipient contract must be self");
|
|
242
261
|
|
|
243
|
-
|
|
262
|
+
const coin = mintShieldedToken(disclose(domain), disclose(amount), disclose(nonce), disclose(recipient));
|
|
263
|
+
if (disclose(!recipient.is_left)) {
|
|
264
|
+
receiveShielded(coin);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return coin;
|
|
244
268
|
}
|
|
245
269
|
|
|
246
270
|
/**
|
|
@@ -255,13 +279,14 @@ module NativeShieldedTokenCore {
|
|
|
255
279
|
* @dev The coin is received by the contract and spent in the same
|
|
256
280
|
* transaction, so the spend goes through `sendImmediateShielded` (the
|
|
257
281
|
* transient path). For coins the contract already holds, use
|
|
258
|
-
* `_burnFromSelf` instead.
|
|
282
|
+
* `_burnFromSelf` instead. A `right(kernel.self())` refund is claimed via
|
|
283
|
+
* `receiveShielded` in this same call.
|
|
259
284
|
*
|
|
260
285
|
* @notice The returned refund coin info is the only copy available to
|
|
261
286
|
* `refundTo`; callers SHOULD deliver it out of band. Wallets cannot detect
|
|
262
287
|
* contract-sent coins by scanning the chain.
|
|
263
288
|
*
|
|
264
|
-
* @circuitInfo k=16, rows=
|
|
289
|
+
* @circuitInfo k=16, rows=53832
|
|
265
290
|
*
|
|
266
291
|
* Requirements:
|
|
267
292
|
*
|
|
@@ -270,12 +295,14 @@ module NativeShieldedTokenCore {
|
|
|
270
295
|
* - `amount` is less than or equal to `coin.value`.
|
|
271
296
|
* - `refundTo` is not zero (the zero key is the burn address; a zero
|
|
272
297
|
* `refundTo` would silently burn the change as well).
|
|
298
|
+
* - `refundTo`, if a contract address, is this contract's own address.
|
|
273
299
|
*
|
|
274
300
|
* @param {Bytes<32>} domain - 32-byte token discriminator.
|
|
275
301
|
* @param {ShieldedCoinInfo} coin - The coin to burn from.
|
|
276
302
|
* @param {Uint<128>} amount - Value to destroy. Must be <= `coin.value`.
|
|
277
303
|
* @param {Either<ZswapCoinPublicKey, ContractAddress>} refundTo - Where to
|
|
278
|
-
* route the unspent portion (`coin.value - amount`)
|
|
304
|
+
* route the unspent portion (`coin.value - amount`): any coin public key, or
|
|
305
|
+
* this contract's own address.
|
|
279
306
|
* @return {Maybe<ShieldedCoinInfo>} - The refund coin created for `refundTo`,
|
|
280
307
|
* or `none` if the coin was burned in full.
|
|
281
308
|
*/
|
|
@@ -286,9 +313,11 @@ module NativeShieldedTokenCore {
|
|
|
286
313
|
refundTo: Either<ZswapCoinPublicKey, ContractAddress>
|
|
287
314
|
): Maybe<ShieldedCoinInfo> {
|
|
288
315
|
assertInitialized();
|
|
289
|
-
|
|
316
|
+
const self = kernel.self();
|
|
317
|
+
assert(coin.color == tokenType(disclose(domain), self), "NativeShieldedToken: wrong token");
|
|
290
318
|
assert(coin.value >= amount, "NativeShieldedToken: insufficient coin value");
|
|
291
319
|
assert(!Utils_isKeyOrAddressZero(refundTo), "NativeShieldedToken: invalid refund target");
|
|
320
|
+
assert(refundTo.is_left || refundTo.right == self, "NativeShieldedToken: refund contract must be self");
|
|
292
321
|
|
|
293
322
|
receiveShielded(disclose(coin));
|
|
294
323
|
const sendRes = sendImmediateShielded(disclose(coin), shieldedBurnAddress(), disclose(amount));
|
|
@@ -299,6 +328,9 @@ module NativeShieldedTokenCore {
|
|
|
299
328
|
disclose(refundTo),
|
|
300
329
|
disclose(sendRes.change.value.value)
|
|
301
330
|
);
|
|
331
|
+
if (disclose(!refundTo.is_left)) {
|
|
332
|
+
receiveShielded(refundRes.sent);
|
|
333
|
+
}
|
|
302
334
|
return some<ShieldedCoinInfo>(refundRes.sent);
|
|
303
335
|
}
|
|
304
336
|
return none<ShieldedCoinInfo>();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0-
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-rc.2 (token/NativeShieldedTokenFamily.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -26,6 +26,10 @@ pragma language_version >= 0.23.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,
|
|
@@ -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=
|
|
193
|
+
* @circuitInfo k=14, rows=10750
|
|
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 {
|
|
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:
|
|
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
|
+
* @circuitInfo k=14, rows=16346
|
|
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(
|
|
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=
|
|
275
|
+
* @circuitInfo k=16, rows=41768
|
|
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 {
|
|
244
|
-
*
|
|
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:
|
|
297
|
+
refundTo: ZswapCoinPublicKey
|
|
253
298
|
): Maybe<ShieldedCoinInfo> {
|
|
254
|
-
return Core__burn(
|
|
299
|
+
return Core__burn(
|
|
300
|
+
domain,
|
|
301
|
+
coin,
|
|
302
|
+
amount,
|
|
303
|
+
left<ZswapCoinPublicKey, ContractAddress>(refundTo)
|
|
304
|
+
);
|
|
255
305
|
}
|
|
256
306
|
|
|
257
307
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0-
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-rc.2 (token/NonFungibleToken.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -58,7 +58,7 @@ pragma language_version >= 0.23.0;
|
|
|
58
58
|
* or in ledger writes. Canonicalization zeroes out the inactive branch of the Either,
|
|
59
59
|
* ensuring that two values with the same active branch always resolve to the same map key
|
|
60
60
|
* regardless of what data the inactive branch carries. Write paths are canonicalized in
|
|
61
|
-
* `_update` (for `_owners` and `_balances`), `
|
|
61
|
+
* `_update` (for `_owners` and `_balances`), `_unsafeApprove` (for `_tokenApprovals`), and
|
|
62
62
|
* `_setApprovalForAll` (for `_operatorApprovals`). Read paths are canonicalized in
|
|
63
63
|
* `balanceOf`, `isApprovedForAll`, and `_isAuthorized`.
|
|
64
64
|
*
|
|
@@ -338,7 +338,7 @@ module NonFungibleToken {
|
|
|
338
338
|
* In the case of an external (non-contract) caller, the caller's identity is derived from the `wit_NonFungibleTokenSK`
|
|
339
339
|
* witness as `persistentHash(secretKey)`.
|
|
340
340
|
*
|
|
341
|
-
* @circuitInfo k=13, rows=
|
|
341
|
+
* @circuitInfo k=13, rows=3415
|
|
342
342
|
*
|
|
343
343
|
* Requirements:
|
|
344
344
|
*
|
|
@@ -383,7 +383,7 @@ module NonFungibleToken {
|
|
|
383
383
|
* In the case of an external (non-contract) caller, the caller's identity is derived from the `wit_NonFungibleTokenSK`
|
|
384
384
|
* witness as `persistentHash(secretKey)`.
|
|
385
385
|
*
|
|
386
|
-
* @circuitInfo k=13, rows=
|
|
386
|
+
* @circuitInfo k=13, rows=2947
|
|
387
387
|
*
|
|
388
388
|
* Requirements:
|
|
389
389
|
*
|
|
@@ -439,7 +439,7 @@ module NonFungibleToken {
|
|
|
439
439
|
* In the case of an external (non-contract) caller, the caller's identity is derived from the `wit_NonFungibleTokenSK`
|
|
440
440
|
* witness as `persistentHash(secretKey)`.
|
|
441
441
|
*
|
|
442
|
-
* @circuitInfo k=13, rows=
|
|
442
|
+
* @circuitInfo k=13, rows=4739
|
|
443
443
|
*
|
|
444
444
|
* Requirements:
|
|
445
445
|
*
|
|
@@ -477,7 +477,7 @@ module NonFungibleToken {
|
|
|
477
477
|
* are not currently supported. Tokens sent to a contract address may become irretrievable.
|
|
478
478
|
* Once contract-to-contract calls are supported, this circuit may be deprecated.
|
|
479
479
|
*
|
|
480
|
-
* @circuitInfo k=13, rows=
|
|
480
|
+
* @circuitInfo k=13, rows=4736
|
|
481
481
|
*
|
|
482
482
|
* Requirements:
|
|
483
483
|
*
|
|
@@ -499,11 +499,14 @@ module NonFungibleToken {
|
|
|
499
499
|
): [] {
|
|
500
500
|
assertInitialized();
|
|
501
501
|
assert(!Utils_isTargetZero(to), "NonFungibleToken: invalid receiver");
|
|
502
|
-
// Setting an "auth" argument enables the `_isAuthorized` check which verifies that the token exists
|
|
503
|
-
// (fromAddress != 0). Therefore, it is not needed to verify that the return value is not 0 here.
|
|
504
502
|
const auth = left<Bytes<32>, ContractAddress>(_computeAccountId());
|
|
505
503
|
const previousOwner = _update(to, tokenId, auth);
|
|
506
504
|
|
|
505
|
+
// The `_isAuthorized` check inside `_update` already implies the token exists, but that
|
|
506
|
+
// holds only while approvals are never recorded for unminted tokens. Assert it directly
|
|
507
|
+
// so a misused `_unsafeApprove` cannot turn this circuit into an unauthorized mint.
|
|
508
|
+
assert(!Utils_isTargetZero(previousOwner), "NonFungibleToken: nonexistent token");
|
|
509
|
+
|
|
507
510
|
const canonFrom = Utils_canonicalize<Bytes<32>, ContractAddress>(fromAddress);
|
|
508
511
|
assert(previousOwner == canonFrom, "NonFungibleToken: incorrect owner");
|
|
509
512
|
}
|
|
@@ -643,8 +646,8 @@ module NonFungibleToken {
|
|
|
643
646
|
|
|
644
647
|
// Execute the update
|
|
645
648
|
if (!Utils_isTargetZero(disclose(fromAddress))) {
|
|
646
|
-
// Clear approval. No need to re-authorize
|
|
647
|
-
|
|
649
|
+
// Clear approval. No need to re-authorize or re-read the owner
|
|
650
|
+
_unsafeApprove(Utils_zeroAccount(), tokenId, Utils_zeroAccount(), false);
|
|
648
651
|
const canonFrom = Utils_canonicalize<Bytes<32>, ContractAddress>(fromAddress);
|
|
649
652
|
const newBalance = _balances.lookup(disclose(canonFrom)) - 1 as Uint<128>;
|
|
650
653
|
_balances.insert(disclose(canonFrom), disclose(newBalance));
|
|
@@ -666,7 +669,7 @@ module NonFungibleToken {
|
|
|
666
669
|
/**
|
|
667
670
|
* @description Mints `tokenId` and transfers it to `to`.
|
|
668
671
|
*
|
|
669
|
-
* @circuitInfo k=11, rows=
|
|
672
|
+
* @circuitInfo k=11, rows=1411
|
|
670
673
|
*
|
|
671
674
|
* Requirements:
|
|
672
675
|
*
|
|
@@ -690,7 +693,7 @@ module NonFungibleToken {
|
|
|
690
693
|
/**
|
|
691
694
|
* @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress.
|
|
692
695
|
*
|
|
693
|
-
* @circuitInfo k=11, rows=
|
|
696
|
+
* @circuitInfo k=11, rows=1408
|
|
694
697
|
*
|
|
695
698
|
* Requirements:
|
|
696
699
|
*
|
|
@@ -723,7 +726,7 @@ module NonFungibleToken {
|
|
|
723
726
|
* The approval is cleared when the token is burned.
|
|
724
727
|
* This circuit does not check if the sender is authorized to operate on the token.
|
|
725
728
|
*
|
|
726
|
-
* @circuitInfo k=10, rows=
|
|
729
|
+
* @circuitInfo k=10, rows=512
|
|
727
730
|
*
|
|
728
731
|
* Requirements:
|
|
729
732
|
*
|
|
@@ -748,7 +751,7 @@ module NonFungibleToken {
|
|
|
748
751
|
* interactions are supported in Compact. This restriction prevents assets from being inadvertently
|
|
749
752
|
* locked in contracts that cannot currently handle token receipt.
|
|
750
753
|
*
|
|
751
|
-
* @circuitInfo k=
|
|
754
|
+
* @circuitInfo k=11, rows=2005
|
|
752
755
|
*
|
|
753
756
|
* Requirements:
|
|
754
757
|
*
|
|
@@ -779,7 +782,7 @@ module NonFungibleToken {
|
|
|
779
782
|
* As opposed to {_unsafeTransferFrom}, this imposes no restrictions on the caller's identity.
|
|
780
783
|
* It does NOT check if the recipient is a ContractAddress.
|
|
781
784
|
*
|
|
782
|
-
* @circuitInfo k=
|
|
785
|
+
* @circuitInfo k=11, rows=2002
|
|
783
786
|
*
|
|
784
787
|
* Requirements:
|
|
785
788
|
*
|
|
@@ -815,11 +818,12 @@ module NonFungibleToken {
|
|
|
815
818
|
/**
|
|
816
819
|
* @description Approve `to` to operate on `tokenId`.
|
|
817
820
|
*
|
|
818
|
-
* @circuitInfo k=11, rows=
|
|
821
|
+
* @circuitInfo k=11, rows=1757
|
|
819
822
|
*
|
|
820
823
|
* Requirements:
|
|
821
824
|
*
|
|
822
825
|
* - The contract is initialized.
|
|
826
|
+
* - `tokenId` must exist.
|
|
823
827
|
* - If `auth` is non 0, then this function will check that `auth` is either the owner of the token,
|
|
824
828
|
* or approved to operate on the token (by the owner).
|
|
825
829
|
*
|
|
@@ -833,6 +837,43 @@ module NonFungibleToken {
|
|
|
833
837
|
tokenId: Uint<128>,
|
|
834
838
|
auth: Either<Bytes<32>, ContractAddress>
|
|
835
839
|
): [] {
|
|
840
|
+
_unsafeApprove(to, tokenId, auth, true);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* @description Approve `to` to operate on `tokenId`, requiring the token to exist
|
|
845
|
+
* only when `isExistenceRequired` is true.
|
|
846
|
+
*
|
|
847
|
+
* @circuitInfo k=11, rows=1870
|
|
848
|
+
*
|
|
849
|
+
* @warning Passing false skips the check that `tokenId` was minted. Both
|
|
850
|
+
* `_unsafeTransferFrom` and `_update` read that invariant back, so a planted approval
|
|
851
|
+
* can mint a token nobody authorized or outlive a later mint. Pass false only where
|
|
852
|
+
* the owner has already been read, as `_update` does.
|
|
853
|
+
*
|
|
854
|
+
* @dev Counterpart to Solidity's `_approve(to, tokenId, auth, bool emitEvent)`, where
|
|
855
|
+
* the flag also suppresses the `Approval` event. Compact has no events, so it carries
|
|
856
|
+
* the existence check alone.
|
|
857
|
+
*
|
|
858
|
+
* Requirements:
|
|
859
|
+
*
|
|
860
|
+
* - The contract is initialized.
|
|
861
|
+
* - `tokenId` must exist, unless `isExistenceRequired` is false and `auth` is zero.
|
|
862
|
+
* - If `auth` is non 0, then this function will check that `auth` is either the owner of the token,
|
|
863
|
+
* or approved to operate on the token (by the owner).
|
|
864
|
+
*
|
|
865
|
+
* @param {Either<Bytes<32>, ContractAddress>} to - The target account to approve
|
|
866
|
+
* @param {Uint<128>} tokenId - The token to approve
|
|
867
|
+
* @param {Either<Bytes<32>, ContractAddress>} auth - An account authorized to operate on all tokens held by the owner of the token
|
|
868
|
+
* @param {Boolean} isExistenceRequired - Whether `tokenId` must exist
|
|
869
|
+
* @return {[]} - Empty tuple.
|
|
870
|
+
*/
|
|
871
|
+
export circuit _unsafeApprove(
|
|
872
|
+
to: Either<Bytes<32>, ContractAddress>,
|
|
873
|
+
tokenId: Uint<128>,
|
|
874
|
+
auth: Either<Bytes<32>, ContractAddress>,
|
|
875
|
+
isExistenceRequired: Boolean
|
|
876
|
+
): [] {
|
|
836
877
|
assertInitialized();
|
|
837
878
|
// Canonicalize + normalize `to`
|
|
838
879
|
const canonTo = Utils_canonicalize<Bytes<32>, ContractAddress>(to);
|
|
@@ -841,11 +882,14 @@ module NonFungibleToken {
|
|
|
841
882
|
// Canonicalize auth
|
|
842
883
|
const canonAuth = Utils_canonicalize<Bytes<32>, ContractAddress>(auth);
|
|
843
884
|
|
|
844
|
-
|
|
885
|
+
// Avoid reading the owner unless necessary
|
|
886
|
+
if (disclose(isExistenceRequired) || !Utils_isTargetZero(disclose(canonAuth))) {
|
|
845
887
|
const owner = _requireOwned(tokenId);
|
|
846
888
|
|
|
847
889
|
// We do not use _isAuthorized because single-token approvals should not be able to call approve
|
|
848
|
-
assert((
|
|
890
|
+
assert((Utils_isTargetZero(disclose(canonAuth)) ||
|
|
891
|
+
owner == disclose(canonAuth) ||
|
|
892
|
+
isApprovedForAll(owner, canonAuth)),
|
|
849
893
|
"NonFungibleToken: invalid approver"
|
|
850
894
|
);
|
|
851
895
|
}
|
|
@@ -856,7 +900,7 @@ module NonFungibleToken {
|
|
|
856
900
|
/**
|
|
857
901
|
* @description Approve `operator` to operate on all of `owner` tokens.
|
|
858
902
|
*
|
|
859
|
-
* @circuitInfo k=11, rows=
|
|
903
|
+
* @circuitInfo k=11, rows=1282
|
|
860
904
|
*
|
|
861
905
|
* Requirements:
|
|
862
906
|
*
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0-rc.2 (token/examples/ZOwnableNativeShieldedTokenExample.compact)
|
|
3
|
+
|
|
4
|
+
pragma language_version >= 0.23.0;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title ZOwnableNativeShieldedTokenExample
|
|
8
|
+
* @description Deployable reference contract for the
|
|
9
|
+
* `ZOwnableNativeShieldedToken` preset: a native shielded token that only a
|
|
10
|
+
* single shielded owner mints and burns. Holders transfer coins through
|
|
11
|
+
* Zswap directly.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import CompactStandardLibrary;
|
|
15
|
+
|
|
16
|
+
import "../presets/ZOwnableNativeShieldedToken" prefix ZOwnableNativeShieldedToken_;
|
|
17
|
+
|
|
18
|
+
export { ZswapCoinPublicKey, ContractAddress, Either, Maybe, ShieldedCoinInfo };
|
|
19
|
+
|
|
20
|
+
// Surface the preset's state unprefixed so `ledger()` readers use the keys the
|
|
21
|
+
// modules declare.
|
|
22
|
+
import {
|
|
23
|
+
_ownerCommitment,
|
|
24
|
+
_counter,
|
|
25
|
+
_instanceSalt,
|
|
26
|
+
_ownableIsInitialized,
|
|
27
|
+
_domain,
|
|
28
|
+
_name,
|
|
29
|
+
_symbol,
|
|
30
|
+
_decimals,
|
|
31
|
+
_isInitialized,
|
|
32
|
+
_totalMinted,
|
|
33
|
+
_totalBurned,
|
|
34
|
+
} from "../presets/ZOwnableNativeShieldedToken";
|
|
35
|
+
export {
|
|
36
|
+
_ownerCommitment,
|
|
37
|
+
_counter,
|
|
38
|
+
_instanceSalt,
|
|
39
|
+
_ownableIsInitialized,
|
|
40
|
+
_domain,
|
|
41
|
+
_name,
|
|
42
|
+
_symbol,
|
|
43
|
+
_decimals,
|
|
44
|
+
_isInitialized,
|
|
45
|
+
_totalMinted,
|
|
46
|
+
_totalBurned,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @description Deploys the token with its owner, domain and metadata.
|
|
51
|
+
*
|
|
52
|
+
* @warning `ownerId` must be `_computeOwnerId(pk, secretNonce)` for the coin
|
|
53
|
+
* public key the owner's wallet will supply as `ownPublicKey()`. The circuit
|
|
54
|
+
* cannot check this at deploy; any other key leaves the contract with no
|
|
55
|
+
* usable owner and no recovery.
|
|
56
|
+
*
|
|
57
|
+
* @param {Bytes<32>} ownerId - `_computeOwnerId(pk, secretNonce)` of the owner.
|
|
58
|
+
* @param {Bytes<32>} instanceSalt - Random per-deployment salt for the owner commitment.
|
|
59
|
+
* @param {Bytes<32>} tokenDomain - Domain of this contract's token color.
|
|
60
|
+
*/
|
|
61
|
+
constructor(
|
|
62
|
+
ownerId: Bytes<32>,
|
|
63
|
+
instanceSalt: Bytes<32>,
|
|
64
|
+
tokenDomain: Bytes<32>,
|
|
65
|
+
name_: Opaque<"string">,
|
|
66
|
+
symbol_: Opaque<"string">,
|
|
67
|
+
decimals_: Uint<8>,
|
|
68
|
+
) {
|
|
69
|
+
ZOwnableNativeShieldedToken_initialize(
|
|
70
|
+
ownerId,
|
|
71
|
+
instanceSalt,
|
|
72
|
+
tokenDomain,
|
|
73
|
+
name_,
|
|
74
|
+
symbol_,
|
|
75
|
+
decimals_,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export circuit mint(recipient: ZswapCoinPublicKey, amount: Uint<64>, nonce: Bytes<32>): ShieldedCoinInfo {
|
|
80
|
+
return ZOwnableNativeShieldedToken_mint(recipient, amount, nonce);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export circuit burn(coin: ShieldedCoinInfo, amount: Uint<64>, refundTo: ZswapCoinPublicKey): Maybe<ShieldedCoinInfo> {
|
|
84
|
+
return ZOwnableNativeShieldedToken_burn(coin, amount, refundTo);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export circuit transferOwnership(newOwnerId: Bytes<32>): [] {
|
|
88
|
+
ZOwnableNativeShieldedToken_transferOwnership(newOwnerId);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export circuit renounceOwnership(): [] {
|
|
92
|
+
ZOwnableNativeShieldedToken_renounceOwnership();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export circuit owner(): Bytes<32> {
|
|
96
|
+
return ZOwnableNativeShieldedToken_owner();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export pure circuit _computeOwnerId(pk: Either<ZswapCoinPublicKey, ContractAddress>, nonce: Bytes<32>): Bytes<32> {
|
|
100
|
+
return ZOwnableNativeShieldedToken__computeOwnerId(pk, nonce);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export circuit totalMinted(): Uint<128> {
|
|
104
|
+
return ZOwnableNativeShieldedToken_totalMinted();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export circuit tokenColor(): Bytes<32> {
|
|
108
|
+
return ZOwnableNativeShieldedToken_tokenColor();
|
|
109
|
+
}
|