@lfdecentralizedtrust/zeto-contracts 0.2.2 → 0.5.0

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 (152) hide show
  1. package/README.md +70 -162
  2. package/contracts/factory.sol +30 -34
  3. package/contracts/factory_upgradeable.sol +11 -7
  4. package/contracts/lib/common/util.sol +40 -0
  5. package/contracts/lib/interfaces/ILockableCapability.sol +318 -0
  6. package/contracts/lib/interfaces/{izeto.sol → IZeto.sol} +13 -1
  7. package/contracts/lib/interfaces/{izeto_initializable.sol → IZetoInitializable.sol} +14 -12
  8. package/contracts/lib/interfaces/{izeto_kyc.sol → IZetoKyc.sol} +3 -3
  9. package/contracts/lib/interfaces/IZetoLockableCapability.sol +237 -0
  10. package/contracts/lib/interfaces/IZetoStorage.sol +106 -0
  11. package/contracts/lib/interfaces/{izeto_lockable.sol → IZetoVerifier.sol} +8 -21
  12. package/contracts/lib/registry.sol +74 -26
  13. package/contracts/lib/storage/base.sol +210 -0
  14. package/contracts/lib/storage/nullifier.sol +166 -0
  15. package/contracts/lib/zeto_common.sol +277 -28
  16. package/contracts/lib/zeto_fungible.sol +451 -33
  17. package/contracts/lib/zeto_fungible_base.sol +69 -0
  18. package/contracts/lib/zeto_fungible_burn.sol +83 -53
  19. package/contracts/lib/zeto_fungible_burn_nullifier.sol +115 -72
  20. package/contracts/lib/zeto_fungible_nullifier.sol +167 -0
  21. package/contracts/lib/zeto_lockable.sol +613 -0
  22. package/contracts/lib/zeto_non_fungible.sol +236 -0
  23. package/contracts/lib/zeto_non_fungible_base.sol +61 -0
  24. package/contracts/lib/zeto_non_fungible_nullifier.sol +61 -0
  25. package/contracts/test/escrow1.sol +90 -34
  26. package/contracts/test/escrow2.sol +64 -29
  27. package/contracts/test/qurrency.sol +10 -2
  28. package/contracts/test/smt.sol +6 -1
  29. package/contracts/test/tendecimals.sol +14 -12
  30. package/contracts/verifiers/impl/anon.sol +189 -0
  31. package/contracts/verifiers/impl/anon_batch.sol +301 -0
  32. package/contracts/verifiers/impl/anon_enc.sol +266 -0
  33. package/contracts/verifiers/impl/anon_enc_batch.sol +602 -0
  34. package/contracts/verifiers/impl/anon_enc_nullifier.sol +287 -0
  35. package/contracts/verifiers/impl/anon_enc_nullifier_batch.sol +679 -0
  36. package/contracts/verifiers/impl/anon_enc_nullifier_kyc.sol +294 -0
  37. package/contracts/verifiers/impl/anon_enc_nullifier_kyc_batch.sol +686 -0
  38. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation.sol +413 -0
  39. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation_batch.sol +1141 -0
  40. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer.sol +217 -0
  41. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked.sol +196 -0
  42. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked_batch.sol +308 -0
  43. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer_batch.sol +385 -0
  44. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer.sol +497 -0
  45. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer_batch.sol +1001 -0
  46. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked.sol → impl/anon_nullifier_transfer.sol} +12 -19
  47. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked_batch.sol → impl/anon_nullifier_transfer_batch.sol} +44 -51
  48. package/contracts/verifiers/impl/burn.sol +182 -0
  49. package/contracts/verifiers/impl/burn_batch.sol +238 -0
  50. package/contracts/verifiers/impl/burn_nullifier.sol +203 -0
  51. package/contracts/verifiers/impl/burn_nullifier_batch.sol +315 -0
  52. package/contracts/verifiers/impl/deposit.sol +182 -0
  53. package/contracts/verifiers/impl/deposit_kyc.sol +189 -0
  54. package/contracts/verifiers/impl/nf_anon.sol +175 -0
  55. package/contracts/verifiers/{verifier_nf_anon_nullifier_transferLocked.sol → impl/nf_anon_nullifier_transfer.sol} +6 -13
  56. package/contracts/verifiers/impl/withdraw.sol +189 -0
  57. package/contracts/verifiers/impl/withdraw_batch.sol +245 -0
  58. package/contracts/verifiers/impl/withdraw_nullifier.sol +210 -0
  59. package/contracts/verifiers/impl/withdraw_nullifier_batch.sol +322 -0
  60. package/contracts/verifiers/verifier_anon.sol +31 -186
  61. package/contracts/verifiers/verifier_anon_batch.sol +31 -298
  62. package/contracts/verifiers/verifier_anon_enc.sol +31 -263
  63. package/contracts/verifiers/verifier_anon_enc_batch.sol +31 -599
  64. package/contracts/verifiers/verifier_anon_enc_nullifier.sol +31 -284
  65. package/contracts/verifiers/verifier_anon_enc_nullifier_batch.sol +33 -676
  66. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc.sol +31 -291
  67. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc_batch.sol +33 -683
  68. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation.sol +33 -410
  69. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation_batch.sol +33 -1138
  70. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer.sol +33 -214
  71. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked.sol +33 -221
  72. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked_batch.sol +33 -389
  73. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer_batch.sol +33 -382
  74. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer.sol +33 -221
  75. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer_batch.sol +33 -389
  76. package/contracts/verifiers/verifier_anon_nullifier_transfer.sol +33 -207
  77. package/contracts/verifiers/verifier_anon_nullifier_transfer_batch.sol +33 -375
  78. package/contracts/verifiers/verifier_burn.sol +31 -179
  79. package/contracts/verifiers/verifier_burn_batch.sol +31 -235
  80. package/contracts/verifiers/verifier_burn_nullifier.sol +31 -200
  81. package/contracts/verifiers/verifier_burn_nullifier_batch.sol +31 -312
  82. package/contracts/verifiers/verifier_deposit.sol +31 -179
  83. package/contracts/verifiers/verifier_deposit_kyc.sol +34 -0
  84. package/contracts/verifiers/verifier_nf_anon.sol +31 -172
  85. package/contracts/verifiers/verifier_nf_anon_nullifier_transfer.sol +33 -179
  86. package/contracts/verifiers/verifier_withdraw.sol +31 -186
  87. package/contracts/verifiers/verifier_withdraw_batch.sol +31 -242
  88. package/contracts/verifiers/verifier_withdraw_nullifier.sol +31 -207
  89. package/contracts/verifiers/verifier_withdraw_nullifier_batch.sol +33 -319
  90. package/contracts/zeto_anon.sol +77 -231
  91. package/contracts/zeto_anon_burnable.sol +56 -12
  92. package/contracts/zeto_anon_enc.sol +93 -190
  93. package/contracts/zeto_anon_enc_nullifier.sol +249 -195
  94. package/contracts/zeto_anon_enc_nullifier_kyc.sol +51 -232
  95. package/contracts/zeto_anon_enc_nullifier_non_repudiation.sol +231 -238
  96. package/contracts/zeto_anon_nullifier.sol +164 -298
  97. package/contracts/zeto_anon_nullifier_burnable.sol +68 -18
  98. package/contracts/zeto_anon_nullifier_kyc.sol +40 -345
  99. package/contracts/zeto_anon_nullifier_qurrency.sol +217 -361
  100. package/contracts/zeto_nf_anon.sol +55 -130
  101. package/contracts/zeto_nf_anon_nullifier.sol +90 -152
  102. package/hardhat.config.ts +9 -3
  103. package/ignition/modules/lib/deps.ts +8 -0
  104. package/ignition/modules/zeto_anon_burnable.ts +8 -7
  105. package/ignition/modules/zeto_anon_enc_nullifier.ts +31 -0
  106. package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +2 -2
  107. package/ignition/modules/zeto_anon_nullifier.ts +28 -4
  108. package/ignition/modules/zeto_anon_nullifier_burnable.ts +50 -16
  109. package/ignition/modules/zeto_anon_nullifier_kyc.ts +27 -12
  110. package/ignition/modules/zeto_nf_anon_nullifier.ts +14 -10
  111. package/package.json +4 -2
  112. package/scripts/deploy_cloneable.ts +19 -10
  113. package/scripts/deploy_upgradeable.ts +9 -5
  114. package/scripts/tokens/Zeto_Anon.ts +3 -3
  115. package/scripts/tokens/Zeto_AnonBurnable.ts +1 -1
  116. package/scripts/tokens/Zeto_AnonEnc.ts +12 -3
  117. package/scripts/tokens/Zeto_AnonEncNullifier.ts +5 -3
  118. package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +1 -1
  119. package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +1 -1
  120. package/scripts/tokens/Zeto_AnonNullifier.ts +1 -1
  121. package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +1 -1
  122. package/scripts/tokens/Zeto_AnonNullifierKyc.ts +1 -1
  123. package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +1 -1
  124. package/scripts/tokens/Zeto_NfAnon.ts +2 -2
  125. package/scripts/tokens/Zeto_NfAnonNullifier.ts +1 -1
  126. package/test/factory.ts +46 -73
  127. package/test/lib/anon_nullifier_helpers.ts +89 -0
  128. package/test/lib/anon_zeto_helpers.ts +76 -0
  129. package/test/lib/deploy.ts +3 -2
  130. package/test/lib/utils.ts +74 -35
  131. package/test/test/escrow1.ts +185 -58
  132. package/test/test/escrow2.ts +200 -107
  133. package/test/test/qurrency.ts +13 -33
  134. package/test/usdc-shielding.ts +39 -26
  135. package/test/utils.ts +144 -21
  136. package/test/zeto_anon.ts +956 -465
  137. package/test/zeto_anon_enc.ts +881 -142
  138. package/test/zeto_anon_enc_nullifier.ts +847 -38
  139. package/test/zeto_anon_enc_nullifier_kyc.ts +120 -181
  140. package/test/zeto_anon_enc_nullifier_non_repudiation.ts +77 -46
  141. package/test/zeto_anon_nullifier.ts +1212 -953
  142. package/test/zeto_anon_nullifier_kyc.ts +674 -655
  143. package/test/zeto_anon_nullifier_qurrency.ts +452 -306
  144. package/test/zeto_nf_anon.ts +737 -137
  145. package/test/zeto_nf_anon_nullifier.ts +876 -246
  146. package/contracts/lib/zeto_base.sol +0 -293
  147. package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
  148. package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
  149. package/contracts/lib/zeto_nullifier.sol +0 -340
  150. package/contracts/zkDvP.sol_ +0 -273
  151. package/test/zkDvP.ts_ +0 -455
  152. /package/contracts/lib/{common.sol → common/common.sol} +0 -0
package/test/factory.ts CHANGED
@@ -47,7 +47,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
47
47
  batchLockVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
48
48
  burnVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
49
49
  batchBurnVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
50
- }
50
+ },
51
51
  };
52
52
  await expect(
53
53
  factory.connect(nonOwner).registerImplementation("test", implInfo as any),
@@ -73,7 +73,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
73
73
  batchLockVerifier: "0x0000000000000000000000000000000000000000",
74
74
  burnVerifier: "0x0000000000000000000000000000000000000000",
75
75
  batchBurnVerifier: "0x0000000000000000000000000000000000000000",
76
- }
76
+ },
77
77
  };
78
78
  await expect(
79
79
  factory.connect(deployer).registerImplementation("test", implInfo as any),
@@ -99,7 +99,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
99
99
  batchLockVerifier: "0x0000000000000000000000000000000000000000",
100
100
  burnVerifier: "0x0000000000000000000000000000000000000000",
101
101
  batchBurnVerifier: "0x0000000000000000000000000000000000000000",
102
- }
102
+ },
103
103
  };
104
104
  await expect(
105
105
  factory.connect(deployer).registerImplementation("test", implInfo as any),
@@ -125,7 +125,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
125
125
  batchLockVerifier: "0x0000000000000000000000000000000000000000",
126
126
  burnVerifier: "0x0000000000000000000000000000000000000000",
127
127
  batchBurnVerifier: "0x0000000000000000000000000000000000000000",
128
- }
128
+ },
129
129
  };
130
130
  await expect(
131
131
  factory.connect(deployer).registerImplementation("test", implInfo as any),
@@ -151,7 +151,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
151
151
  batchLockVerifier: "0x0000000000000000000000000000000000000000",
152
152
  burnVerifier: "0x0000000000000000000000000000000000000000",
153
153
  batchBurnVerifier: "0x0000000000000000000000000000000000000000",
154
- }
154
+ },
155
155
  };
156
156
  const tx1 = await factory
157
157
  .connect(deployer)
@@ -161,7 +161,12 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
161
161
  await expect(
162
162
  factory
163
163
  .connect(deployer)
164
- .deployZetoFungibleToken("name", "symbol", "test", await deployer.getAddress()),
164
+ .deployZetoFungibleToken(
165
+ "name",
166
+ "symbol",
167
+ "test",
168
+ await deployer.getAddress(),
169
+ ),
165
170
  ).rejectedWith("Factory: depositVerifier address is required");
166
171
  });
167
172
  it("attempting to deploy a fungible token but with a registered implementation that misses required depositVerifier should fail", async function () {
@@ -183,7 +188,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
183
188
  batchLockVerifier: "0x0000000000000000000000000000000000000000",
184
189
  burnVerifier: "0x0000000000000000000000000000000000000000",
185
190
  batchBurnVerifier: "0x0000000000000000000000000000000000000000",
186
- }
191
+ },
187
192
  };
188
193
  const tx1 = await factory
189
194
  .connect(deployer)
@@ -193,7 +198,12 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
193
198
  await expect(
194
199
  factory
195
200
  .connect(deployer)
196
- .deployZetoFungibleToken("name", "symbol", "test", await deployer.getAddress()),
201
+ .deployZetoFungibleToken(
202
+ "name",
203
+ "symbol",
204
+ "test",
205
+ await deployer.getAddress(),
206
+ ),
197
207
  ).rejectedWith("Factory: depositVerifier address is required");
198
208
  });
199
209
 
@@ -216,7 +226,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
216
226
  batchLockVerifier: "0x0000000000000000000000000000000000000000",
217
227
  burnVerifier: "0x0000000000000000000000000000000000000000",
218
228
  batchBurnVerifier: "0x0000000000000000000000000000000000000000",
219
- }
229
+ },
220
230
  };
221
231
  const tx1 = await factory
222
232
  .connect(deployer)
@@ -226,7 +236,12 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
226
236
  await expect(
227
237
  factory
228
238
  .connect(deployer)
229
- .deployZetoFungibleToken("name", "symbol", "test", await deployer.getAddress()),
239
+ .deployZetoFungibleToken(
240
+ "name",
241
+ "symbol",
242
+ "test",
243
+ await deployer.getAddress(),
244
+ ),
230
245
  ).rejectedWith("Factory: withdrawVerifier address is required");
231
246
  });
232
247
 
@@ -249,7 +264,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
249
264
  batchLockVerifier: "0x0000000000000000000000000000000000000000",
250
265
  burnVerifier: "0x0000000000000000000000000000000000000000",
251
266
  batchBurnVerifier: "0x0000000000000000000000000000000000000000",
252
- }
267
+ },
253
268
  };
254
269
  const tx1 = await factory
255
270
  .connect(deployer)
@@ -259,68 +274,15 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
259
274
  await expect(
260
275
  factory
261
276
  .connect(deployer)
262
- .deployZetoFungibleToken("name", "symbol", "test", await deployer.getAddress()),
277
+ .deployZetoFungibleToken(
278
+ "name",
279
+ "symbol",
280
+ "test",
281
+ await deployer.getAddress(),
282
+ ),
263
283
  ).rejectedWith("Factory: batchWithdrawVerifier address is required");
264
284
  });
265
285
 
266
- // it("attempting to deploy a fungible token but with a registered implementation that misses required lockVerifier should fail", async function () {
267
- // // we want to test the effectiveness of the factory contract
268
- // // to create clones of the Zeto implementation contract
269
- // const Factory = await ethers.getContractFactory("ZetoTokenFactory");
270
- // const factory = await Factory.deploy();
271
- // await factory.waitForDeployment();
272
-
273
- // const implInfo = {
274
- // implementation: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
275
- // verifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
276
- // batchVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
277
- // depositVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
278
- // withdrawVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
279
- // batchWithdrawVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
280
- // lockVerifier: "0x0000000000000000000000000000000000000000",
281
- // batchLockVerifier: "0x0000000000000000000000000000000000000000",
282
- // };
283
- // const tx1 = await factory
284
- // .connect(deployer)
285
- // .registerImplementation("test", implInfo as any);
286
- // await tx1.wait();
287
-
288
- // await expect(
289
- // factory
290
- // .connect(deployer)
291
- // .deployZetoFungibleToken("test", await deployer.getAddress()),
292
- // ).rejectedWith("Factory: lockVerifier address is required");
293
- // });
294
-
295
- // it("attempting to deploy a fungible token but with a registered implementation that misses required batchLockVerifier should fail", async function () {
296
- // // we want to test the effectiveness of the factory contract
297
- // // to create clones of the Zeto implementation contract
298
- // const Factory = await ethers.getContractFactory("ZetoTokenFactory");
299
- // const factory = await Factory.deploy();
300
- // await factory.waitForDeployment();
301
-
302
- // const implInfo = {
303
- // implementation: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
304
- // verifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
305
- // batchVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
306
- // depositVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
307
- // withdrawVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
308
- // batchWithdrawVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
309
- // lockVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
310
- // batchLockVerifier: "0x0000000000000000000000000000000000000000",
311
- // };
312
- // const tx1 = await factory
313
- // .connect(deployer)
314
- // .registerImplementation("test", implInfo as any);
315
- // await tx1.wait();
316
-
317
- // await expect(
318
- // factory
319
- // .connect(deployer)
320
- // .deployZetoFungibleToken("test", await deployer.getAddress()),
321
- // ).rejectedWith("Factory: batchLockVerifier address is required");
322
- // });
323
-
324
286
  it("attempting to deploy a fungible token with a properly registered implementation should succeed", async function () {
325
287
  // we want to test the effectiveness of the factory contract
326
288
  // to create clones of the Zeto implementation contract
@@ -328,8 +290,14 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
328
290
  const factory = await Factory.deploy();
329
291
  await factory.waitForDeployment();
330
292
 
293
+ // deploy a real Zeto token so that the "implementation" contract can
294
+ // pass the code length check in the ERC1967Proxy contract
295
+ const Zeto = await ethers.getContractFactory("Zeto_Anon");
296
+ const zeto = await Zeto.deploy();
297
+ await zeto.waitForDeployment();
298
+
331
299
  const implInfo = {
332
- implementation: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
300
+ implementation: zeto.target,
333
301
  verifiers: {
334
302
  verifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
335
303
  batchVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
@@ -340,7 +308,7 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
340
308
  batchLockVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
341
309
  burnVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
342
310
  batchBurnVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
343
- }
311
+ },
344
312
  };
345
313
  const tx1 = await factory
346
314
  .connect(deployer)
@@ -350,7 +318,12 @@ describe("(factory) Zeto based fungible token with anonymity without encryption
350
318
  await expect(
351
319
  factory
352
320
  .connect(deployer)
353
- .deployZetoFungibleToken("name", "symbol", "test", await deployer.getAddress()),
321
+ .deployZetoFungibleToken(
322
+ "name",
323
+ "symbol",
324
+ "test",
325
+ await deployer.getAddress(),
326
+ ),
354
327
  ).fulfilled;
355
328
  });
356
329
  });
@@ -0,0 +1,89 @@
1
+ // Copyright © 2024 Kaleido, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ //
5
+ // ZK helpers for the `anon_nullifier_transfer` circuit family ({Zeto_AnonNullifier}
6
+ // unlocked-input transfers and createLock). Extracted so escrow and other suites
7
+ // can use them without importing the full `zeto_anon_nullifier.ts` Hardhat module.
8
+
9
+ import { AbiCoder, BigNumberish, ethers } from "ethers";
10
+ import { encodeProof } from "zeto-js";
11
+ import { groth16 } from "snarkjs";
12
+ import { User, UTXO, logger } from "./utils";
13
+
14
+ /**
15
+ * Build a Groth16 proof for an unlocked-input nullifier transfer (merkle-backed).
16
+ */
17
+ export async function prepareProof(
18
+ circuit: any,
19
+ provingKey: any,
20
+ signer: User,
21
+ inputs: UTXO[],
22
+ _nullifiers: UTXO[],
23
+ outputs: UTXO[],
24
+ root: BigInt,
25
+ merkleProof: BigInt[][],
26
+ owners: User[],
27
+ lockDelegate?: string,
28
+ ) {
29
+ const nullifiers = _nullifiers.map((nullifier) => nullifier.hash) as [
30
+ BigNumberish,
31
+ BigNumberish,
32
+ ];
33
+ const inputCommitments: BigNumberish[] = inputs.map(
34
+ (input) => input.hash,
35
+ ) as BigNumberish[];
36
+ const inputValues = inputs.map((input) => BigInt(input.value || 0n));
37
+ const inputSalts = inputs.map((input) => input.salt || 0n);
38
+ const outputCommitments: BigNumberish[] = outputs.map(
39
+ (output) => output.hash,
40
+ ) as BigNumberish[];
41
+ const outputValues = outputs.map((output) => BigInt(output.value || 0n));
42
+ const outputOwnerPublicKeys: BigNumberish[][] = owners.map(
43
+ (owner) => owner.babyJubPublicKey,
44
+ ) as BigNumberish[][];
45
+
46
+ const startWitnessCalculation = Date.now();
47
+ const inputObj: Record<string, unknown> = {
48
+ nullifiers,
49
+ inputCommitments,
50
+ inputValues,
51
+ inputSalts,
52
+ inputOwnerPrivateKey: signer.formattedPrivateKey,
53
+ root,
54
+ enabled: nullifiers.map((n) => (n !== 0n ? 1 : 0)),
55
+ merkleProof,
56
+ outputCommitments,
57
+ outputValues,
58
+ outputSalts: outputs.map((output) => output.salt || 0n),
59
+ outputOwnerPublicKeys,
60
+ };
61
+ if (lockDelegate) {
62
+ inputObj["lockDelegate"] = ethers.toBigInt(lockDelegate);
63
+ }
64
+
65
+ const witness = await circuit.calculateWTNSBin(inputObj, true);
66
+ const timeWithnessCalculation = Date.now() - startWitnessCalculation;
67
+
68
+ const startProofGeneration = Date.now();
69
+ const { proof } = (await groth16.prove(provingKey, witness)) as {
70
+ proof: BigNumberish[];
71
+ publicSignals: BigNumberish[];
72
+ };
73
+ const timeProofGeneration = Date.now() - startProofGeneration;
74
+
75
+ logger.debug(
76
+ `Witness calculation time: ${timeWithnessCalculation}ms. Proof generation time: ${timeProofGeneration}ms.`,
77
+ );
78
+
79
+ const encodedProof = encodeProof(proof);
80
+ return encodedProof;
81
+ }
82
+
83
+ /** ABI encoding for nullifier transfer proofs: root prefix + Groth16 tuple. */
84
+ export function encodeToBytes(root: any, proof: any) {
85
+ return new AbiCoder().encode(
86
+ ["uint256 root", "tuple(uint256[2] pA, uint256[2][2] pB, uint256[2] pC)"],
87
+ [root, proof],
88
+ );
89
+ }
@@ -0,0 +1,76 @@
1
+ // Copyright © 2024 Kaleido, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ //
5
+ // Shared ZK helpers for the plain `anon` circuit (non-nullifier tokens such as
6
+ // {Zeto_Anon}). Kept separate from `zeto_anon.ts` so escrow and other suites
7
+ // can import these without registering the full Zeto_Anon Hardhat test module.
8
+
9
+ import { AbiCoder, BigNumberish } from "ethers";
10
+ import { encodeProof } from "zeto-js";
11
+ import { groth16 } from "snarkjs";
12
+ import { formatPrivKeyForBabyJub, stringifyBigInts } from "maci-crypto";
13
+ import { User, UTXO, logger, ZERO_UTXO } from "./utils";
14
+
15
+ const ZERO_PUBKEY = [0n, 0n];
16
+
17
+ export async function prepareProof(
18
+ circuit: any,
19
+ provingKey: any,
20
+ signer: User,
21
+ inputs: UTXO[],
22
+ outputs: UTXO[],
23
+ owners: User[],
24
+ ) {
25
+ const inputCommitments: BigNumberish[] = inputs.map(
26
+ (input) => input.hash,
27
+ ) as BigNumberish[];
28
+ const inputValues = inputs.map((input) => BigInt(input.value || 0n));
29
+ const inputSalts = inputs.map((input) => input.salt || 0n);
30
+ const outputCommitments: BigNumberish[] = outputs.map(
31
+ (output) => output.hash,
32
+ ) as BigNumberish[];
33
+ const outputValues = outputs.map((output) => BigInt(output.value || 0n));
34
+ const outputSalts = outputs.map((o) => o.salt || 0n);
35
+ const outputOwnerPublicKeys: BigNumberish[][] = owners.map(
36
+ (owner) => owner.babyJubPublicKey || ZERO_PUBKEY,
37
+ ) as BigNumberish[][];
38
+ const otherInputs = stringifyBigInts({
39
+ inputOwnerPrivateKey: formatPrivKeyForBabyJub(signer.babyJubPrivateKey),
40
+ });
41
+
42
+ const startWitnessCalculation = Date.now();
43
+ const witness = await circuit.calculateWTNSBin(
44
+ {
45
+ inputCommitments,
46
+ inputValues,
47
+ inputSalts,
48
+ outputCommitments,
49
+ outputValues,
50
+ outputSalts,
51
+ outputOwnerPublicKeys,
52
+ ...otherInputs,
53
+ },
54
+ true,
55
+ );
56
+ const timeWitnessCalculation = Date.now() - startWitnessCalculation;
57
+
58
+ const startProofGeneration = Date.now();
59
+ const { proof, publicSignals } = (await groth16.prove(
60
+ provingKey,
61
+ witness,
62
+ )) as { proof: BigNumberish[]; publicSignals: BigNumberish[] };
63
+ const timeProofGeneration = Date.now() - startProofGeneration;
64
+ logger.debug(
65
+ `Witness calculation time: ${timeWitnessCalculation}ms, Proof generation time: ${timeProofGeneration}ms`,
66
+ );
67
+ const encodedProof = encodeProof(proof);
68
+ return encodedProof;
69
+ }
70
+
71
+ export function encodeToBytes(proof: any) {
72
+ return new AbiCoder().encode(
73
+ ["tuple(uint256[2] pA, uint256[2][2] pB, uint256[2] pC)"],
74
+ [proof],
75
+ );
76
+ }
@@ -10,6 +10,7 @@ import {
10
10
  deployNonFungible as deployNonFungibleCloneable,
11
11
  } from "../../scripts/deploy_cloneable";
12
12
  import fungibilities from "../../scripts/tokens.json";
13
+ import { logger } from "./utils";
13
14
  import { ethers } from "hardhat";
14
15
 
15
16
  export async function deployZeto(tokenName: string) {
@@ -34,7 +35,7 @@ export async function deployZeto(tokenName: string) {
34
35
  }
35
36
 
36
37
  if (process.env.USE_FACTORY !== "true") {
37
- console.log("Deploying as upgradeable contracts");
38
+ logger.debug("Deploying as upgradeable contracts");
38
39
  // setup via the deployment scripts
39
40
  const deployFunc = isFungible
40
41
  ? deployFungibleUpgradeable
@@ -42,7 +43,7 @@ export async function deployZeto(tokenName: string) {
42
43
  const result = await deployFunc(tokenName);
43
44
  ({ deployer, zeto, erc20 } = result as any);
44
45
  } else {
45
- console.log('Deploying as cloneable contracts using "ZetoTokenFactory"');
46
+ logger.debug('Deploying as cloneable contracts using "ZetoTokenFactory"');
46
47
  let args, zetoImpl;
47
48
  const deployFunc = isFungible
48
49
  ? deployFungibleCloneable
package/test/lib/utils.ts CHANGED
@@ -18,13 +18,15 @@ import {
18
18
  ContractTransactionReceipt,
19
19
  Signer,
20
20
  BigNumberish,
21
- AddressLike,
22
21
  } from "ethers";
23
22
  import {
24
23
  genKeypair,
25
24
  formatPrivKeyForBabyJub,
26
- genEcdhSharedKey,
27
25
  } from "maci-crypto";
26
+ import { Logger, ILogObj } from "tslog";
27
+ const logLevel = process.env.LOG_LEVEL || "3";
28
+ export const logger: Logger<ILogObj> = new Logger({ name: "e2e", minLevel: parseInt(logLevel) });
29
+
28
30
  import { Poseidon, newSalt, tokenUriHash } from "zeto-js";
29
31
 
30
32
  const poseidonHash3 = Poseidon.poseidon3;
@@ -35,18 +37,18 @@ export interface UTXO {
35
37
  value?: number;
36
38
  tokenId?: number;
37
39
  uri?: string;
38
- hash: BigInt;
39
- salt?: BigInt;
40
+ hash: bigint;
41
+ salt?: bigint;
40
42
  }
41
43
 
42
- export const ZERO_UTXO: UTXO = { hash: BigInt(0) };
44
+ export const ZERO_UTXO: UTXO = { hash: 0n };
43
45
 
44
46
  export interface User {
45
47
  signer: Signer;
46
48
  ethAddress: string;
47
- babyJubPrivateKey: BigInt;
48
- babyJubPublicKey: BigInt[];
49
- formattedPrivateKey: BigInt;
49
+ babyJubPrivateKey: bigint;
50
+ babyJubPublicKey: bigint[];
51
+ formattedPrivateKey: bigint;
50
52
  }
51
53
 
52
54
  export async function newUser(signer: Signer) {
@@ -62,7 +64,7 @@ export async function newUser(signer: Signer) {
62
64
  };
63
65
  }
64
66
 
65
- export function newUTXO(value: number, owner: User, salt?: BigInt): UTXO {
67
+ export function newUTXO(value: number, owner: User, salt?: bigint): UTXO {
66
68
  if (!salt) salt = newSalt();
67
69
  const hash = poseidonHash4([
68
70
  BigInt(value),
@@ -77,7 +79,7 @@ export function newAssetUTXO(
77
79
  tokenId: number,
78
80
  uri: string,
79
81
  owner: User,
80
- salt?: BigInt,
82
+ salt?: bigint,
81
83
  ): UTXO {
82
84
  if (!salt) salt = newSalt();
83
85
  const hash = poseidonHash5([
@@ -122,10 +124,13 @@ export async function doMint(
122
124
  .connect(minter)
123
125
  .mint(outputCommitments, "0x");
124
126
  const result = await tx.wait();
125
- console.log(`Method mint() complete. Gas used: ${result?.gasUsed}`);
127
+ logger.debug(`Method mint() complete. Gas used: ${result?.gasUsed}`);
126
128
  if (result?.gasUsed && Array.isArray(gasHistories)) {
127
129
  gasHistories.push(result?.gasUsed);
128
130
  }
131
+ if (!result) {
132
+ throw new Error("doMint: transaction receipt is null");
133
+ }
129
134
  return result;
130
135
  }
131
136
 
@@ -141,10 +146,13 @@ export async function doDeposit(
141
146
  .connect(depositUser)
142
147
  .deposit(amount, commitment, proof, "0x");
143
148
  const result = await tx.wait();
144
- console.log(`Method deposit() complete. Gas used: ${result?.gasUsed}`);
149
+ logger.debug(`Method deposit() complete. Gas used: ${result?.gasUsed}`);
145
150
  if (result?.gasUsed && Array.isArray(gasHistories)) {
146
151
  gasHistories.push(result?.gasUsed);
147
152
  }
153
+ if (!result) {
154
+ throw new Error("doDeposit: transaction receipt is null");
155
+ }
148
156
  return result;
149
157
  }
150
158
 
@@ -162,17 +170,23 @@ export async function doWithdraw(
162
170
  .connect(withdrawUser)
163
171
  .withdraw(amount, nullifiers, commitment, root, proof);
164
172
  const result = await tx.wait();
165
- console.log(`Method withdraw() complete. Gas used: ${result?.gasUsed}`);
173
+ logger.debug(`Method withdraw() complete. Gas used: ${result?.gasUsed}`);
166
174
  if (result?.gasUsed && Array.isArray(gasHistories)) {
167
175
  gasHistories.push(result?.gasUsed);
168
176
  }
177
+ if (!result) {
178
+ throw new Error("doWithdraw: transaction receipt is null");
179
+ }
169
180
  return result;
170
181
  }
171
182
 
172
183
  export function parseUTXOEvents(
173
184
  zetoTokenContract: any,
174
- result: ContractTransactionReceipt,
185
+ result: ContractTransactionReceipt | null,
175
186
  ) {
187
+ if (!result) {
188
+ throw new Error("parseUTXOEvents: transaction receipt is null");
189
+ }
176
190
  let returnValues: any[] = [];
177
191
  for (const log of result.logs || []) {
178
192
  const event = zetoTokenContract.interface.parseLog(log as any);
@@ -183,6 +197,13 @@ export function parseUTXOEvents(
183
197
  outputs: event?.args.outputs,
184
198
  submitter: event?.args.submitter,
185
199
  };
200
+ } else if (event?.name === "UTXOTransferLocked") {
201
+ e = {
202
+ lockedInputs: event?.args.lockedInputs,
203
+ lockedOutputs: event?.args.lockedOutputs,
204
+ outputs: event?.args.outputs,
205
+ submitter: event?.args.submitter,
206
+ };
186
207
  } else if (event?.name === "UTXOTransferWithEncryptedValues") {
187
208
  e = {
188
209
  inputs: event?.args.inputs,
@@ -192,6 +213,15 @@ export function parseUTXOEvents(
192
213
  submitter: event?.args.submitter,
193
214
  ecdhPublicKey: event?.args.ecdhPublicKey,
194
215
  };
216
+ } else if (event?.name === "UTXOTransferWithMlkemEncryptedValues") {
217
+ e = {
218
+ inputs: event?.args.inputs,
219
+ outputs: event?.args.outputs,
220
+ encryptedValues: event?.args.encryptedValues,
221
+ encryptionNonce: event?.args.encryptionNonce,
222
+ submitter: event?.args.submitter,
223
+ encapsulatedSharedSecret: event?.args.encapsulatedSharedSecret,
224
+ };
195
225
  } else if (event?.name === "UTXOTransferNonRepudiation") {
196
226
  e = {
197
227
  inputs: event?.args.inputs,
@@ -208,36 +238,45 @@ export function parseUTXOEvents(
208
238
  receivers: event?.args.receivers,
209
239
  submitter: event?.args.submitter,
210
240
  };
211
- } else if (event?.name === "TradeCompleted") {
241
+ } else if (event?.name === "UTXOWithdraw") {
212
242
  e = {
213
- tradeId: event?.args.tradeId,
214
- trade: event?.args.trade,
243
+ amount: event?.args.amount,
244
+ inputs: event?.args.inputs,
245
+ output: event?.args.output,
215
246
  };
216
- } else if (event?.name === "UTXOsLocked") {
247
+ } else if (event?.name === "LockCreate") {
217
248
  e = {
218
- outputs: event?.args.outputs,
219
- lockedOutputs: event?.args.lockedOutputs,
220
- delegate: event?.args.delegate,
249
+ lockId: event?.args.lockId,
250
+ lockData: event?.args.lockData,
221
251
  };
222
- } else if (event?.name === "LockDelegateChanged") {
252
+ } else if (event?.name === "UnlockPrepare") {
223
253
  e = {
224
- lockedOutputs: event?.args.lockedOutputs,
225
- oldDelegate: event?.args.oldDelegate,
226
- newDelegate: event?.args.newDelegate,
254
+ lockId: event?.args.lockId,
255
+ operator: event?.args.operator,
256
+ settle: event?.args.settle,
227
257
  };
228
- } else if (event?.name === "PaymentInitiated") {
258
+ } else if (event?.name === "Unlock") {
229
259
  e = {
230
- paymentId: event?.args.paymentId,
231
- lockedInputs: event?.args.lockedInputs,
232
- nullifiers: event?.args.nullifiers,
233
- outputs: event?.args.outputs,
260
+ lockId: event?.args.lockId,
261
+ operator: event?.args.operator,
262
+ inputs: event?.args.inputs,
263
+ delegate: event?.args.delegate,
264
+ settle: event?.args.settle,
234
265
  };
235
- } else if (
236
- event?.name === "PaymentApproved" ||
237
- event?.name === "PaymentCompleted"
238
- ) {
266
+ } else if (event?.name === "LockRollback") {
239
267
  e = {
240
- paymentId: event?.args.paymentId,
268
+ lockId: event?.args.lockId,
269
+ operator: event?.args.operator,
270
+ inputs: event?.args.inputs,
271
+ delegate: event?.args.delegate,
272
+ rollback: event?.args.rollback,
273
+ };
274
+ } else if (event?.name === "LockDelegate") {
275
+ e = {
276
+ lockId: event?.args.lockId,
277
+ operator: event?.args.operator,
278
+ oldDelegate: event?.args.oldDelegate,
279
+ newDelegate: event?.args.newDelegate,
241
280
  };
242
281
  }
243
282
  returnValues.push(e);