@lfdecentralizedtrust/zeto-contracts 0.2.2 → 0.5.1

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 (164) hide show
  1. package/README.md +76 -162
  2. package/config/eip170.ts +30 -0
  3. package/contracts/factory.sol +30 -34
  4. package/contracts/factory_upgradeable.sol +11 -7
  5. package/contracts/lib/common/util.sol +40 -0
  6. package/contracts/lib/interfaces/ILockableCapability.sol +318 -0
  7. package/contracts/lib/interfaces/{izeto.sol → IZeto.sol} +13 -1
  8. package/contracts/lib/interfaces/{izeto_initializable.sol → IZetoInitializable.sol} +14 -12
  9. package/contracts/lib/interfaces/{izeto_kyc.sol → IZetoKyc.sol} +3 -3
  10. package/contracts/lib/interfaces/IZetoLockHooks.sol +42 -0
  11. package/contracts/lib/interfaces/IZetoLockableCapability.sol +237 -0
  12. package/contracts/lib/interfaces/IZetoStorage.sol +106 -0
  13. package/contracts/lib/interfaces/{izeto_lockable.sol → IZetoVerifier.sol} +8 -21
  14. package/contracts/lib/registry.sol +74 -26
  15. package/contracts/lib/storage/base.sol +210 -0
  16. package/contracts/lib/storage/nullifier.sol +166 -0
  17. package/contracts/lib/zeto_common.sol +277 -28
  18. package/contracts/lib/zeto_fungible.sol +443 -33
  19. package/contracts/lib/zeto_fungible_base.sol +69 -0
  20. package/contracts/lib/zeto_fungible_burn.sol +83 -53
  21. package/contracts/lib/zeto_fungible_burn_nullifier.sol +115 -72
  22. package/contracts/lib/zeto_fungible_nullifier.sol +167 -0
  23. package/contracts/lib/zeto_lockable.sol +219 -0
  24. package/contracts/lib/zeto_lockable_lib.sol +460 -0
  25. package/contracts/lib/zeto_lockable_storage.sol +43 -0
  26. package/contracts/lib/zeto_non_fungible.sol +228 -0
  27. package/contracts/lib/zeto_non_fungible_base.sol +61 -0
  28. package/contracts/lib/zeto_non_fungible_nullifier.sol +61 -0
  29. package/contracts/test/escrow1.sol +90 -34
  30. package/contracts/test/escrow2.sol +64 -29
  31. package/contracts/test/qurrency.sol +10 -2
  32. package/contracts/test/smt.sol +6 -1
  33. package/contracts/test/tendecimals.sol +14 -12
  34. package/contracts/verifiers/impl/anon.sol +189 -0
  35. package/contracts/verifiers/impl/anon_batch.sol +301 -0
  36. package/contracts/verifiers/impl/anon_enc.sol +266 -0
  37. package/contracts/verifiers/impl/anon_enc_batch.sol +602 -0
  38. package/contracts/verifiers/impl/anon_enc_nullifier.sol +287 -0
  39. package/contracts/verifiers/impl/anon_enc_nullifier_batch.sol +679 -0
  40. package/contracts/verifiers/impl/anon_enc_nullifier_kyc.sol +294 -0
  41. package/contracts/verifiers/impl/anon_enc_nullifier_kyc_batch.sol +686 -0
  42. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation.sol +413 -0
  43. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation_batch.sol +1141 -0
  44. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer.sol +217 -0
  45. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked.sol +196 -0
  46. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked_batch.sol +308 -0
  47. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer_batch.sol +385 -0
  48. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer.sol +497 -0
  49. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer_batch.sol +1001 -0
  50. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked.sol → impl/anon_nullifier_transfer.sol} +12 -19
  51. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked_batch.sol → impl/anon_nullifier_transfer_batch.sol} +44 -51
  52. package/contracts/verifiers/impl/burn.sol +182 -0
  53. package/contracts/verifiers/impl/burn_batch.sol +238 -0
  54. package/contracts/verifiers/impl/burn_nullifier.sol +203 -0
  55. package/contracts/verifiers/impl/burn_nullifier_batch.sol +315 -0
  56. package/contracts/verifiers/impl/deposit.sol +182 -0
  57. package/contracts/verifiers/impl/deposit_kyc.sol +189 -0
  58. package/contracts/verifiers/impl/nf_anon.sol +175 -0
  59. package/contracts/verifiers/{verifier_nf_anon_nullifier_transferLocked.sol → impl/nf_anon_nullifier_transfer.sol} +6 -13
  60. package/contracts/verifiers/impl/withdraw.sol +189 -0
  61. package/contracts/verifiers/impl/withdraw_batch.sol +245 -0
  62. package/contracts/verifiers/impl/withdraw_nullifier.sol +210 -0
  63. package/contracts/verifiers/impl/withdraw_nullifier_batch.sol +322 -0
  64. package/contracts/verifiers/verifier_anon.sol +31 -186
  65. package/contracts/verifiers/verifier_anon_batch.sol +31 -298
  66. package/contracts/verifiers/verifier_anon_enc.sol +31 -263
  67. package/contracts/verifiers/verifier_anon_enc_batch.sol +31 -599
  68. package/contracts/verifiers/verifier_anon_enc_nullifier.sol +31 -284
  69. package/contracts/verifiers/verifier_anon_enc_nullifier_batch.sol +33 -676
  70. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc.sol +31 -291
  71. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc_batch.sol +33 -683
  72. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation.sol +33 -410
  73. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation_batch.sol +33 -1138
  74. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer.sol +33 -214
  75. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked.sol +33 -221
  76. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked_batch.sol +33 -389
  77. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer_batch.sol +33 -382
  78. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer.sol +33 -221
  79. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer_batch.sol +33 -389
  80. package/contracts/verifiers/verifier_anon_nullifier_transfer.sol +33 -207
  81. package/contracts/verifiers/verifier_anon_nullifier_transfer_batch.sol +33 -375
  82. package/contracts/verifiers/verifier_burn.sol +31 -179
  83. package/contracts/verifiers/verifier_burn_batch.sol +31 -235
  84. package/contracts/verifiers/verifier_burn_nullifier.sol +31 -200
  85. package/contracts/verifiers/verifier_burn_nullifier_batch.sol +31 -312
  86. package/contracts/verifiers/verifier_deposit.sol +31 -179
  87. package/contracts/verifiers/verifier_deposit_kyc.sol +34 -0
  88. package/contracts/verifiers/verifier_nf_anon.sol +31 -172
  89. package/contracts/verifiers/verifier_nf_anon_nullifier_transfer.sol +33 -179
  90. package/contracts/verifiers/verifier_withdraw.sol +31 -186
  91. package/contracts/verifiers/verifier_withdraw_batch.sol +31 -242
  92. package/contracts/verifiers/verifier_withdraw_nullifier.sol +31 -207
  93. package/contracts/verifiers/verifier_withdraw_nullifier_batch.sol +33 -319
  94. package/contracts/zeto_anon.sol +77 -231
  95. package/contracts/zeto_anon_burnable.sol +56 -12
  96. package/contracts/zeto_anon_enc.sol +93 -190
  97. package/contracts/zeto_anon_enc_nullifier.sol +249 -195
  98. package/contracts/zeto_anon_enc_nullifier_kyc.sol +51 -232
  99. package/contracts/zeto_anon_enc_nullifier_non_repudiation.sol +231 -238
  100. package/contracts/zeto_anon_nullifier.sol +164 -298
  101. package/contracts/zeto_anon_nullifier_burnable.sol +68 -18
  102. package/contracts/zeto_anon_nullifier_kyc.sol +40 -345
  103. package/contracts/zeto_anon_nullifier_qurrency.sol +217 -361
  104. package/contracts/zeto_nf_anon.sol +55 -130
  105. package/contracts/zeto_nf_anon_nullifier.sol +90 -152
  106. package/hardhat.config.ts +18 -3
  107. package/ignition/modules/lib/deps.ts +13 -0
  108. package/ignition/modules/test/tendecimals.ts +7 -1
  109. package/ignition/modules/zeto_anon.ts +3 -0
  110. package/ignition/modules/zeto_anon_burnable.ts +11 -7
  111. package/ignition/modules/zeto_anon_enc.ts +3 -0
  112. package/ignition/modules/zeto_anon_enc_nullifier.ts +34 -0
  113. package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +5 -2
  114. package/ignition/modules/zeto_anon_enc_nullifier_non_repudiation.ts +3 -0
  115. package/ignition/modules/zeto_anon_nullifier.ts +31 -4
  116. package/ignition/modules/zeto_anon_nullifier_burnable.ts +53 -16
  117. package/ignition/modules/zeto_anon_nullifier_kyc.ts +30 -12
  118. package/ignition/modules/zeto_anon_nullifier_qurrency.ts +3 -0
  119. package/ignition/modules/zeto_nf_anon.ts +3 -1
  120. package/ignition/modules/zeto_nf_anon_nullifier.ts +17 -12
  121. package/package.json +7 -3
  122. package/scripts/deploy_cloneable.ts +19 -10
  123. package/scripts/deploy_upgradeable.ts +9 -5
  124. package/scripts/lib/zeto_libraries.ts +47 -0
  125. package/scripts/tokens/Zeto_Anon.ts +6 -3
  126. package/scripts/tokens/Zeto_AnonBurnable.ts +4 -1
  127. package/scripts/tokens/Zeto_AnonEnc.ts +15 -3
  128. package/scripts/tokens/Zeto_AnonEncNullifier.ts +11 -8
  129. package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +7 -6
  130. package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +7 -6
  131. package/scripts/tokens/Zeto_AnonNullifier.ts +7 -6
  132. package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +7 -6
  133. package/scripts/tokens/Zeto_AnonNullifierKyc.ts +7 -6
  134. package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +7 -8
  135. package/scripts/tokens/Zeto_NfAnon.ts +5 -3
  136. package/scripts/tokens/Zeto_NfAnonNullifier.ts +7 -7
  137. package/test/factory.ts +55 -73
  138. package/test/lib/anon_nullifier_helpers.ts +89 -0
  139. package/test/lib/anon_zeto_helpers.ts +76 -0
  140. package/test/lib/deploy.ts +5 -2
  141. package/test/lib/eip170.ts +23 -0
  142. package/test/lib/utils.ts +74 -35
  143. package/test/test/escrow1.ts +185 -58
  144. package/test/test/escrow2.ts +200 -107
  145. package/test/test/qurrency.ts +13 -33
  146. package/test/usdc-shielding.ts +39 -27
  147. package/test/utils.ts +144 -21
  148. package/test/zeto_anon.ts +956 -465
  149. package/test/zeto_anon_enc.ts +881 -143
  150. package/test/zeto_anon_enc_nullifier.ts +850 -39
  151. package/test/zeto_anon_enc_nullifier_kyc.ts +123 -182
  152. package/test/zeto_anon_enc_nullifier_non_repudiation.ts +80 -47
  153. package/test/zeto_anon_nullifier.ts +1212 -954
  154. package/test/zeto_anon_nullifier_kyc.ts +677 -656
  155. package/test/zeto_anon_nullifier_qurrency.ts +455 -307
  156. package/test/zeto_nf_anon.ts +737 -138
  157. package/test/zeto_nf_anon_nullifier.ts +876 -247
  158. package/contracts/lib/zeto_base.sol +0 -293
  159. package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
  160. package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
  161. package/contracts/lib/zeto_nullifier.sol +0 -340
  162. package/contracts/zkDvP.sol_ +0 -273
  163. package/test/zkDvP.ts_ +0 -455
  164. /package/contracts/lib/{common.sol → common/common.sol} +0 -0
@@ -20,6 +20,7 @@ import {
20
20
  DepositVerifierModule,
21
21
  WithdrawNullifierVerifierModule,
22
22
  BatchWithdrawNullifierVerifierModule,
23
+ ZetoLockableLibModule,
23
24
  } from "./lib/deps";
24
25
 
25
26
  const VerifierModule = buildModule("Groth16Verifier_AnonEncNullifier", (m) => {
@@ -35,10 +36,40 @@ const BatchVerifierModule = buildModule(
35
36
  },
36
37
  );
37
38
 
39
+ // Locked-input transfers reuse the plain {Groth16Verifier_AnonEnc} verifier
40
+ // (the same one the non-nullifier {Zeto_AnonEnc} token uses for its
41
+ // regular transfers), NOT a nullifier-aware verifier.
42
+ //
43
+ // Rationale: under the new ILockableCapability storage, locked UTXOs are
44
+ // kept in a flat per-lock mapping keyed by lockId — there is no SMT for
45
+ // locked UTXOs and the locked-input proof has no nullifier history to
46
+ // bind against. {Zeto_AnonEncNullifier.constructPublicInputs(...,
47
+ // inputsLocked = true)} reflects this by emitting public inputs as
48
+ // `[ecdhPublicKey, encryptedValues, inputCommitments, outputCommitments,
49
+ // encryptionNonce]` — exactly what `Groth16Verifier_AnonEnc` expects.
50
+ // The encryption witness (ECDH key + encrypted blob) still applies because
51
+ // the receiver still needs data availability for the post-spend outputs.
52
+ const LockVerifierModule = buildModule("Groth16Verifier_AnonEnc", (m) => {
53
+ const verifier = m.contract("Groth16Verifier_AnonEnc", []);
54
+ return { verifier };
55
+ });
56
+
57
+ // Batched (10-in / 10-out) twin of {LockVerifierModule}. Same rationale.
58
+ const BatchLockVerifierModule = buildModule(
59
+ "Groth16Verifier_AnonEncBatch",
60
+ (m) => {
61
+ const verifier = m.contract("Groth16Verifier_AnonEncBatch", []);
62
+ return { verifier };
63
+ },
64
+ );
65
+
38
66
  export default buildModule("Zeto_AnonEncNullifier", (m) => {
67
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
39
68
  const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
40
69
  const { verifier } = m.useModule(VerifierModule);
70
+ const { verifier: lockVerifier } = m.useModule(LockVerifierModule);
41
71
  const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
72
+ const { verifier: batchLockVerifier } = m.useModule(BatchLockVerifierModule);
42
73
  const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
43
74
  const { verifier: withdrawVerifier } = m.useModule(
44
75
  WithdrawNullifierVerifierModule,
@@ -51,10 +82,13 @@ export default buildModule("Zeto_AnonEncNullifier", (m) => {
51
82
  depositVerifier,
52
83
  withdrawVerifier,
53
84
  verifier,
85
+ lockVerifier,
54
86
  batchVerifier,
87
+ batchLockVerifier,
55
88
  batchWithdrawVerifier,
56
89
  smtLib,
57
90
  poseidon2,
58
91
  poseidon3,
92
+ zetoLockableLib,
59
93
  };
60
94
  });
@@ -17,9 +17,10 @@
17
17
  import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
18
18
  import {
19
19
  SmtLibModule,
20
- DepositVerifierModule,
20
+ DepositKycVerifierModule,
21
21
  WithdrawNullifierVerifierModule,
22
22
  BatchWithdrawNullifierVerifierModule,
23
+ ZetoLockableLibModule,
23
24
  } from "./lib/deps";
24
25
 
25
26
  const VerifierModule = buildModule(
@@ -39,10 +40,11 @@ const BatchVerifierModule = buildModule(
39
40
  );
40
41
 
41
42
  export default buildModule("Zeto_AnonEncNullifierKyc", (m) => {
43
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
42
44
  const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
43
45
  const { verifier } = m.useModule(VerifierModule);
44
46
  const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
45
- const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
47
+ const { verifier: depositVerifier } = m.useModule(DepositKycVerifierModule);
46
48
  const { verifier: withdrawVerifier } = m.useModule(
47
49
  WithdrawNullifierVerifierModule,
48
50
  );
@@ -59,5 +61,6 @@ export default buildModule("Zeto_AnonEncNullifierKyc", (m) => {
59
61
  smtLib,
60
62
  poseidon2,
61
63
  poseidon3,
64
+ zetoLockableLib,
62
65
  };
63
66
  });
@@ -20,6 +20,7 @@ import {
20
20
  DepositVerifierModule,
21
21
  WithdrawNullifierVerifierModule,
22
22
  BatchWithdrawNullifierVerifierModule,
23
+ ZetoLockableLibModule,
23
24
  } from "./lib/deps";
24
25
 
25
26
  const VerifierModule = buildModule(
@@ -45,6 +46,7 @@ const BatchVerifierModule = buildModule(
45
46
  );
46
47
 
47
48
  export default buildModule("Zeto_AnonEncNullifierNonRepudiation", (m) => {
49
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
48
50
  const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
49
51
  const { verifier } = m.useModule(VerifierModule);
50
52
  const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
@@ -64,5 +66,6 @@ export default buildModule("Zeto_AnonEncNullifierNonRepudiation", (m) => {
64
66
  smtLib,
65
67
  poseidon2,
66
68
  poseidon3,
69
+ zetoLockableLib,
67
70
  };
68
71
  });
@@ -20,6 +20,7 @@ import {
20
20
  DepositVerifierModule,
21
21
  WithdrawNullifierVerifierModule,
22
22
  BatchWithdrawNullifierVerifierModule,
23
+ ZetoLockableLibModule,
23
24
  } from "./lib/deps";
24
25
 
25
26
  const VerifierModule = buildModule(
@@ -30,11 +31,31 @@ const VerifierModule = buildModule(
30
31
  },
31
32
  );
32
33
 
34
+ // Locked-input transfers reuse the plain {Groth16Verifier_Anon} verifier
35
+ // (the same one the non-nullifier {Zeto_Anon} token uses for its regular
36
+ // transfers), NOT a nullifier-aware verifier.
37
+ //
38
+ // Rationale: under the new ILockableCapability storage, locked UTXOs are
39
+ // kept in a flat per-lock mapping keyed by lockId. Previously they were
40
+ // shadowed in a dedicated locked-state Sparse Merkle Tree (separate from
41
+ // the unlocked-UTXO SMT) so that the locked-input proof could assert
42
+ // SMT membership against a locked-state root; that secondary tree has
43
+ // been removed. As a result, settling a lock now consumes the locked
44
+ // UTXOs by their raw commitment hashes (the on-chain mapping enforces
45
+ // single-spend semantics — a lock can only be cleared once), so the
46
+ // proof has no nullifiers and no SMT membership to bind against. That
47
+ // matches exactly what the simpler `anon` circuit asserts: hash + sum +
48
+ // owner-key derivation over input/output commitments.
49
+ //
50
+ // The corresponding contract code path is
51
+ // {Zeto_AnonNullifier.constructPublicInputs(..., inputsLocked = true)},
52
+ // which emits public inputs as `[inputCommitments, outputCommitments]`
53
+ // — exactly the layout `Groth16Verifier_Anon` expects.
33
54
  const LockVerifierModule = buildModule(
34
- "Groth16Verifier_AnonNullifierTransferLocked",
55
+ "Groth16Verifier_Anon",
35
56
  (m) => {
36
57
  const verifier = m.contract(
37
- "Groth16Verifier_AnonNullifierTransferLocked",
58
+ "Groth16Verifier_Anon",
38
59
  [],
39
60
  );
40
61
  return { verifier };
@@ -52,11 +73,15 @@ const BatchVerifierModule = buildModule(
52
73
  },
53
74
  );
54
75
 
76
+ // Batched (10-in / 10-out) twin of {LockVerifierModule}. Same rationale:
77
+ // locked-input settlements consume raw UTXO commitments — not nullifiers
78
+ // — so the lock-side verifier is the plain `anon_batch` one, not the
79
+ // nullifier-aware `anon_nullifier_transfer_batch`.
55
80
  const BatchLockVerifierModule = buildModule(
56
- "Groth16Verifier_AnonNullifierTransferLockedBatch",
81
+ "Groth16Verifier_AnonBatch",
57
82
  (m) => {
58
83
  const verifier = m.contract(
59
- "Groth16Verifier_AnonNullifierTransferLockedBatch",
84
+ "Groth16Verifier_AnonBatch",
60
85
  [],
61
86
  );
62
87
  return { verifier };
@@ -64,6 +89,7 @@ const BatchLockVerifierModule = buildModule(
64
89
  );
65
90
 
66
91
  export default buildModule("Zeto_AnonNullifier", (m) => {
92
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
67
93
  const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
68
94
  const { verifier } = m.useModule(VerifierModule);
69
95
  const { verifier: lockVerifier } = m.useModule(LockVerifierModule);
@@ -88,5 +114,6 @@ export default buildModule("Zeto_AnonNullifier", (m) => {
88
114
  smtLib,
89
115
  poseidon2,
90
116
  poseidon3,
117
+ zetoLockableLib,
91
118
  };
92
119
  });
@@ -20,6 +20,7 @@ import {
20
20
  DepositVerifierModule,
21
21
  WithdrawNullifierVerifierModule,
22
22
  BatchWithdrawNullifierVerifierModule,
23
+ ZetoLockableLibModule,
23
24
  } from "./lib/deps";
24
25
 
25
26
  const VerifierModule = buildModule(
@@ -30,11 +31,31 @@ const VerifierModule = buildModule(
30
31
  },
31
32
  );
32
33
 
34
+ // Locked-input transfers reuse the plain {Groth16Verifier_Anon} verifier
35
+ // (the same one the non-nullifier {Zeto_Anon} token uses for its regular
36
+ // transfers), NOT a nullifier-aware verifier.
37
+ //
38
+ // Rationale: under the new ILockableCapability storage, locked UTXOs are
39
+ // kept in a flat per-lock mapping keyed by lockId. Previously they were
40
+ // shadowed in a dedicated locked-state Sparse Merkle Tree (separate from
41
+ // the unlocked-UTXO SMT) so that the locked-input proof could assert
42
+ // SMT membership against a locked-state root; that secondary tree has
43
+ // been removed. As a result, settling a lock now consumes the locked
44
+ // UTXOs by their raw commitment hashes (the on-chain mapping enforces
45
+ // single-spend semantics — a lock can only be cleared once), so the
46
+ // proof has no nullifiers and no SMT membership to bind against. That
47
+ // matches exactly what the simpler `anon` circuit asserts: hash + sum +
48
+ // owner-key derivation over input/output commitments.
49
+ //
50
+ // The corresponding contract code path is
51
+ // {Zeto_AnonNullifier.constructPublicInputs(..., inputsLocked = true)},
52
+ // which emits public inputs as `[inputCommitments, outputCommitments]`
53
+ // — exactly the layout `Groth16Verifier_Anon` expects.
33
54
  const LockVerifierModule = buildModule(
34
- "Groth16Verifier_AnonNullifierTransferLocked",
55
+ "Groth16Verifier_Anon",
35
56
  (m) => {
36
57
  const verifier = m.contract(
37
- "Groth16Verifier_AnonNullifierTransferLocked",
58
+ "Groth16Verifier_Anon",
38
59
  [],
39
60
  );
40
61
  return { verifier };
@@ -44,30 +65,47 @@ const LockVerifierModule = buildModule(
44
65
  const BatchVerifierModule = buildModule(
45
66
  "Groth16Verifier_AnonNullifierTransferBatch",
46
67
  (m) => {
47
- const verifier = m.contract("Groth16Verifier_AnonNullifierTransferBatch", []);
68
+ const verifier = m.contract(
69
+ "Groth16Verifier_AnonNullifierTransferBatch",
70
+ [],
71
+ );
48
72
  return { verifier };
49
73
  },
50
74
  );
51
75
 
76
+ // Batched (10-in / 10-out) twin of {LockVerifierModule}. Same rationale:
77
+ // locked-input settlements consume raw UTXO commitments — not nullifiers
78
+ // — so the lock-side verifier is the plain `anon_batch` one, not the
79
+ // nullifier-aware `anon_nullifier_transfer_batch`.
52
80
  const BatchLockVerifierModule = buildModule(
53
- "Groth16Verifier_AnonNullifierTransferLockedBatch",
81
+ "Groth16Verifier_AnonBatch",
54
82
  (m) => {
55
- const verifier = m.contract("Groth16Verifier_AnonNullifierTransferLockedBatch", []);
83
+ const verifier = m.contract(
84
+ "Groth16Verifier_AnonBatch",
85
+ [],
86
+ );
56
87
  return { verifier };
57
88
  },
58
89
  );
59
90
 
60
- const BurnNullifierVerifierModule = buildModule("Groth16Verifier_BurnNullifier", (m) => {
61
- const verifier = m.contract("Groth16Verifier_BurnNullifier", []);
62
- return { verifier };
63
- });
91
+ const BurnNullifierVerifierModule = buildModule(
92
+ "Groth16Verifier_BurnNullifier",
93
+ (m) => {
94
+ const verifier = m.contract("Groth16Verifier_BurnNullifier", []);
95
+ return { verifier };
96
+ },
97
+ );
64
98
 
65
- const BatchBurnNullifierVerifierModule = buildModule("Groth16Verifier_BurnNullifierBatch", (m) => {
66
- const verifier = m.contract("Groth16Verifier_BurnNullifierBatch", []);
67
- return { verifier };
68
- });
99
+ const BatchBurnNullifierVerifierModule = buildModule(
100
+ "Groth16Verifier_BurnNullifierBatch",
101
+ (m) => {
102
+ const verifier = m.contract("Groth16Verifier_BurnNullifierBatch", []);
103
+ return { verifier };
104
+ },
105
+ );
69
106
 
70
107
  export default buildModule("Zeto_AnonNullifier", (m) => {
108
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
71
109
  const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
72
110
  const { verifier } = m.useModule(VerifierModule);
73
111
  const { verifier: lockVerifier } = m.useModule(LockVerifierModule);
@@ -80,9 +118,7 @@ export default buildModule("Zeto_AnonNullifier", (m) => {
80
118
  const { verifier: batchWithdrawVerifier } = m.useModule(
81
119
  BatchWithdrawNullifierVerifierModule,
82
120
  );
83
- const { verifier: burnVerifier } = m.useModule(
84
- BurnNullifierVerifierModule,
85
- );
121
+ const { verifier: burnVerifier } = m.useModule(BurnNullifierVerifierModule);
86
122
  const { verifier: batchBurnVerifier } = m.useModule(
87
123
  BatchBurnNullifierVerifierModule,
88
124
  );
@@ -100,5 +136,6 @@ export default buildModule("Zeto_AnonNullifier", (m) => {
100
136
  smtLib,
101
137
  poseidon2,
102
138
  poseidon3,
139
+ zetoLockableLib,
103
140
  };
104
141
  });
@@ -17,44 +17,61 @@
17
17
  import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
18
18
  import {
19
19
  SmtLibModule,
20
- DepositVerifierModule,
21
20
  WithdrawNullifierVerifierModule,
22
21
  BatchWithdrawNullifierVerifierModule,
22
+ DepositKycVerifierModule,
23
+ ZetoLockableLibModule,
23
24
  } from "./lib/deps";
24
25
 
25
- const VerifierModule = buildModule("Groth16Verifier_AnonNullifierKycTransfer", (m) => {
26
- const verifier = m.contract("Groth16Verifier_AnonNullifierKycTransfer", []);
27
- return { verifier };
28
- });
26
+ const VerifierModule = buildModule(
27
+ "Groth16Verifier_AnonNullifierKycTransfer",
28
+ (m) => {
29
+ const verifier = m.contract("Groth16Verifier_AnonNullifierKycTransfer", []);
30
+ return { verifier };
31
+ },
32
+ );
29
33
 
30
34
  const BatchVerifierModule = buildModule(
31
35
  "Groth16Verifier_AnonNullifierKycTransferBatch",
32
36
  (m) => {
33
- const verifier = m.contract("Groth16Verifier_AnonNullifierKycTransferBatch", []);
37
+ const verifier = m.contract(
38
+ "Groth16Verifier_AnonNullifierKycTransferBatch",
39
+ [],
40
+ );
34
41
  return { verifier };
35
42
  },
36
43
  );
37
44
 
38
- const LockVerifierModule = buildModule("Groth16Verifier_AnonNullifierKycTransferLocked", (m) => {
39
- const verifier = m.contract("Groth16Verifier_AnonNullifierKycTransferLocked", []);
40
- return { verifier };
41
- });
45
+ const LockVerifierModule = buildModule(
46
+ "Groth16Verifier_AnonNullifierKycTransferLocked",
47
+ (m) => {
48
+ const verifier = m.contract(
49
+ "Groth16Verifier_AnonNullifierKycTransferLocked",
50
+ [],
51
+ );
52
+ return { verifier };
53
+ },
54
+ );
42
55
 
43
56
  const BatchLockVerifierModule = buildModule(
44
57
  "Groth16Verifier_AnonNullifierKycTransferLockedBatch",
45
58
  (m) => {
46
- const verifier = m.contract("Groth16Verifier_AnonNullifierKycTransferLockedBatch", []);
59
+ const verifier = m.contract(
60
+ "Groth16Verifier_AnonNullifierKycTransferLockedBatch",
61
+ [],
62
+ );
47
63
  return { verifier };
48
64
  },
49
65
  );
50
66
 
51
67
  export default buildModule("Zeto_AnonNullifierKyc", (m) => {
68
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
52
69
  const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
53
70
  const { verifier } = m.useModule(VerifierModule);
54
71
  const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
55
72
  const { verifier: lockVerifier } = m.useModule(LockVerifierModule);
56
73
  const { verifier: batchLockVerifier } = m.useModule(BatchLockVerifierModule);
57
- const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
74
+ const { verifier: depositVerifier } = m.useModule(DepositKycVerifierModule);
58
75
  const { verifier: withdrawVerifier } = m.useModule(
59
76
  WithdrawNullifierVerifierModule,
60
77
  );
@@ -73,5 +90,6 @@ export default buildModule("Zeto_AnonNullifierKyc", (m) => {
73
90
  smtLib,
74
91
  poseidon2,
75
92
  poseidon3,
93
+ zetoLockableLib,
76
94
  };
77
95
  });
@@ -20,6 +20,7 @@ import {
20
20
  DepositVerifierModule,
21
21
  WithdrawNullifierVerifierModule,
22
22
  BatchWithdrawNullifierVerifierModule,
23
+ ZetoLockableLibModule,
23
24
  } from "./lib/deps";
24
25
 
25
26
  const VerifierModule = buildModule(
@@ -64,6 +65,7 @@ const BatchVerifierModule = buildModule(
64
65
  // );
65
66
 
66
67
  export default buildModule("Zeto_AnonNullifierQurrency", (m) => {
68
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
67
69
  const { smtLib, poseidon2, poseidon3, poseidon5, poseidon6 } = m.useModule(SmtLibModule);
68
70
  const { verifier } = m.useModule(VerifierModule);
69
71
  // const { verifier: lockVerifier } = m.useModule(LockVerifierModule);
@@ -90,5 +92,6 @@ export default buildModule("Zeto_AnonNullifierQurrency", (m) => {
90
92
  poseidon3,
91
93
  poseidon5,
92
94
  poseidon6,
95
+ zetoLockableLib,
93
96
  };
94
97
  });
@@ -15,13 +15,15 @@
15
15
  // limitations under the License.
16
16
 
17
17
  import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
18
+ import { ZetoLockableLibModule } from "./lib/deps";
18
19
  const VerifierModule = buildModule("Groth16Verifier_NfAnon", (m) => {
19
20
  const verifier = m.contract("Groth16Verifier_NfAnon", []);
20
21
  return { verifier };
21
22
  });
22
23
 
23
24
  export default buildModule("Zeto_NfAnon", (m) => {
25
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
24
26
  const { verifier } = m.useModule(VerifierModule);
25
27
 
26
- return { verifier };
28
+ return { verifier, zetoLockableLib };
27
29
  });
@@ -15,7 +15,7 @@
15
15
  // limitations under the License.
16
16
 
17
17
  import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
18
- import { SmtLibModule } from "./lib/deps";
18
+ import { SmtLibModule, ZetoLockableLibModule } from "./lib/deps";
19
19
 
20
20
  const VerifierModule = buildModule(
21
21
  "Groth16Verifier_NfAnonNullifierTransfer",
@@ -25,21 +25,26 @@ const VerifierModule = buildModule(
25
25
  },
26
26
  );
27
27
 
28
- const LockVerifierModule = buildModule(
29
- "Groth16Verifier_NfAnonNullifierTransferLocked",
30
- (m) => {
31
- const verifier = m.contract(
32
- "Groth16Verifier_NfAnonNullifierTransferLocked",
33
- [],
34
- );
35
- return { verifier };
36
- },
37
- );
28
+ // Locked-input transition for the NF nullifier token reuses the simple
29
+ // {Groth16Verifier_NfAnon} verifier, mirroring how Zeto_AnonNullifier
30
+ // reuses {Groth16Verifier_Anon} for its lock path. In the new
31
+ // {ILockableCapability} architecture the locked-UTXO ledger is a flat
32
+ // mapping (no Merkle tree, no per-UTXO delegate SMT), so the proof for
33
+ // a locked-input spend collapses to the same `[input, output]` shape as
34
+ // the non-nullifier NF transfer. The historical
35
+ // `Groth16Verifier_NfAnonNullifierTransferLocked` (which baked the
36
+ // locked-SMT inclusion + delegate-binding into the proof) is no longer
37
+ // needed and intentionally not deployed.
38
+ const LockVerifierModule = buildModule("Groth16Verifier_NfAnon", (m) => {
39
+ const verifier = m.contract("Groth16Verifier_NfAnon", []);
40
+ return { verifier };
41
+ });
38
42
 
39
43
  export default buildModule("Zeto_NfAnonNullifier", (m) => {
44
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
40
45
  const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
41
46
  const { verifier } = m.useModule(VerifierModule);
42
47
  const { verifier: lockVerifier } = m.useModule(LockVerifierModule);
43
48
 
44
- return { verifier, lockVerifier, smtLib, poseidon2, poseidon3 };
49
+ return { verifier, lockVerifier, smtLib, poseidon2, poseidon3, zetoLockableLib };
45
50
  });
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@lfdecentralizedtrust/zeto-contracts",
3
- "version": "0.2.2",
3
+ "version": "0.5.1",
4
4
  "description": "Zero knowledge proof based UTXO tokens toolkit for fungible or non-fungible assets",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "prettier": "npx prettier contracts scripts ignition test --check",
8
8
  "prettier:fix": "npm run prettier -- --write",
9
9
  "pretest": "npm run prettier:fix",
10
- "test": "npx hardhat test"
10
+ "test": "npx hardhat test",
11
+ "size": "npx hardhat size-contracts"
11
12
  },
12
13
  "keywords": [],
13
14
  "repository": {
@@ -21,13 +22,16 @@
21
22
  "@nomicfoundation/hardhat-ignition-ethers": "^0.15.0",
22
23
  "@nomicfoundation/hardhat-toolbox": "^5.0.0",
23
24
  "circomlibjs": "^0.1.7",
25
+ "hardhat-contract-sizer": "^2.10.1",
24
26
  "maci-crypto": "1.1.1",
27
+ "mlkem": "^2.3.1",
25
28
  "prettier": "^3.3.3",
26
29
  "snarkjs": "0.7.5",
30
+ "tslog": "^4.10.2",
27
31
  "zeto-js": "file:../zkp/js"
28
32
  },
29
33
  "dependencies": {
30
- "@iden3/contracts": "git+https://github.com/kaleido-io/contracts.git#keccak256",
34
+ "@iden3/contracts": "file:../../contracts",
31
35
  "@openzeppelin/contracts": "^5.1.0",
32
36
  "@openzeppelin/contracts-upgradeable": "^5.0.2",
33
37
  "@openzeppelin/hardhat-upgrades": "^3.2.1",
@@ -1,4 +1,11 @@
1
1
  import { ethers, ignition } from "hardhat";
2
+ import { Logger, ILogObj } from "tslog";
3
+ const logLevel = process.env.LOG_LEVEL || "3";
4
+ export const logger: Logger<ILogObj> = new Logger({
5
+ name: "deploy_cloneable",
6
+ minLevel: parseInt(logLevel),
7
+ });
8
+
2
9
  import erc20Module from "../ignition/modules/erc20";
3
10
  import { getLinkedContractFactory, deploy } from "./lib/common";
4
11
 
@@ -17,14 +24,15 @@ export async function deployFungible(tokenName: string) {
17
24
 
18
25
  const zetoImpl: any = await zetoFactory.deploy();
19
26
  await zetoImpl.waitForDeployment();
20
- // console.log(args);
21
- await zetoImpl.connect(deployer).initialize(...args);
22
-
23
- const tx3 = await zetoImpl.connect(deployer).setERC20(erc20.target);
24
- await tx3.wait();
27
+ // Do not call {initialize} or {setERC20} on the implementation. Leaf Zeto
28
+ // contracts lock the impl with {_disableInitializers} in the constructor,
29
+ // so {initialize} here would always revert with {InvalidInitialization}.
30
+ // Factory tests ({ZetoTokenFactory}) deploy ERC1967 proxies whose constructor
31
+ // delegates {initialize} into fresh proxy storage; {deployZeto} then binds
32
+ // ERC20 on each proxy via {setERC20}.
25
33
 
26
- console.log(`ERC20 deployed: ${erc20.target}`);
27
- console.log(`ZetoToken deployed: ${zetoImpl.target}`);
34
+ logger.debug(`ERC20 deployed: ${erc20.target}`);
35
+ logger.debug(`ZetoToken impl deployed: ${zetoImpl.target}`);
28
36
 
29
37
  return { deployer, zetoImpl, erc20, args };
30
38
  }
@@ -42,9 +50,10 @@ export async function deployNonFungible(tokenName: string) {
42
50
  }
43
51
  const zetoImpl: any = await zetoFactory.deploy();
44
52
  await zetoImpl.waitForDeployment();
45
- await zetoImpl.connect(deployer).initialize(...args);
53
+ // Same rationale as {deployFungible}: impl stays uninitialized; proxies
54
+ // created by the factory run {initialize} via ERC1967Proxy constructor data.
46
55
 
47
- console.log(`ZetoToken deployed: ${zetoImpl.target}`);
56
+ logger.debug(`ZetoToken impl deployed: ${zetoImpl.target}`);
48
57
 
49
58
  return { deployer, zetoImpl, args };
50
59
  }
@@ -57,6 +66,6 @@ deploy(deployFungible, deployNonFungible)
57
66
  process.exit(0);
58
67
  })
59
68
  .catch((error) => {
60
- console.error(error);
69
+ logger.error(error);
61
70
  process.exit(1);
62
71
  });
@@ -1,4 +1,8 @@
1
1
  import { ethers, ignition, upgrades } from "hardhat";
2
+ import { Logger, ILogObj } from "tslog";
3
+ const logLevel = process.env.LOG_LEVEL || "3";
4
+ export const logger: Logger<ILogObj> = new Logger({ name: "deploy_upgradeable", minLevel: parseInt(logLevel) });
5
+
2
6
  import erc20Module from "../ignition/modules/erc20";
3
7
  import { getLinkedContractFactory, deploy } from "./lib/common";
4
8
 
@@ -6,13 +10,13 @@ export async function deployFungible(tokenName: string, erc20Address?: string) {
6
10
  let erc20: any;
7
11
  if (!erc20Address) {
8
12
  ({ erc20 } = await ignition.deploy(erc20Module));
9
- console.log(`ERC20 deployed: ${erc20.target}`);
13
+ logger.debug(`ERC20 deployed: ${erc20.target}`);
10
14
  } else {
11
15
  erc20 = await ethers.getContractAt("SampleERC20", erc20Address);
12
16
  if (!erc20) {
13
17
  throw new Error(`ERC20 contract not found at address: ${erc20Address}`);
14
18
  }
15
- console.log(`Using existing ERC20 contract at: ${erc20.target}`);
19
+ logger.debug(`Using existing ERC20 contract at: ${erc20.target}`);
16
20
  }
17
21
  const verifiersDeployer = require(`./tokens/${tokenName}`);
18
22
  const { deployer, args, libraries } =
@@ -39,7 +43,7 @@ export async function deployFungible(tokenName: string, erc20Address?: string) {
39
43
  const tx3 = await zeto.connect(deployer).setERC20(erc20.target);
40
44
  await tx3.wait();
41
45
 
42
- console.log(`ZetoToken deployed: ${zeto.target}`);
46
+ logger.debug(`ZetoToken deployed: ${zeto.target}`);
43
47
 
44
48
  return { deployer, zeto, erc20 };
45
49
  }
@@ -67,7 +71,7 @@ export async function deployNonFungible(tokenName: string) {
67
71
  const zetoAddress = await proxy.getAddress();
68
72
  const zeto: any = await ethers.getContractAt(tokenName, zetoAddress);
69
73
 
70
- console.log(`ZetoToken deployed: ${zeto.target}`);
74
+ logger.debug(`ZetoToken deployed: ${zeto.target}`);
71
75
 
72
76
  return { deployer, zeto };
73
77
  }
@@ -80,6 +84,6 @@ deploy(deployFungible, deployNonFungible)
80
84
  process.exit(0);
81
85
  })
82
86
  .catch((error) => {
83
- console.error(error);
87
+ logger.error(error);
84
88
  process.exit(1);
85
89
  });
@@ -0,0 +1,47 @@
1
+ // Copyright © 2025 Kaleido, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // you may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+
17
+ /** Hardhat library link map for Zeto token implementations. */
18
+ export function withZetoLockableLib(
19
+ zetoLockableLib: { target: string },
20
+ extra: Record<string, string> = {},
21
+ ): Record<string, string> {
22
+ return {
23
+ ZetoLockableLib: zetoLockableLib.target,
24
+ ...extra,
25
+ };
26
+ }
27
+
28
+ export function smtLibraries(deps: {
29
+ smtLib: { target: string };
30
+ poseidon2: { target: string };
31
+ poseidon3: { target: string };
32
+ poseidon5?: { target: string };
33
+ poseidon6?: { target: string };
34
+ }): Record<string, string> {
35
+ const libs: Record<string, string> = {
36
+ SmtLib: deps.smtLib.target,
37
+ PoseidonUnit2L: deps.poseidon2.target,
38
+ PoseidonUnit3L: deps.poseidon3.target,
39
+ };
40
+ if (deps.poseidon5) {
41
+ libs.PoseidonUnit5L = deps.poseidon5.target;
42
+ }
43
+ if (deps.poseidon6) {
44
+ libs.PoseidonUnit6L = deps.poseidon6.target;
45
+ }
46
+ return libs;
47
+ }