@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
package/README.md CHANGED
@@ -1,191 +1,105 @@
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
+ ### Contract size (EIP-170)
17
+
18
+ Mainnet limits deployed bytecode to **24,576 bytes**. This repo enforces that on the Hardhat network and at compile time via `hardhat-contract-sizer`. Run `npm run size` to print sizes after compile.
19
+
20
+ ### Circuits and proving keys
21
+
22
+ Hardhat tests load circuit WASM via **`zeto-js`** (`file:../zkp/js`). Before running tests:
23
+
24
+ 1. Build **zkp/js** and produce **proving keys** and verification artifacts as described in [`../zkp/js/README.md`](../zkp/js/README.md) (build section).
25
+ 2. Ensure **`zeto-js` unit tests pass** in `zkp/js` before relying on Solidity tests here.
26
+ 3. Set environment variables so tests can find WASM and keys (same layout as CI):
27
+
28
+ - **`CIRCUITS_ROOT`**: directory containing compiled circuit artifacts (e.g. `anon_js/`, `anon_nullifier_transfer_js/`, …).
29
+ - **`PROVING_KEYS_ROOT`**: directory containing the proving key files referenced by the test harness.
30
+
31
+ Example:
8
32
 
9
33
  ```console
10
- npm install --save-dev hardhat
11
- npx hardhat init
34
+ export CIRCUITS_ROOT=/path/to/zeto-artifacts
35
+ export PROVING_KEYS_ROOT=/path/to/zeto-artifacts
36
+ npm test
37
+ ```
38
+
39
+ ### `@iden3/contracts` (nullifier / SMT)
40
+
41
+ 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"`).
42
+
43
+ Clone [kaleido-io/contracts](https://github.com/kaleido-io/contracts) (branch **`keccak256`**) next to the **zeto** repo root so the layout is:
44
+
45
+ ```text
46
+ contracts/ # iden3 SMT package (branch keccak256)
47
+ package.json
48
+ ...
49
+ zeto/
50
+ solidity/
51
+ zkp/
52
+ ...
12
53
  ```
13
54
 
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.
55
+ Run **`npm install`** in the **`contracts`** checkout so the file dependency resolves.
15
56
 
16
- # Deploy Zeto Token Contracts
57
+ ## Deploying token contracts
17
58
 
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:
59
+ Scripts deploy the token named by **`ZETO_NAME`** (see `scripts/tokens.json` / Ignition modules for valid names).
19
60
 
20
- ## `deploy_upgradeable`
61
+ ### Upgradeable (UUPS proxy)
21
62
 
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).
63
+ Deploys the implementation plus an ERC1967 proxy and runs `initialize`. Suitable when you want upgradeability via OpenZeppelin’s UUPS pattern.
23
64
 
24
65
  ```console
25
66
  export ZETO_NAME=Zeto_AnonEncNullifier
26
67
  npx hardhat run scripts/deploy_upgradeable.ts
27
68
  ```
28
69
 
29
- ## `deploy_cloneable`
70
+ 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
71
 
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).
72
+ ### Cloneable / factory workflow
32
73
 
33
74
  ```console
34
75
  export ZETO_NAME=Zeto_AnonEncNullifier
35
76
  npx hardhat run scripts/deploy_cloneable.ts
36
77
  ```
37
78
 
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).
79
+ 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.
39
80
 
40
- # Run The Hardhat Tests
81
+ Every token implementation links the external **`ZetoLockableLib`** library (deployed once per chain via Ignition). Token deploy scripts in `scripts/tokens/` pass it in the `libraries` map alongside `SmtLib` / Poseidon where applicable.
41
82
 
42
- Once you have run one of the sample deployment scripts above, you can proceed to run the hardhat tests in this project.
83
+ For a single initialized deployment without the factory path, use **`deploy_upgradeable.ts`**.
84
+
85
+ Cheap repeat deployments: OpenZeppelin [minimal proxies / Clones](https://docs.openzeppelin.com/contracts/5.x/api/utils#Clones).
86
+
87
+ ## Running tests
43
88
 
44
89
  ```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)
90
+ npm install
91
+ npm test
191
92
  ```
93
+
94
+ `pretest` runs Prettier on `contracts`, `scripts`, `ignition`, and `test`; fix formatting or run `npm run prettier:fix` if the check fails.
95
+
96
+ Optional:
97
+
98
+ - **`USE_FACTORY=true`**: exercise the factory deployment path (cloneable impl + `ZetoTokenFactory`) in addition to the default upgradeable path when relevant tests support it.
99
+
100
+ 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.
101
+
102
+ ## Further reading
103
+
104
+ - Token variants and feature matrix: [`doc-site/docs/implementations/`](../doc-site/docs/implementations/) (repository root).
105
+ - Circuit sources: [`../zkp/circuits/`](../zkp/circuits/).
@@ -0,0 +1,30 @@
1
+ /**
2
+ * EIP-170 (Spurious Dragon) maximum deployed runtime bytecode size.
3
+ * @see https://eips.ethereum.org/EIPS/eip-170
4
+ */
5
+ export const EIP170_BYTE_LIMIT = 24_576;
6
+
7
+ /**
8
+ * Contracts that currently exceed EIP170_BYTE_LIMIT with the compiler settings
9
+ * in hardhat.config.ts. Exempt from `hardhat-contract-sizer` strict checks
10
+ * until further library splits land.
11
+ *
12
+ * Remove names from this list as implementations are brought under the limit.
13
+ */
14
+ export const EIP170_EXEMPT_CONTRACTS: readonly string[] = [
15
+ "Zeto_AnonEncNullifier",
16
+ "Zeto_AnonEncNullifierKyc",
17
+ "Zeto_AnonEncNullifierNonRepudiation",
18
+ "Zeto_AnonNullifierBurnable",
19
+ "Zeto_AnonNullifierQurrency",
20
+ "Groth16Verifier_AnonEncNullifierNonRepudiationBatch",
21
+ ] as const;
22
+
23
+ export const EIP170_EXEMPT_CONTRACTS_SET = new Set<string>(
24
+ EIP170_EXEMPT_CONTRACTS,
25
+ );
26
+
27
+ /** Token implementations in the exemption list (excludes standalone verifiers). */
28
+ export const EIP170_EXEMPT_TOKEN_SET = new Set<string>(
29
+ EIP170_EXEMPT_CONTRACTS.filter((name) => name.startsWith("Zeto_")),
30
+ );
@@ -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
+ }