@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/README.md CHANGED
@@ -1,191 +1,99 @@
1
- # Sample Implementations of Zeto base Privacy Preserving Tokens
1
+ # Zeto Solidity contracts
2
2
 
3
- This project contains sample implementations of privacy preserving tokens for both fungible and non-fungible assets, using the Zeto toolkit.
3
+ Privacy-preserving token implementations for fungible and non-fungible assets, built with the Zeto ZK toolkit (Groth16 circuits, UTXO model, optional nullifiers and encryption).
4
4
 
5
- # Prerequisites
5
+ ## Prerequisites
6
6
 
7
- Running the included tests requires Hardhat:
7
+ - Node.js (see repo CI for supported versions).
8
+ - From this directory (`solidity/`), install dependencies:
9
+
10
+ ```console
11
+ npm install
12
+ ```
13
+
14
+ Hardhat and related tooling are pulled in via `@nomicfoundation/hardhat-toolbox`; you do not need to run `hardhat init` in this repository.
15
+
16
+ ### Circuits and proving keys
17
+
18
+ Hardhat tests load circuit WASM via **`zeto-js`** (`file:../zkp/js`). Before running tests:
19
+
20
+ 1. Build **zkp/js** and produce **proving keys** and verification artifacts as described in [`../zkp/js/README.md`](../zkp/js/README.md) (build section).
21
+ 2. Ensure **`zeto-js` unit tests pass** in `zkp/js` before relying on Solidity tests here.
22
+ 3. Set environment variables so tests can find WASM and keys (same layout as CI):
23
+
24
+ - **`CIRCUITS_ROOT`**: directory containing compiled circuit artifacts (e.g. `anon_js/`, `anon_nullifier_transfer_js/`, …).
25
+ - **`PROVING_KEYS_ROOT`**: directory containing the proving key files referenced by the test harness.
26
+
27
+ Example:
8
28
 
9
29
  ```console
10
- npm install --save-dev hardhat
11
- npx hardhat init
30
+ export CIRCUITS_ROOT=/path/to/zeto-artifacts
31
+ export PROVING_KEYS_ROOT=/path/to/zeto-artifacts
32
+ npm test
12
33
  ```
13
34
 
14
- The hardhat test cases make use of the `zeto-js` library, which must be built first. Refer to the steps in [the library's README](/zkp/js/README.md#build) to build the proving keys, and verification keys. Make sure you can successfully run the unit tests for the zeto-js library, before returning back here to continue with the hardhat tests for the Solidity implementation.
35
+ ### `@iden3/contracts` (nullifier / SMT)
36
+
37
+ Tokens that use nullifiers depend on iden3’s Sparse Merkle Tree Solidity library. This workspace expects it at **`../../contracts`** relative to `solidity/` (see `package.json`: `"@iden3/contracts": "file:../../contracts"`).
15
38
 
16
- # Deploy Zeto Token Contracts
39
+ Clone [kaleido-io/contracts](https://github.com/kaleido-io/contracts) (branch **`keccak256`**) next to the **zeto** repo root so the layout is:
40
+
41
+ ```text
42
+ contracts/ # iden3 SMT package (branch keccak256)
43
+ package.json
44
+ ...
45
+ zeto/
46
+ solidity/
47
+ zkp/
48
+ ...
49
+ ```
17
50
 
18
- Zeto token contracts can be deployed to your hardhat test environment as either upgradeable contracts or cloneable contracts with one of the two hardhat scripts:
51
+ Run **`npm install`** in the **`contracts`** checkout so the file dependency resolves.
19
52
 
20
- ## `deploy_upgradeable`
53
+ ## Deploying token contracts
21
54
 
22
- Deploys the target contract, designated by the `ZETO_NAME` environment variable, as a [UUPSUpgradeable contract](https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups). This allows contracts to receive software updates after their initial deployment. For more information about this design pattern, refer to the [OpenZeppelin documentation](https://docs.openzeppelin.com/upgrades-plugins/proxies).
55
+ Scripts deploy the token named by **`ZETO_NAME`** (see `scripts/tokens.json` / Ignition modules for valid names).
56
+
57
+ ### Upgradeable (UUPS proxy)
58
+
59
+ Deploys the implementation plus an ERC1967 proxy and runs `initialize`. Suitable when you want upgradeability via OpenZeppelin’s UUPS pattern.
23
60
 
24
61
  ```console
25
62
  export ZETO_NAME=Zeto_AnonEncNullifier
26
63
  npx hardhat run scripts/deploy_upgradeable.ts
27
64
  ```
28
65
 
29
- ## `deploy_cloneable`
66
+ Background: [Transparent vs UUPS proxies](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-vs-uups), [Upgrades plugin](https://docs.openzeppelin.com/upgrades-plugins/proxies).
30
67
 
31
- Deploys the target contract, designated by the `ZETO_NAME` environment variable, as a [cloneable contract](https://blog.openzeppelin.com/workshop-recap-cheap-contract-deployment-through-clones).
68
+ ### Cloneable / factory workflow
32
69
 
33
70
  ```console
34
71
  export ZETO_NAME=Zeto_AnonEncNullifier
35
72
  npx hardhat run scripts/deploy_cloneable.ts
36
73
  ```
37
74
 
38
- A cloneable contract can cheaply be cloned into separate instances after deployment. Non-cloneable contracts require re-initializing and copying all contract state, which can result in high gas fees. For more information, refer to the [OpenZeppelin documentation](https://docs.openzeppelin.com/contracts/4.x/api/proxy#Clones).
75
+ This deploys the **implementation only**. Leaf tokens lock the impl with `_disableInitializers()`; **`initialize` runs on proxies** created by **`ZetoTokenFactory`**. Tests use **`USE_FACTORY=true`** in `test/lib/deploy.ts` to register the impl and deploy initialized clones. Running the script **by itself** does not yield a ready-to-use initialized token unless you finish that factory flow.
76
+
77
+ For a single initialized deployment without the factory path, use **`deploy_upgradeable.ts`**.
39
78
 
40
- # Run The Hardhat Tests
79
+ Cheap repeat deployments: OpenZeppelin [minimal proxies / Clones](https://docs.openzeppelin.com/contracts/5.x/api/utils#Clones).
41
80
 
42
- Once you have run one of the sample deployment scripts above, you can proceed to run the hardhat tests in this project.
81
+ ## Running tests
43
82
 
44
83
  ```console
45
- npm i
46
- npm t
47
-
48
- > zeto@0.0.1 test
49
- > npx hardhat test
50
-
51
-
52
-
53
- Registry tests
54
- Registry deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3
55
- ✔ should register a new user (43ms)
56
- ✔ should return the correct public key
57
-
58
- Zeto based fungible token with anonymity without encryption or nullifier
59
- Method mint() complete. Gas used: 75301
60
- Witness calculation time: 38ms, Proof generation time: 334ms
61
- Method transfer() complete. Gas used: 336231
62
- ✔ mint to Alice and transfer UTXOs honestly to Bob should succeed (395ms)
63
- Method mint() complete. Gas used: 50947
64
- Witness calculation time: 19ms, Proof generation time: 179ms
65
- Method transfer() complete. Gas used: 336337
66
- ✔ Bob transfers UTXOs, previously received from Alice, honestly to Charlie should succeed (215ms)
67
- ✔ mint existing unspent UTXOs should fail
68
- ✔ mint existing spent UTXOs should fail
69
- Witness calculation time: 20ms, Proof generation time: 178ms
70
- ✔ transfer non-existing UTXOs should fail (207ms)
71
- Witness calculation time: 20ms, Proof generation time: 181ms
72
- ✔ transfer spent UTXOs should fail (double spend protection) (210ms)
73
- Witness calculation time: 19ms, Proof generation time: 193ms
74
- ✔ spend by using the same UTXO as both inputs should fail (222ms)
75
-
76
- Zeto based fungible token with anonymity and encryption
77
- Method mint() complete. Gas used: 75301
78
- Witness calculation time: 52ms, Proof generation time: 359ms
79
- Method transfer() complete. Gas used: 362628
80
- ✔ mint to Alice and transfer UTXOs honestly to Bob should succeed (449ms)
81
- Witness calculation time: 33ms, Proof generation time: 336ms
82
- Method transfer() complete. Gas used: 355662
83
- ✔ Bob transfers UTXOs, previously received from Alice, honestly to Charlie should succeed (383ms)
84
- ✔ mint existing unspent UTXOs should fail
85
- ✔ mint existing spent UTXOs should fail
86
- Witness calculation time: 32ms, Proof generation time: 334ms
87
- ✔ transfer non-existing UTXOs should fail (376ms)
88
- Witness calculation time: 33ms, Proof generation time: 378ms
89
- ✔ transfer spent UTXOs should fail (double spend protection) (421ms)
90
- Method mint() complete. Gas used: 50959
91
- Witness calculation time: 33ms, Proof generation time: 341ms
92
- ✔ spend by using the same UTXO as both inputs should fail (385ms)
93
-
94
- Zeto based fungible token with anonymity using nullifiers and encryption
95
- ✔ onchain SMT root should be equal to the offchain SMT root
96
- Method mint() complete. Gas used: 823254
97
- Witness calculation time: 118ms. Proof generation time: 2288ms.
98
- Time to execute transaction: 40ms. Gas used: 1763072
99
- ✔ mint to Alice and transfer UTXOs honestly to Bob should succeed (2491ms)
100
- Witness calculation time: 80ms. Proof generation time: 2235ms.
101
- Time to execute transaction: 28ms. Gas used: 1677252
102
- ✔ Bob transfers UTXOs, previously received from Alice, honestly to Charlie should succeed (2351ms)
103
- ✔ mint existing unspent UTXOs should fail
104
- ✔ mint existing spent UTXOs should fail
105
- Witness calculation time: 77ms. Proof generation time: 2345ms.
106
- ✔ transfer spent UTXOs should fail (double spend protection) (2435ms)
107
- Method mint() complete. Gas used: 878936
108
- Witness calculation time: 78ms. Proof generation time: 2248ms.
109
- ✔ transfer with existing UTXOs in the output should fail (mass conservation protection) (2362ms)
110
- Witness calculation time: 77ms. Proof generation time: 2292ms.
111
- ✔ spend by using the same UTXO as both inputs should fail (2381ms)
112
- Witness calculation time: 78ms. Proof generation time: 2324ms.
113
- ✔ transfer non-existing UTXOs should fail (2454ms)
114
-
115
- Zeto based fungible token with anonymity using nullifiers without encryption
116
- ✔ onchain SMT root should be equal to the offchain SMT root
117
- Method mint() complete. Gas used: 906173
118
- Witness calculation time: 105ms. Proof generation time: 2151ms.
119
- Time to execute transaction: 30ms. Gas used: 1737824
120
- ✔ mint to Alice and transfer UTXOs honestly to Bob should succeed (2312ms)
121
- Witness calculation time: 63ms. Proof generation time: 2137ms.
122
- Time to execute transaction: 33ms. Gas used: 2025451
123
- ✔ Bob transfers UTXOs, previously received from Alice, honestly to Charlie should succeed (2245ms)
124
- ✔ mint existing unspent UTXOs should fail
125
- ✔ mint existing spent UTXOs should fail
126
- Witness calculation time: 64ms. Proof generation time: 2181ms.
127
- ✔ transfer spent UTXOs should fail (double spend protection) (2256ms)
128
- Method mint() complete. Gas used: 941948
129
- Witness calculation time: 64ms. Proof generation time: 2171ms.
130
- ✔ transfer with existing UTXOs in the output should fail (mass conservation protection) (2272ms)
131
- Witness calculation time: 64ms. Proof generation time: 2128ms.
132
- ✔ spend by using the same UTXO as both inputs should fail (2202ms)
133
- Witness calculation time: 63ms. Proof generation time: 2183ms.
134
- ✔ transfer non-existing UTXOs should fail (2294ms)
135
-
136
- Zeto based non-fungible token with anonymity without encryption or nullifiers
137
- Method mint() complete. Gas used: 50959
138
- Witness calculation time: 39ms, Proof generation time: 116ms
139
- Method transfer() complete. Gas used: 288112
140
- ✔ mint to Alice and transfer UTXOs honestly to Bob should succeed (170ms)
141
- Witness calculation time: 19ms, Proof generation time: 120ms
142
- Method transfer() complete. Gas used: 288136
143
- ✔ Bob transfers UTXOs, previously received from Alice, honestly to Charlie should succeed (152ms)
144
- ✔ mint existing unspent UTXOs should fail
145
- ✔ mint existing spent UTXOs should fail
146
- Witness calculation time: 19ms, Proof generation time: 150ms
147
- ✔ transfer non-existing UTXOs should fail (179ms)
148
- Witness calculation time: 18ms, Proof generation time: 115ms
149
- ✔ transfer spent UTXOs should fail (double spend protection) (141ms)
150
-
151
- Zeto based non-fungible token with anonymity using nullifiers without encryption
152
- ✔ onchain SMT root should be equal to the offchain SMT root
153
- Method mint() complete. Gas used: 338260
154
- Witness calculation time: 84ms. Proof generation time: 1137ms.
155
- Time to execute transaction: 17ms. Gas used: 796127
156
- ✔ mint to Alice and transfer UTXOs honestly to Bob should succeed (1250ms)
157
- Witness calculation time: 46ms. Proof generation time: 1172ms.
158
- Time to execute transaction: 19ms. Gas used: 909983
159
- ✔ Bob transfers UTXOs, previously received from Alice, honestly to Charlie should succeed (1243ms)
160
- ✔ mint existing unspent UTXOs should fail
161
- ✔ mint existing spent UTXOs should fail
162
- Witness calculation time: 41ms. Proof generation time: 1146ms.
163
- ✔ transfer spent UTXOs should fail (double spend protection) (1196ms)
164
- Witness calculation time: 38ms. Proof generation time: 1163ms.
165
- ✔ transfer non-existing UTXOs should fail (1229ms)
166
-
167
- DvP flows between fungible and non-fungible tokens based on Zeto with anonymity without encryption or nullifiers
168
- ZK Asset contract deployed at 0xf4B146FbA71F41E0592668ffbF264F1D186b2Ca8
169
- ZK Payment contract deployed at 0xBEc49fA140aCaA83533fB00A2BB19bDdd0290f25
170
- Method mint() complete. Gas used: 75289
171
- ✔ mint to Alice some payment tokens
172
- Method mint() complete. Gas used: 75277
173
- ✔ mint to Bob some asset tokens
174
- ✔ Initiating a DvP transaction without payment input or asset input should fail
175
- ✔ Initiating a DvP transaction with payment input but no payment output should fail
176
- ✔ Initiating a DvP transaction with payment inputs and asset inputs should fail
177
- ✔ Initiating a DvP transaction with asset input but no asset output should fail
178
- ✔ Initiating a successful DvP transaction with payment inputs
179
- ✔ Initiating a successful DvP transaction with asset inputs
180
- ✔ Accepting a trade using an invalid trade ID should fail
181
- ✔ Failing cases for accepting a trade with payment terms
182
- ✔ Failing cases for accepting a trade with asset terms
183
- Method mint() complete. Gas used: 50959
184
- Method mint() complete. Gas used: 50959
185
- Witness calculation time: 36ms, Proof generation time: 183ms
186
- Witness calculation time: 38ms, Proof generation time: 121ms
187
- ✔ Initiating a successful DvP transaction with payment inputs and accepting by specifying asset inputs (421ms)
188
-
189
-
190
- 59 passing (41s)
84
+ npm install
85
+ npm test
191
86
  ```
87
+
88
+ `pretest` runs Prettier on `contracts`, `scripts`, `ignition`, and `test`; fix formatting or run `npm run prettier:fix` if the check fails.
89
+
90
+ Optional:
91
+
92
+ - **`USE_FACTORY=true`**: exercise the factory deployment path (cloneable impl + `ZetoTokenFactory`) in addition to the default upgradeable path when relevant tests support it.
93
+
94
+ Successful runs exercise mint/transfer/withdraw flows, nullifier trees, registry helpers, DvP samples, and gas-heavy suites depending on which circuits and keys are present.
95
+
96
+ ## Further reading
97
+
98
+ - Token variants and feature matrix: [`doc-site/docs/implementations/`](../doc-site/docs/implementations/) (repository root).
99
+ - Circuit sources: [`../zkp/circuits/`](../zkp/circuits/).
@@ -15,9 +15,9 @@
15
15
  // limitations under the License.
16
16
  pragma solidity ^0.8.27;
17
17
 
18
- import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
19
18
  import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
20
- import {IZetoInitializable} from "./lib/interfaces/izeto_initializable.sol";
19
+ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
20
+ import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
21
21
 
22
22
  contract ZetoTokenFactory is Ownable {
23
23
  // all the addresses needed by the factory to
@@ -36,7 +36,7 @@ contract ZetoTokenFactory is Ownable {
36
36
  constructor() Ownable(msg.sender) {}
37
37
 
38
38
  function registerImplementation(
39
- string memory name,
39
+ string calldata name,
40
40
  ImplementationInfo memory implementation
41
41
  ) public onlyOwner {
42
42
  require(
@@ -44,7 +44,7 @@ contract ZetoTokenFactory is Ownable {
44
44
  "Factory: implementation address is required"
45
45
  );
46
46
  require(
47
- implementation.verifiers.verifier != address(0),
47
+ address(implementation.verifiers.verifier) != address(0),
48
48
  "Factory: verifier address is required"
49
49
  );
50
50
  // the depositVerifier and withdrawVerifier are optional
@@ -53,9 +53,9 @@ contract ZetoTokenFactory is Ownable {
53
53
  }
54
54
 
55
55
  function deployZetoFungibleToken(
56
- string memory name,
57
- string memory symbol,
58
- string memory tokenImplementation,
56
+ string calldata name,
57
+ string calldata symbol,
58
+ string calldata tokenImplementation,
59
59
  address initialOwner
60
60
  ) public returns (address) {
61
61
  ImplementationInfo memory args = implementations[tokenImplementation];
@@ -66,40 +66,38 @@ contract ZetoTokenFactory is Ownable {
66
66
  // check that the registered implementation is for a fungible token
67
67
  // and has the required verifier addresses
68
68
  require(
69
- args.verifiers.depositVerifier != address(0),
69
+ address(args.verifiers.depositVerifier) != address(0),
70
70
  "Factory: depositVerifier address is required"
71
71
  );
72
72
  require(
73
- args.verifiers.withdrawVerifier != address(0),
73
+ address(args.verifiers.withdrawVerifier) != address(0),
74
74
  "Factory: withdrawVerifier address is required"
75
75
  );
76
76
  require(
77
- args.verifiers.batchVerifier != address(0),
77
+ address(args.verifiers.batchVerifier) != address(0),
78
78
  "Factory: batchVerifier address is required"
79
79
  );
80
80
  require(
81
- args.verifiers.batchWithdrawVerifier != address(0),
81
+ address(args.verifiers.batchWithdrawVerifier) != address(0),
82
82
  "Factory: batchWithdrawVerifier address is required"
83
83
  );
84
- address instance = Clones.clone(args.implementation);
85
- require(
86
- instance != address(0),
87
- "Factory: failed to clone implementation"
88
- );
89
- (IZetoInitializable(instance)).initialize(
90
- name,
91
- symbol,
92
- initialOwner,
93
- args.verifiers
84
+ address instance = address(
85
+ new ERC1967Proxy(
86
+ args.implementation,
87
+ abi.encodeCall(
88
+ IZetoInitializable.initialize,
89
+ (name, symbol, initialOwner, args.verifiers)
90
+ )
91
+ )
94
92
  );
95
93
  emit ZetoTokenDeployed(instance);
96
94
  return instance;
97
95
  }
98
96
 
99
97
  function deployZetoNonFungibleToken(
100
- string memory name,
101
- string memory symbol,
102
- string memory tokenImplementation,
98
+ string calldata name,
99
+ string calldata symbol,
100
+ string calldata tokenImplementation,
103
101
  address initialOwner
104
102
  ) public returns (address) {
105
103
  ImplementationInfo memory args = implementations[tokenImplementation];
@@ -107,16 +105,14 @@ contract ZetoTokenFactory is Ownable {
107
105
  args.implementation != address(0),
108
106
  "Factory: failed to find implementation"
109
107
  );
110
- address instance = Clones.clone(args.implementation);
111
- require(
112
- instance != address(0),
113
- "Factory: failed to clone implementation"
114
- );
115
- (IZetoInitializable(instance)).initialize(
116
- name,
117
- symbol,
118
- initialOwner,
119
- args.verifiers
108
+ address instance = address(
109
+ new ERC1967Proxy(
110
+ args.implementation,
111
+ abi.encodeCall(
112
+ IZetoInitializable.initialize,
113
+ (name, symbol, initialOwner, args.verifiers)
114
+ )
115
+ )
120
116
  );
121
117
  emit ZetoTokenDeployed(instance);
122
118
  return instance;
@@ -19,9 +19,13 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini
19
19
  import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
20
20
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
21
21
  import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
22
- import {IZetoInitializable} from "./lib/interfaces/izeto_initializable.sol";
22
+ import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
23
23
 
24
- contract ZetoTokenFactoryUpgradeable is Initializable, OwnableUpgradeable, UUPSUpgradeable {
24
+ contract ZetoTokenFactoryUpgradeable is
25
+ Initializable,
26
+ OwnableUpgradeable,
27
+ UUPSUpgradeable
28
+ {
25
29
  // all the addresses needed by the factory to
26
30
  // clone a Zeto token and initialize it. The
27
31
  // "implementation" is used to clone the token,
@@ -71,7 +75,7 @@ contract ZetoTokenFactoryUpgradeable is Initializable, OwnableUpgradeable, UUPSU
71
75
  "Factory: implementation address is required"
72
76
  );
73
77
  require(
74
- implementation.verifiers.verifier != address(0),
78
+ address(implementation.verifiers.verifier) != address(0),
75
79
  "Factory: verifier address is required"
76
80
  );
77
81
  // the depositVerifier and withdrawVerifier are optional
@@ -95,19 +99,19 @@ contract ZetoTokenFactoryUpgradeable is Initializable, OwnableUpgradeable, UUPSU
95
99
  // check that the registered implementation is for a fungible token
96
100
  // and has the required verifier addresses
97
101
  require(
98
- args.verifiers.depositVerifier != address(0),
102
+ address(args.verifiers.depositVerifier) != address(0),
99
103
  "Factory: depositVerifier address is required"
100
104
  );
101
105
  require(
102
- args.verifiers.withdrawVerifier != address(0),
106
+ address(args.verifiers.withdrawVerifier) != address(0),
103
107
  "Factory: withdrawVerifier address is required"
104
108
  );
105
109
  require(
106
- args.verifiers.batchVerifier != address(0),
110
+ address(args.verifiers.batchVerifier) != address(0),
107
111
  "Factory: batchVerifier address is required"
108
112
  );
109
113
  require(
110
- args.verifiers.batchWithdrawVerifier != address(0),
114
+ address(args.verifiers.batchWithdrawVerifier) != address(0),
111
115
  "Factory: batchWithdrawVerifier address is required"
112
116
  );
113
117
  address instance = Clones.clone(args.implementation);
@@ -0,0 +1,40 @@
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
+ pragma solidity ^0.8.27;
17
+
18
+ import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol";
19
+ import {PoseidonUnit3L} from "@iden3/contracts/contracts/lib/Poseidon.sol";
20
+
21
+ library Util {
22
+ function sortCommitments(
23
+ uint256[] memory utxos
24
+ ) internal pure returns (uint256[] memory) {
25
+ uint256[] memory sorted = new uint256[](utxos.length);
26
+ for (uint256 i = 0; i < utxos.length; ++i) {
27
+ sorted[i] = utxos[i];
28
+ }
29
+ sorted = Arrays.sort(sorted);
30
+ return sorted;
31
+ }
32
+
33
+ function getLeafNodeHash(
34
+ uint256 index,
35
+ uint256 value
36
+ ) internal pure returns (uint256) {
37
+ uint256[3] memory params = [index, value, uint256(1)];
38
+ return PoseidonUnit3L.poseidon(params);
39
+ }
40
+ }