@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.
- package/README.md +76 -162
- package/config/eip170.ts +30 -0
- package/contracts/factory.sol +30 -34
- package/contracts/factory_upgradeable.sol +11 -7
- package/contracts/lib/common/util.sol +40 -0
- package/contracts/lib/interfaces/ILockableCapability.sol +318 -0
- package/contracts/lib/interfaces/{izeto.sol → IZeto.sol} +13 -1
- package/contracts/lib/interfaces/{izeto_initializable.sol → IZetoInitializable.sol} +14 -12
- package/contracts/lib/interfaces/{izeto_kyc.sol → IZetoKyc.sol} +3 -3
- package/contracts/lib/interfaces/IZetoLockHooks.sol +42 -0
- package/contracts/lib/interfaces/IZetoLockableCapability.sol +237 -0
- package/contracts/lib/interfaces/IZetoStorage.sol +106 -0
- package/contracts/lib/interfaces/{izeto_lockable.sol → IZetoVerifier.sol} +8 -21
- package/contracts/lib/registry.sol +74 -26
- package/contracts/lib/storage/base.sol +210 -0
- package/contracts/lib/storage/nullifier.sol +166 -0
- package/contracts/lib/zeto_common.sol +277 -28
- package/contracts/lib/zeto_fungible.sol +443 -33
- package/contracts/lib/zeto_fungible_base.sol +69 -0
- package/contracts/lib/zeto_fungible_burn.sol +83 -53
- package/contracts/lib/zeto_fungible_burn_nullifier.sol +115 -72
- package/contracts/lib/zeto_fungible_nullifier.sol +167 -0
- package/contracts/lib/zeto_lockable.sol +219 -0
- package/contracts/lib/zeto_lockable_lib.sol +460 -0
- package/contracts/lib/zeto_lockable_storage.sol +43 -0
- package/contracts/lib/zeto_non_fungible.sol +228 -0
- package/contracts/lib/zeto_non_fungible_base.sol +61 -0
- package/contracts/lib/zeto_non_fungible_nullifier.sol +61 -0
- package/contracts/test/escrow1.sol +90 -34
- package/contracts/test/escrow2.sol +64 -29
- package/contracts/test/qurrency.sol +10 -2
- package/contracts/test/smt.sol +6 -1
- package/contracts/test/tendecimals.sol +14 -12
- package/contracts/verifiers/impl/anon.sol +189 -0
- package/contracts/verifiers/impl/anon_batch.sol +301 -0
- package/contracts/verifiers/impl/anon_enc.sol +266 -0
- package/contracts/verifiers/impl/anon_enc_batch.sol +602 -0
- package/contracts/verifiers/impl/anon_enc_nullifier.sol +287 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_batch.sol +679 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_kyc.sol +294 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_kyc_batch.sol +686 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation.sol +413 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation_batch.sol +1141 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transfer.sol +217 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked.sol +196 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked_batch.sol +308 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transfer_batch.sol +385 -0
- package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer.sol +497 -0
- package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer_batch.sol +1001 -0
- package/contracts/verifiers/{verifier_anon_nullifier_transferLocked.sol → impl/anon_nullifier_transfer.sol} +12 -19
- package/contracts/verifiers/{verifier_anon_nullifier_transferLocked_batch.sol → impl/anon_nullifier_transfer_batch.sol} +44 -51
- package/contracts/verifiers/impl/burn.sol +182 -0
- package/contracts/verifiers/impl/burn_batch.sol +238 -0
- package/contracts/verifiers/impl/burn_nullifier.sol +203 -0
- package/contracts/verifiers/impl/burn_nullifier_batch.sol +315 -0
- package/contracts/verifiers/impl/deposit.sol +182 -0
- package/contracts/verifiers/impl/deposit_kyc.sol +189 -0
- package/contracts/verifiers/impl/nf_anon.sol +175 -0
- package/contracts/verifiers/{verifier_nf_anon_nullifier_transferLocked.sol → impl/nf_anon_nullifier_transfer.sol} +6 -13
- package/contracts/verifiers/impl/withdraw.sol +189 -0
- package/contracts/verifiers/impl/withdraw_batch.sol +245 -0
- package/contracts/verifiers/impl/withdraw_nullifier.sol +210 -0
- package/contracts/verifiers/impl/withdraw_nullifier_batch.sol +322 -0
- package/contracts/verifiers/verifier_anon.sol +31 -186
- package/contracts/verifiers/verifier_anon_batch.sol +31 -298
- package/contracts/verifiers/verifier_anon_enc.sol +31 -263
- package/contracts/verifiers/verifier_anon_enc_batch.sol +31 -599
- package/contracts/verifiers/verifier_anon_enc_nullifier.sol +31 -284
- package/contracts/verifiers/verifier_anon_enc_nullifier_batch.sol +33 -676
- package/contracts/verifiers/verifier_anon_enc_nullifier_kyc.sol +31 -291
- package/contracts/verifiers/verifier_anon_enc_nullifier_kyc_batch.sol +33 -683
- package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation.sol +33 -410
- package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation_batch.sol +33 -1138
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer.sol +33 -214
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked.sol +33 -221
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked_batch.sol +33 -389
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer_batch.sol +33 -382
- package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer.sol +33 -221
- package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer_batch.sol +33 -389
- package/contracts/verifiers/verifier_anon_nullifier_transfer.sol +33 -207
- package/contracts/verifiers/verifier_anon_nullifier_transfer_batch.sol +33 -375
- package/contracts/verifiers/verifier_burn.sol +31 -179
- package/contracts/verifiers/verifier_burn_batch.sol +31 -235
- package/contracts/verifiers/verifier_burn_nullifier.sol +31 -200
- package/contracts/verifiers/verifier_burn_nullifier_batch.sol +31 -312
- package/contracts/verifiers/verifier_deposit.sol +31 -179
- package/contracts/verifiers/verifier_deposit_kyc.sol +34 -0
- package/contracts/verifiers/verifier_nf_anon.sol +31 -172
- package/contracts/verifiers/verifier_nf_anon_nullifier_transfer.sol +33 -179
- package/contracts/verifiers/verifier_withdraw.sol +31 -186
- package/contracts/verifiers/verifier_withdraw_batch.sol +31 -242
- package/contracts/verifiers/verifier_withdraw_nullifier.sol +31 -207
- package/contracts/verifiers/verifier_withdraw_nullifier_batch.sol +33 -319
- package/contracts/zeto_anon.sol +77 -231
- package/contracts/zeto_anon_burnable.sol +56 -12
- package/contracts/zeto_anon_enc.sol +93 -190
- package/contracts/zeto_anon_enc_nullifier.sol +249 -195
- package/contracts/zeto_anon_enc_nullifier_kyc.sol +51 -232
- package/contracts/zeto_anon_enc_nullifier_non_repudiation.sol +231 -238
- package/contracts/zeto_anon_nullifier.sol +164 -298
- package/contracts/zeto_anon_nullifier_burnable.sol +68 -18
- package/contracts/zeto_anon_nullifier_kyc.sol +40 -345
- package/contracts/zeto_anon_nullifier_qurrency.sol +217 -361
- package/contracts/zeto_nf_anon.sol +55 -130
- package/contracts/zeto_nf_anon_nullifier.sol +90 -152
- package/hardhat.config.ts +18 -3
- package/ignition/modules/lib/deps.ts +13 -0
- package/ignition/modules/test/tendecimals.ts +7 -1
- package/ignition/modules/zeto_anon.ts +3 -0
- package/ignition/modules/zeto_anon_burnable.ts +11 -7
- package/ignition/modules/zeto_anon_enc.ts +3 -0
- package/ignition/modules/zeto_anon_enc_nullifier.ts +34 -0
- package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +5 -2
- package/ignition/modules/zeto_anon_enc_nullifier_non_repudiation.ts +3 -0
- package/ignition/modules/zeto_anon_nullifier.ts +31 -4
- package/ignition/modules/zeto_anon_nullifier_burnable.ts +53 -16
- package/ignition/modules/zeto_anon_nullifier_kyc.ts +30 -12
- package/ignition/modules/zeto_anon_nullifier_qurrency.ts +3 -0
- package/ignition/modules/zeto_nf_anon.ts +3 -1
- package/ignition/modules/zeto_nf_anon_nullifier.ts +17 -12
- package/package.json +7 -3
- package/scripts/deploy_cloneable.ts +19 -10
- package/scripts/deploy_upgradeable.ts +9 -5
- package/scripts/lib/zeto_libraries.ts +47 -0
- package/scripts/tokens/Zeto_Anon.ts +6 -3
- package/scripts/tokens/Zeto_AnonBurnable.ts +4 -1
- package/scripts/tokens/Zeto_AnonEnc.ts +15 -3
- package/scripts/tokens/Zeto_AnonEncNullifier.ts +11 -8
- package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +7 -6
- package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +7 -6
- package/scripts/tokens/Zeto_AnonNullifier.ts +7 -6
- package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +7 -6
- package/scripts/tokens/Zeto_AnonNullifierKyc.ts +7 -6
- package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +7 -8
- package/scripts/tokens/Zeto_NfAnon.ts +5 -3
- package/scripts/tokens/Zeto_NfAnonNullifier.ts +7 -7
- package/test/factory.ts +55 -73
- package/test/lib/anon_nullifier_helpers.ts +89 -0
- package/test/lib/anon_zeto_helpers.ts +76 -0
- package/test/lib/deploy.ts +5 -2
- package/test/lib/eip170.ts +23 -0
- package/test/lib/utils.ts +74 -35
- package/test/test/escrow1.ts +185 -58
- package/test/test/escrow2.ts +200 -107
- package/test/test/qurrency.ts +13 -33
- package/test/usdc-shielding.ts +39 -27
- package/test/utils.ts +144 -21
- package/test/zeto_anon.ts +956 -465
- package/test/zeto_anon_enc.ts +881 -143
- package/test/zeto_anon_enc_nullifier.ts +850 -39
- package/test/zeto_anon_enc_nullifier_kyc.ts +123 -182
- package/test/zeto_anon_enc_nullifier_non_repudiation.ts +80 -47
- package/test/zeto_anon_nullifier.ts +1212 -954
- package/test/zeto_anon_nullifier_kyc.ts +677 -656
- package/test/zeto_anon_nullifier_qurrency.ts +455 -307
- package/test/zeto_nf_anon.ts +737 -138
- package/test/zeto_nf_anon_nullifier.ts +876 -247
- package/contracts/lib/zeto_base.sol +0 -293
- package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
- package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
- package/contracts/lib/zeto_nullifier.sol +0 -340
- package/contracts/zkDvP.sol_ +0 -273
- package/test/zkDvP.ts_ +0 -455
- /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
|
-
}
|
package/contracts/zkDvP.sol_
DELETED
|
@@ -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
|
-
}
|