@lfdecentralizedtrust/zeto-contracts 0.2.1 → 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 (155) hide show
  1. package/README.md +70 -162
  2. package/contracts/factory.sol +30 -34
  3. package/contracts/factory_upgradeable.sol +160 -0
  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 +77 -27
  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 +8 -3
  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 +218 -360
  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 +9 -6
  104. package/ignition/modules/zeto_anon_burnable.ts +8 -7
  105. package/ignition/modules/zeto_anon_enc_nullifier.ts +33 -1
  106. package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +2 -2
  107. package/ignition/modules/zeto_anon_enc_nullifier_non_repudiation.ts +2 -1
  108. package/ignition/modules/zeto_anon_nullifier.ts +30 -5
  109. package/ignition/modules/zeto_anon_nullifier_burnable.ts +52 -17
  110. package/ignition/modules/zeto_anon_nullifier_kyc.ts +27 -12
  111. package/ignition/modules/zeto_anon_nullifier_qurrency.ts +2 -1
  112. package/ignition/modules/zeto_nf_anon_nullifier.ts +16 -12
  113. package/package.json +4 -2
  114. package/scripts/deploy_cloneable.ts +19 -10
  115. package/scripts/deploy_upgradeable.ts +9 -5
  116. package/scripts/tokens/Zeto_Anon.ts +3 -3
  117. package/scripts/tokens/Zeto_AnonBurnable.ts +1 -1
  118. package/scripts/tokens/Zeto_AnonEnc.ts +12 -3
  119. package/scripts/tokens/Zeto_AnonEncNullifier.ts +7 -3
  120. package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +1 -1
  121. package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +3 -1
  122. package/scripts/tokens/Zeto_AnonNullifier.ts +3 -1
  123. package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +3 -1
  124. package/scripts/tokens/Zeto_AnonNullifierKyc.ts +1 -1
  125. package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +3 -1
  126. package/scripts/tokens/Zeto_NfAnon.ts +2 -2
  127. package/scripts/tokens/Zeto_NfAnonNullifier.ts +3 -2
  128. package/test/factory.ts +46 -73
  129. package/test/factory_upgradeable.ts +311 -0
  130. package/test/lib/anon_nullifier_helpers.ts +89 -0
  131. package/test/lib/anon_zeto_helpers.ts +76 -0
  132. package/test/lib/deploy.ts +3 -2
  133. package/test/lib/utils.ts +74 -35
  134. package/test/test/escrow1.ts +185 -58
  135. package/test/test/escrow2.ts +200 -107
  136. package/test/test/qurrency.ts +13 -33
  137. package/test/usdc-shielding.ts +39 -26
  138. package/test/utils.ts +144 -21
  139. package/test/zeto_anon.ts +956 -465
  140. package/test/zeto_anon_enc.ts +881 -142
  141. package/test/zeto_anon_enc_nullifier.ts +847 -38
  142. package/test/zeto_anon_enc_nullifier_kyc.ts +120 -181
  143. package/test/zeto_anon_enc_nullifier_non_repudiation.ts +77 -46
  144. package/test/zeto_anon_nullifier.ts +1212 -953
  145. package/test/zeto_anon_nullifier_kyc.ts +674 -655
  146. package/test/zeto_anon_nullifier_qurrency.ts +452 -306
  147. package/test/zeto_nf_anon.ts +737 -137
  148. package/test/zeto_nf_anon_nullifier.ts +876 -246
  149. package/contracts/lib/zeto_base.sol +0 -293
  150. package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
  151. package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
  152. package/contracts/lib/zeto_nullifier.sol +0 -334
  153. package/contracts/zkDvP.sol_ +0 -273
  154. package/test/zkDvP.ts_ +0 -455
  155. /package/contracts/lib/{common.sol → common/common.sol} +0 -0
@@ -1,334 +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/lib/SmtLib.sol";
24
- import {PoseidonUnit3L} from "@iden3/contracts/lib/Poseidon.sol";
25
- import {console} from "hardhat/console.sol";
26
-
27
- /// @title A sample base implementation of a Zeto based token contract with nullifiers
28
- /// @author Kaleido, Inc.
29
- /// @dev Implements common functionalities of Zeto based tokens using nullifiers
30
- abstract contract ZetoNullifier is IZeto, IZetoLockable, ZetoCommon {
31
- // used for tracking regular (unlocked) UTXOs
32
- SmtLib.Data internal _commitmentsTree;
33
- // used for locked UTXOs tracking. multi-step transaction flows that require counterparties
34
- // to upload proofs. To protect the party that uploads their proof first,
35
- // and prevent any other party from utilizing the uploaded proof to execute
36
- // a transaction, the input UTXOs or nullifiers can be locked and only usable
37
- // by the same party that did the locking.
38
- SmtLib.Data internal _lockedCommitmentsTree;
39
- using SmtLib for SmtLib.Data;
40
- mapping(uint256 => bool) private _nullifiers;
41
-
42
- error UTXORootNotFound(uint256 root);
43
-
44
- function __ZetoNullifier_init(
45
- string memory name_,
46
- string memory symbol_,
47
- address initialOwner
48
- ) internal onlyInitializing {
49
- __ZetoCommon_init(name_, symbol_, initialOwner);
50
- _commitmentsTree.initialize(MAX_SMT_DEPTH);
51
- _lockedCommitmentsTree.initialize(MAX_SMT_DEPTH);
52
- }
53
-
54
- function validateTransactionProposal(
55
- uint256[] memory nullifiers,
56
- uint256[] memory outputs,
57
- uint256 root,
58
- bool isLocked
59
- ) internal view returns (bool) {
60
- validateNullifiers(nullifiers);
61
- validateOutputs(outputs);
62
- validateRoot(root, isLocked);
63
-
64
- return true;
65
- }
66
-
67
- function validateNullifiers(
68
- uint256[] memory nullifiers
69
- ) internal view returns (bool) {
70
- // sort the nullifiers to detect duplicates
71
- uint256[] memory sortedInputs = sortCommitments(nullifiers);
72
-
73
- // Check the inputs are all unspent
74
- for (uint256 i = 0; i < sortedInputs.length; ++i) {
75
- if (sortedInputs[i] == 0) {
76
- // skip the zero inputs
77
- continue;
78
- }
79
- if (i > 0 && sortedInputs[i] == sortedInputs[i - 1]) {
80
- revert UTXODuplicate(sortedInputs[i]);
81
- }
82
- if (_nullifiers[sortedInputs[i]] == true) {
83
- revert UTXOAlreadySpent(sortedInputs[i]);
84
- }
85
- }
86
- }
87
-
88
- function validateOutputs(
89
- uint256[] memory outputs
90
- ) internal view returns (bool) {
91
- // sort the outputs to detect duplicates
92
- uint256[] memory sortedOutputs = sortCommitments(outputs);
93
-
94
- // Check the outputs are all new UTXOs
95
- for (uint256 i = 0; i < sortedOutputs.length; ++i) {
96
- if (sortedOutputs[i] == 0) {
97
- // skip the zero outputs
98
- continue;
99
- }
100
- if (i > 0 && sortedOutputs[i] == sortedOutputs[i - 1]) {
101
- revert UTXODuplicate(sortedOutputs[i]);
102
- }
103
- // check the unlocked commitments tree
104
- bool existsInTree = exists(sortedOutputs[i]);
105
- if (existsInTree) {
106
- revert UTXOAlreadyOwned(sortedOutputs[i]);
107
- }
108
- }
109
- }
110
-
111
- function validateRoot(
112
- uint256 root,
113
- bool isLocked
114
- ) internal view returns (bool) {
115
- // Check if the root has existed before. It does not need to be the latest root.
116
- // Our SMT is append-only, so if the root has existed before, and the merklet proof
117
- // is valid, then the leaves still exist in the tree.
118
- if (isLocked && !_lockedCommitmentsTree.rootExists(root)) {
119
- revert UTXORootNotFound(root);
120
- } else if (!isLocked && !_commitmentsTree.rootExists(root)) {
121
- revert UTXORootNotFound(root);
122
- }
123
-
124
- return true;
125
- }
126
-
127
- function processInputsAndOutputs(
128
- uint256[] memory nullifiers,
129
- uint256[] memory outputs,
130
- uint256[] memory lockedOutputs,
131
- address delegate
132
- ) internal {
133
- processNullifiers(nullifiers);
134
- processOutputs(outputs);
135
- processLockedOutputs(lockedOutputs, delegate);
136
- }
137
-
138
- function processNullifiers(uint256[] memory nullifiers) internal {
139
- for (uint256 i = 0; i < nullifiers.length; ++i) {
140
- if (nullifiers[i] != 0) {
141
- _nullifiers[nullifiers[i]] = true;
142
- }
143
- }
144
- }
145
-
146
- function processOutputs(uint256[] memory outputs) internal {
147
- for (uint256 i = 0; i < outputs.length; ++i) {
148
- if (outputs[i] != 0) {
149
- _commitmentsTree.addLeaf(outputs[i], outputs[i]);
150
- }
151
- }
152
- }
153
-
154
- function processLockedOutputs(
155
- uint256[] memory lockedOutputs,
156
- address delegate
157
- ) internal {
158
- for (uint256 i = 0; i < lockedOutputs.length; ++i) {
159
- if (lockedOutputs[i] != 0) {
160
- _lockedCommitmentsTree.addLeaf(
161
- lockedOutputs[i],
162
- uint256(uint160(delegate))
163
- );
164
- }
165
- }
166
- }
167
-
168
- // This function is used to mint new UTXOs, as an example implementation,
169
- // which is only callable by the owner.
170
- function _mint(
171
- uint256[] memory utxos,
172
- bytes calldata data
173
- ) internal virtual {
174
- validateOutputs(utxos);
175
- processOutputs(utxos);
176
- emit UTXOMint(utxos, msg.sender, data);
177
- }
178
-
179
- // This function is used to burn the owner's UTXOs
180
- function _burn(
181
- uint256[] memory nullifiers,
182
- uint256 output,
183
- uint256 root,
184
- bytes calldata data
185
- ) internal virtual {
186
- validateNullifiers(nullifiers);
187
- uint256[] memory outputStates = new uint256[](1);
188
- outputStates[0] = output;
189
- validateOutputs(outputStates);
190
- validateRoot(root, false);
191
-
192
- emit UTXOBurn(nullifiers, output, msg.sender, data);
193
- }
194
-
195
- function getRoot() public view returns (uint256) {
196
- return _commitmentsTree.getRoot();
197
- }
198
-
199
- function getRootForLocked() public view returns (uint256) {
200
- return _lockedCommitmentsTree.getRoot();
201
- }
202
-
203
- // Locks the UTXOs so that they can only be spent by submitting the appropriate
204
- // proof from the Eth account designated as the "delegate". This function
205
- // should be called by escrow contracts that will use uploaded proofs
206
- // to execute transactions, in order to prevent the proof from being used
207
- // by parties other than the escrow contract.
208
- // Assumes that the outputs and locked outputs are already validated to be new UTXOs.
209
- function _lock(
210
- uint256[] memory nullifiers,
211
- uint256[] memory outputs,
212
- uint256[] memory lockedOutputs,
213
- address delegate,
214
- bytes calldata data
215
- ) internal {
216
- for (uint256 i = 0; i < outputs.length; ++i) {
217
- if (outputs[i] == 0) {
218
- // skip the zero outputs
219
- continue;
220
- }
221
- _commitmentsTree.addLeaf(outputs[i], outputs[i]);
222
- }
223
-
224
- // Check the locked outputs are all new UTXOs
225
- for (uint256 i = 0; i < lockedOutputs.length; ++i) {
226
- if (lockedOutputs[i] == 0) {
227
- // skip the zero outputs
228
- continue;
229
- }
230
- _lockedCommitmentsTree.addLeaf(
231
- lockedOutputs[i],
232
- uint256(uint160(delegate))
233
- );
234
- }
235
-
236
- emit UTXOsLocked(
237
- nullifiers,
238
- outputs,
239
- lockedOutputs,
240
- delegate,
241
- msg.sender,
242
- data
243
- );
244
- }
245
-
246
- // move the ability to spend the locked UTXOs to the delegate account.
247
- // The sender must be the current delegate.
248
- function delegateLock(
249
- uint256[] memory utxos,
250
- address delegate,
251
- bytes calldata data
252
- ) public {
253
- for (uint256 i = 0; i < utxos.length; ++i) {
254
- if (utxos[i] == 0) {
255
- continue;
256
- }
257
- bool existsInTree;
258
- address currentDelegate;
259
- (existsInTree, currentDelegate) = existsAsLocked(
260
- utxos[i],
261
- msg.sender
262
- );
263
- if (!existsInTree) {
264
- revert UTXONotLocked(utxos[i]);
265
- }
266
- if (currentDelegate != msg.sender) {
267
- revert NotLockDelegate(utxos[i], delegate, msg.sender);
268
- }
269
- _lockedCommitmentsTree.addLeaf(
270
- utxos[i],
271
- uint256(uint160(delegate))
272
- );
273
- }
274
-
275
- emit LockDelegateChanged(utxos, msg.sender, delegate, data);
276
- }
277
-
278
- function locked(
279
- uint256 utxo,
280
- address delegate
281
- ) public view returns (bool, address) {
282
- return existsAsLocked(utxo, delegate);
283
- }
284
-
285
- function getLeafNodeHash(
286
- uint256 index,
287
- uint256 value
288
- ) internal pure returns (uint256) {
289
- uint256[3] memory params = [index, value, uint256(1)];
290
- return PoseidonUnit3L.poseidon(params);
291
- }
292
-
293
- // check the existence of a UTXO in either the unlocked or locked commitments tree
294
- function exists(uint256 utxo) internal view returns (bool) {
295
- bool existsInTree = everExistedAsUnlocked(utxo);
296
- if (!existsInTree) {
297
- return everExistedAsLocked(utxo);
298
- }
299
- return existsInTree;
300
- }
301
-
302
- // check the existence of a UTXO in the commitments tree. we take a shortcut
303
- // by checking the list of nodes by their node hash, because the commitments
304
- // tree is append-only, no updates or deletions are allowed. As a result, all
305
- // nodes in the list are valid leaf nodes, aka there are no orphaned nodes.
306
- function everExistedAsUnlocked(uint256 utxo) internal view returns (bool) {
307
- uint256 nodeHash = getLeafNodeHash(utxo, utxo);
308
- SmtLib.Node memory node = _commitmentsTree.getNode(nodeHash);
309
- return node.nodeType != SmtLib.NodeType.EMPTY;
310
- }
311
-
312
- // check if an UTXO has ever existed in the locked commitments tree. Because
313
- // this tree allows updates to an existing leaf node, we check the node by its
314
- // merkle proof
315
- function everExistedAsLocked(uint256 utxo) internal view returns (bool) {
316
- SmtLib.Proof memory proof = _lockedCommitmentsTree.getProof(utxo);
317
- return proof.existence;
318
- }
319
-
320
- // check the existence of a locked UTXO in the locked commitments tree. Because
321
- // this tree allows updates to an existing leaf node, we need to check the node
322
- // by its merkle proof, which is built from the current tree and disregards the
323
- // orphaned nodes after updates.
324
- function existsAsLocked(
325
- uint256 utxo,
326
- address delegate
327
- ) internal view returns (bool, address) {
328
- SmtLib.Proof memory proof = _lockedCommitmentsTree.getProof(utxo);
329
- return (
330
- proof.existence && proof.value == uint256(uint160(delegate)),
331
- address(uint160(proof.value))
332
- );
333
- }
334
- }
@@ -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
- }