@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
@@ -1,340 +0,0 @@
1
- // Copyright © 2024 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 {Commonlib} from "./common.sol";
19
- import {IZeto} from "./interfaces/izeto.sol";
20
- import {MAX_SMT_DEPTH} from "./interfaces/izeto.sol";
21
- import {IZetoLockable} from "./interfaces/izeto_lockable.sol";
22
- import {ZetoCommon} from "./zeto_common.sol";
23
- import {SmtLib} from "@iden3/contracts/contracts/lib/SmtLib.sol";
24
- import {PoseidonHasher} from "@iden3/contracts/contracts/lib/hash/PoseidonHasher.sol";
25
- import {IHasher} from "@iden3/contracts/contracts/interfaces/IHasher.sol";
26
- import {PoseidonUnit3L} from "@iden3/contracts/contracts/lib/Poseidon.sol";
27
- import {console} from "hardhat/console.sol";
28
-
29
- /// @title A sample base implementation of a Zeto based token contract with nullifiers
30
- /// @author Kaleido, Inc.
31
- /// @dev Implements common functionalities of Zeto based tokens using nullifiers
32
- abstract contract ZetoNullifier is IZeto, IZetoLockable, ZetoCommon {
33
- // used for tracking regular (unlocked) UTXOs
34
- SmtLib.Data internal _commitmentsTree;
35
- // used for locked UTXOs tracking. multi-step transaction flows that require counterparties
36
- // to upload proofs. To protect the party that uploads their proof first,
37
- // and prevent any other party from utilizing the uploaded proof to execute
38
- // a transaction, the input UTXOs or nullifiers can be locked and only usable
39
- // by the same party that did the locking.
40
- SmtLib.Data internal _lockedCommitmentsTree;
41
- using SmtLib for SmtLib.Data;
42
- mapping(uint256 => bool) private _nullifiers;
43
- IHasher private _hasher;
44
-
45
- error UTXORootNotFound(uint256 root);
46
-
47
- function __ZetoNullifier_init(
48
- string memory name_,
49
- string memory symbol_,
50
- address initialOwner
51
- ) internal onlyInitializing {
52
- __ZetoCommon_init(name_, symbol_, initialOwner);
53
- _commitmentsTree.initialize(MAX_SMT_DEPTH);
54
- _lockedCommitmentsTree.initialize(MAX_SMT_DEPTH);
55
- _hasher = new PoseidonHasher();
56
- _commitmentsTree.setHasher(_hasher);
57
- _lockedCommitmentsTree.setHasher(_hasher);
58
- }
59
-
60
- function validateTransactionProposal(
61
- uint256[] memory nullifiers,
62
- uint256[] memory outputs,
63
- uint256 root,
64
- bool isLocked
65
- ) internal view returns (bool) {
66
- validateNullifiers(nullifiers);
67
- validateOutputs(outputs);
68
- validateRoot(root, isLocked);
69
-
70
- return true;
71
- }
72
-
73
- function validateNullifiers(
74
- uint256[] memory nullifiers
75
- ) internal view returns (bool) {
76
- // sort the nullifiers to detect duplicates
77
- uint256[] memory sortedInputs = sortCommitments(nullifiers);
78
-
79
- // Check the inputs are all unspent
80
- for (uint256 i = 0; i < sortedInputs.length; ++i) {
81
- if (sortedInputs[i] == 0) {
82
- // skip the zero inputs
83
- continue;
84
- }
85
- if (i > 0 && sortedInputs[i] == sortedInputs[i - 1]) {
86
- revert UTXODuplicate(sortedInputs[i]);
87
- }
88
- if (_nullifiers[sortedInputs[i]] == true) {
89
- revert UTXOAlreadySpent(sortedInputs[i]);
90
- }
91
- }
92
- }
93
-
94
- function validateOutputs(
95
- uint256[] memory outputs
96
- ) internal view returns (bool) {
97
- // sort the outputs to detect duplicates
98
- uint256[] memory sortedOutputs = sortCommitments(outputs);
99
-
100
- // Check the outputs are all new UTXOs
101
- for (uint256 i = 0; i < sortedOutputs.length; ++i) {
102
- if (sortedOutputs[i] == 0) {
103
- // skip the zero outputs
104
- continue;
105
- }
106
- if (i > 0 && sortedOutputs[i] == sortedOutputs[i - 1]) {
107
- revert UTXODuplicate(sortedOutputs[i]);
108
- }
109
- // check the unlocked commitments tree
110
- bool existsInTree = exists(sortedOutputs[i]);
111
- if (existsInTree) {
112
- revert UTXOAlreadyOwned(sortedOutputs[i]);
113
- }
114
- }
115
- }
116
-
117
- function validateRoot(
118
- uint256 root,
119
- bool isLocked
120
- ) internal view returns (bool) {
121
- // Check if the root has existed before. It does not need to be the latest root.
122
- // Our SMT is append-only, so if the root has existed before, and the merklet proof
123
- // is valid, then the leaves still exist in the tree.
124
- if (isLocked && !_lockedCommitmentsTree.rootExists(root)) {
125
- revert UTXORootNotFound(root);
126
- } else if (!isLocked && !_commitmentsTree.rootExists(root)) {
127
- revert UTXORootNotFound(root);
128
- }
129
-
130
- return true;
131
- }
132
-
133
- function processInputsAndOutputs(
134
- uint256[] memory nullifiers,
135
- uint256[] memory outputs,
136
- uint256[] memory lockedOutputs,
137
- address delegate
138
- ) internal {
139
- processNullifiers(nullifiers);
140
- processOutputs(outputs);
141
- processLockedOutputs(lockedOutputs, delegate);
142
- }
143
-
144
- function processNullifiers(uint256[] memory nullifiers) internal {
145
- for (uint256 i = 0; i < nullifiers.length; ++i) {
146
- if (nullifiers[i] != 0) {
147
- _nullifiers[nullifiers[i]] = true;
148
- }
149
- }
150
- }
151
-
152
- function processOutputs(uint256[] memory outputs) internal {
153
- for (uint256 i = 0; i < outputs.length; ++i) {
154
- if (outputs[i] != 0) {
155
- _commitmentsTree.addLeaf(outputs[i], outputs[i]);
156
- }
157
- }
158
- }
159
-
160
- function processLockedOutputs(
161
- uint256[] memory lockedOutputs,
162
- address delegate
163
- ) internal {
164
- for (uint256 i = 0; i < lockedOutputs.length; ++i) {
165
- if (lockedOutputs[i] != 0) {
166
- _lockedCommitmentsTree.addLeaf(
167
- lockedOutputs[i],
168
- uint256(uint160(delegate))
169
- );
170
- }
171
- }
172
- }
173
-
174
- // This function is used to mint new UTXOs, as an example implementation,
175
- // which is only callable by the owner.
176
- function _mint(
177
- uint256[] memory utxos,
178
- bytes calldata data
179
- ) internal virtual {
180
- validateOutputs(utxos);
181
- processOutputs(utxos);
182
- emit UTXOMint(utxos, msg.sender, data);
183
- }
184
-
185
- // This function is used to burn the owner's UTXOs
186
- function _burn(
187
- uint256[] memory nullifiers,
188
- uint256 output,
189
- uint256 root,
190
- bytes calldata data
191
- ) internal virtual {
192
- validateNullifiers(nullifiers);
193
- uint256[] memory outputStates = new uint256[](1);
194
- outputStates[0] = output;
195
- validateOutputs(outputStates);
196
- validateRoot(root, false);
197
-
198
- emit UTXOBurn(nullifiers, output, msg.sender, data);
199
- }
200
-
201
- function getRoot() public view returns (uint256) {
202
- return _commitmentsTree.getRoot();
203
- }
204
-
205
- function getRootForLocked() public view returns (uint256) {
206
- return _lockedCommitmentsTree.getRoot();
207
- }
208
-
209
- // Locks the UTXOs so that they can only be spent by submitting the appropriate
210
- // proof from the Eth account designated as the "delegate". This function
211
- // should be called by escrow contracts that will use uploaded proofs
212
- // to execute transactions, in order to prevent the proof from being used
213
- // by parties other than the escrow contract.
214
- // Assumes that the outputs and locked outputs are already validated to be new UTXOs.
215
- function _lock(
216
- uint256[] memory nullifiers,
217
- uint256[] memory outputs,
218
- uint256[] memory lockedOutputs,
219
- address delegate,
220
- bytes calldata data
221
- ) internal {
222
- for (uint256 i = 0; i < outputs.length; ++i) {
223
- if (outputs[i] == 0) {
224
- // skip the zero outputs
225
- continue;
226
- }
227
- _commitmentsTree.addLeaf(outputs[i], outputs[i]);
228
- }
229
-
230
- // Check the locked outputs are all new UTXOs
231
- for (uint256 i = 0; i < lockedOutputs.length; ++i) {
232
- if (lockedOutputs[i] == 0) {
233
- // skip the zero outputs
234
- continue;
235
- }
236
- _lockedCommitmentsTree.addLeaf(
237
- lockedOutputs[i],
238
- uint256(uint160(delegate))
239
- );
240
- }
241
-
242
- emit UTXOsLocked(
243
- nullifiers,
244
- outputs,
245
- lockedOutputs,
246
- delegate,
247
- msg.sender,
248
- data
249
- );
250
- }
251
-
252
- // move the ability to spend the locked UTXOs to the delegate account.
253
- // The sender must be the current delegate.
254
- function delegateLock(
255
- uint256[] memory utxos,
256
- address delegate,
257
- bytes calldata data
258
- ) public {
259
- for (uint256 i = 0; i < utxos.length; ++i) {
260
- if (utxos[i] == 0) {
261
- continue;
262
- }
263
- bool existsInTree;
264
- address currentDelegate;
265
- (existsInTree, currentDelegate) = existsAsLocked(
266
- utxos[i],
267
- msg.sender
268
- );
269
- if (!existsInTree) {
270
- revert UTXONotLocked(utxos[i]);
271
- }
272
- if (currentDelegate != msg.sender) {
273
- revert NotLockDelegate(utxos[i], delegate, msg.sender);
274
- }
275
- _lockedCommitmentsTree.addLeaf(
276
- utxos[i],
277
- uint256(uint160(delegate))
278
- );
279
- }
280
-
281
- emit LockDelegateChanged(utxos, msg.sender, delegate, data);
282
- }
283
-
284
- function locked(
285
- uint256 utxo,
286
- address delegate
287
- ) public view returns (bool, address) {
288
- return existsAsLocked(utxo, delegate);
289
- }
290
-
291
- function getLeafNodeHash(
292
- uint256 index,
293
- uint256 value
294
- ) internal pure returns (uint256) {
295
- uint256[3] memory params = [index, value, uint256(1)];
296
- return PoseidonUnit3L.poseidon(params);
297
- }
298
-
299
- // check the existence of a UTXO in either the unlocked or locked commitments tree
300
- function exists(uint256 utxo) internal view returns (bool) {
301
- bool existsInTree = everExistedAsUnlocked(utxo);
302
- if (!existsInTree) {
303
- return everExistedAsLocked(utxo);
304
- }
305
- return existsInTree;
306
- }
307
-
308
- // check the existence of a UTXO in the commitments tree. we take a shortcut
309
- // by checking the list of nodes by their node hash, because the commitments
310
- // tree is append-only, no updates or deletions are allowed. As a result, all
311
- // nodes in the list are valid leaf nodes, aka there are no orphaned nodes.
312
- function everExistedAsUnlocked(uint256 utxo) internal view returns (bool) {
313
- uint256 nodeHash = getLeafNodeHash(utxo, utxo);
314
- SmtLib.Node memory node = _commitmentsTree.getNode(nodeHash);
315
- return node.nodeType != SmtLib.NodeType.EMPTY;
316
- }
317
-
318
- // check if an UTXO has ever existed in the locked commitments tree. Because
319
- // this tree allows updates to an existing leaf node, we check the node by its
320
- // merkle proof
321
- function everExistedAsLocked(uint256 utxo) internal view returns (bool) {
322
- SmtLib.Proof memory proof = _lockedCommitmentsTree.getProof(utxo);
323
- return proof.existence;
324
- }
325
-
326
- // check the existence of a locked UTXO in the locked commitments tree. Because
327
- // this tree allows updates to an existing leaf node, we need to check the node
328
- // by its merkle proof, which is built from the current tree and disregards the
329
- // orphaned nodes after updates.
330
- function existsAsLocked(
331
- uint256 utxo,
332
- address delegate
333
- ) internal view returns (bool, address) {
334
- SmtLib.Proof memory proof = _lockedCommitmentsTree.getProof(utxo);
335
- return (
336
- proof.existence && proof.value == uint256(uint160(delegate)),
337
- address(uint160(proof.value))
338
- );
339
- }
340
- }
@@ -1,273 +0,0 @@
1
- // Copyright © 2024 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 {Commonlib} from "./lib/common.sol";
19
- import {Zeto_Anon} from "./zeto_anon.sol";
20
- import {Zeto_NfAnon} from "./zeto_nf_anon.sol";
21
-
22
- /// @title A sample on-chain implementation of a DvP escrow contract using ZKP based C-UTXO tokens
23
- /// @author Kaleido, Inc.
24
- /// @dev Implements escrow based DvP flows with ZKP based C-UTXO tokens
25
- contract zkDvP {
26
- enum TradeStatus {
27
- INITIATED,
28
- ACCEPTED,
29
- COMPLETED,
30
- CANCELLED
31
- }
32
-
33
- struct Trade {
34
- TradeStatus status;
35
- // payment counterparty is the party that initiates the payment transaction
36
- // it does NOT need to be actual owner of the payment UTXOs. The ZK proof of
37
- // the payment transaction will ensure that the payment counterparty is authorized
38
- // to spend the payment UTXOs
39
- address paymentCounterparty;
40
- // inputs for the payment transaction
41
- uint256[2] paymentInputs;
42
- uint256[2] paymentOutputs;
43
- Commonlib.Proof paymentProof;
44
- // asset counterparty is the party that initiates the asset transaction
45
- // it does NOT need to be actual owner of the asset UTXOs. The ZK proof of
46
- // the asset transaction will ensure that the asset counterparty is authorized
47
- // to spend the asset UTXOs
48
- address assetCounterparty;
49
- // inputs for the delivery transaction
50
- uint256 assetInput;
51
- uint256 assetOutput;
52
- Commonlib.Proof assetProof;
53
- }
54
-
55
- Zeto_Anon paymentToken;
56
- Zeto_NfAnon assetToken;
57
- mapping(uint256 => Trade) trades;
58
- uint256 tradeCount;
59
-
60
- event TradeInitiated(uint256 indexed tradeId, Trade trade);
61
- event TradeAccepted(uint256 indexed tradeId, Trade trade);
62
- event TradeCompleted(uint256 indexed tradeId, Trade trade);
63
-
64
- constructor(address paymentTokenAddress, address assetTokenAddress) {
65
- tradeCount = 0;
66
- paymentToken = Zeto_Anon(paymentTokenAddress);
67
- assetToken = Zeto_NfAnon(assetTokenAddress);
68
- }
69
-
70
- function initiateTrade(
71
- uint256[2] memory paymentInputs,
72
- uint256[2] memory paymentOutputs,
73
- bytes32 paymentProofHash,
74
- uint256 assetInput,
75
- uint256 assetOutput,
76
- bytes32 assetProofHash
77
- ) public {
78
- address paymentCounterparty;
79
- address assetCounterparty;
80
- require(
81
- !isEmptyArray(paymentInputs) || assetInput != 0,
82
- "Payment inputs and asset input cannot be zero at the same time"
83
- );
84
- require(
85
- !(!isEmptyArray(paymentInputs) && assetInput != 0),
86
- "Payment inputs and asset input cannot be provided at the same time"
87
- );
88
- if (!isEmptyArray(paymentInputs)) {
89
- require(
90
- !isEmptyArray(paymentOutputs),
91
- "Payment outputs cannot be zero when payment inputs are non-zero"
92
- );
93
- paymentCounterparty = msg.sender;
94
- }
95
- if (assetInput != 0) {
96
- require(
97
- assetOutput != 0,
98
- "Asset output cannot be zero when asset input is non-zero"
99
- );
100
- assetCounterparty = msg.sender;
101
- }
102
-
103
- Commonlib.Proof memory emptyProof;
104
- Trade memory trade = Trade(
105
- TradeStatus.INITIATED,
106
- paymentCounterparty,
107
- paymentInputs,
108
- paymentOutputs,
109
- paymentProofHash,
110
- emptyProof,
111
- assetCounterparty,
112
- assetInput,
113
- assetOutput,
114
- assetProofHash,
115
- emptyProof
116
- );
117
-
118
- trades[tradeCount] = trade;
119
- emit TradeInitiated(tradeCount, trade);
120
- tradeCount++;
121
- }
122
-
123
- function acceptTrade(
124
- uint256 tradeId,
125
- uint256[2] memory paymentInputs,
126
- uint256[2] memory paymentOutputs,
127
- bytes32 paymentProofHash,
128
- uint256 assetInput,
129
- uint256 assetOutput,
130
- bytes32 assetProofHash
131
- ) public {
132
- Trade memory trade = trades[tradeId];
133
- require(
134
- trade.paymentCounterparty != address(0) ||
135
- trade.assetCounterparty != address(0),
136
- "Trade does not exist"
137
- );
138
- require(
139
- trade.status == TradeStatus.INITIATED,
140
- "Trade must be in INITIATED state to accept"
141
- );
142
-
143
- // check that the inputs from the accepting party are complementary
144
- if (!isEmptyArray(trade.paymentInputs)) {
145
- require(
146
- isEmptyArray(paymentInputs),
147
- "Payment inputs already provided by the trade initiator"
148
- );
149
- require(
150
- isEmptyArray(paymentOutputs),
151
- "Payment outputs already provided by the trade initiator"
152
- );
153
- require(
154
- assetInput != 0,
155
- "Asset input must be provided to accept the trade"
156
- );
157
- require(
158
- assetOutput != 0,
159
- "Asset output must be provided to accept the trade"
160
- );
161
-
162
- trade.assetInput = assetInput;
163
- trade.assetOutput = assetOutput;
164
- trade.assetProofHash = assetProofHash;
165
- trade.assetCounterparty = msg.sender;
166
- } else if (trade.assetInput != 0) {
167
- require(
168
- assetInput == 0,
169
- "Asset inputs already provided by the trade initiator"
170
- );
171
- require(
172
- assetOutput == 0,
173
- "Asset outputs already provided by the trade initiator"
174
- );
175
- require(
176
- !isEmptyArray(paymentInputs),
177
- "Payment inputs must be provided to accept the trade"
178
- );
179
- require(
180
- !isEmptyArray(paymentOutputs),
181
- "Payment outputs must be provided to accept the trade"
182
- );
183
-
184
- trade.paymentInputs = paymentInputs;
185
- trade.paymentOutputs = paymentOutputs;
186
- trade.paymentProofHash = paymentProofHash;
187
- trade.paymentCounterparty = msg.sender;
188
- }
189
- trade.status = TradeStatus.ACCEPTED;
190
- trades[tradeId] = trade;
191
-
192
- emit TradeAccepted(tradeId, trade);
193
- }
194
-
195
- function completeTrade(
196
- uint256 tradeId,
197
- Commonlib.Proof calldata proof
198
- ) public {
199
- Trade memory trade = trades[tradeId];
200
- require(
201
- trade.status == TradeStatus.ACCEPTED,
202
- "Trade must be in ACCEPTED state to complete"
203
- );
204
- bytes32 proofHash = Commonlib.getProofHash(proof);
205
- uint256[] memory lockedStates;
206
- if (trade.paymentProofHash == proofHash) {
207
- trade.paymentProof = proof;
208
- lockedStates = new uint256[](trade.paymentInputs.length);
209
- for (uint256 i = 0; i < trade.paymentInputs.length; i++) {
210
- lockedStates[i] = trade.paymentInputs[i];
211
- }
212
- paymentToken.lock(lockedStates, lockProof, address(this), "0x");
213
- } else if (trade.assetProofHash == proofHash) {
214
- trade.assetProof = proof;
215
- lockedStates = new uint256[](1);
216
- lockedStates[0] = trade.assetInput;
217
- assetToken.lockStates(lockedStates, lockProof, address(this), "0x");
218
- } else {
219
- revert("Invalid proof");
220
- }
221
- trades[tradeId] = trade;
222
-
223
- if (
224
- !isEmptyProof(trade.paymentProof) && !isEmptyProof(trade.assetProof)
225
- ) {
226
- uint256[] memory pIns = new uint256[](2);
227
- pIns[0] = trade.paymentInputs[0];
228
- pIns[1] = trade.paymentInputs[1];
229
- uint256[] memory pOuts = new uint256[](2);
230
- pOuts[0] = trade.paymentOutputs[0];
231
- pOuts[1] = trade.paymentOutputs[1];
232
- require(
233
- paymentToken.transfer(pIns, pOuts, trade.paymentProof, ""),
234
- "Payment branch of the trade failed"
235
- );
236
- require(
237
- assetToken.transfer(
238
- trade.assetInput,
239
- trade.assetOutput,
240
- trade.assetProof,
241
- ""
242
- ),
243
- "Asset branch of the trade failed"
244
- );
245
- trade.status = TradeStatus.COMPLETED;
246
- trades[tradeId] = trade;
247
- emit TradeCompleted(tradeId, trade);
248
- }
249
- }
250
-
251
- function isEmptyArray(uint256[2] memory arr) private pure returns (bool) {
252
- if (arr.length == 0) {
253
- return true;
254
- }
255
- for (uint256 i = 0; i < arr.length; i++) {
256
- if (arr[i] != 0) {
257
- return false;
258
- }
259
- }
260
- return true;
261
- }
262
-
263
- function isEmptyProof(
264
- Commonlib.Proof memory proof
265
- ) private pure returns (bool) {
266
- bool isEmpty = ((proof.pA.length == 0 || proof.pA[0] == 0) &&
267
- (proof.pB.length == 0 ||
268
- proof.pB[0].length == 0 ||
269
- proof.pB[0][0] == 0) &&
270
- (proof.pC.length == 0 || proof.pC[0] == 0));
271
- return isEmpty;
272
- }
273
- }