@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
@@ -0,0 +1,43 @@
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
+ /// @dev ERC-7201 (`erc7201:zeto.storage.ZetoLockable`): lock lifecycle state for
19
+ /// {ZetoLockableLib} and embedding token contracts.
20
+ library ZetoLockableStorage {
21
+ struct ZetoLockInfo {
22
+ address owner;
23
+ address spender;
24
+ bytes32 spendCommitment;
25
+ bytes32 cancelCommitment;
26
+ uint256[] lockedInputs;
27
+ }
28
+
29
+ struct Layout {
30
+ mapping(bytes32 => ZetoLockInfo) locks;
31
+ mapping(address => mapping(bytes32 => bool)) txIds;
32
+ mapping(uint256 => address) utxoDelegates;
33
+ }
34
+
35
+ bytes32 private constant STORAGE_LOCATION =
36
+ 0x6f84b5947db308f6274c3bdf3450b8e85913b258c3b2e7abbddf0986236a4900;
37
+
38
+ function layout() internal pure returns (Layout storage $) {
39
+ assembly {
40
+ $.slot := STORAGE_LOCATION
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,228 @@
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 {ZetoLockable} from "./zeto_lockable.sol";
19
+ import {Commonlib} from "./common/common.sol";
20
+ import {IZetoInitializable} from "./interfaces/IZetoInitializable.sol";
21
+ import {IZetoStorage} from "./interfaces/IZetoStorage.sol";
22
+
23
+ /// @title A sample base implementation of a Zeto based non-fungible
24
+ /// token contract.
25
+ /// @author Kaleido, Inc.
26
+ /// @dev The proof has the following statements:
27
+ /// - The sender owns the private key whose public key is part of the pre-image of the input UTXOs commitments
28
+ /// (aka the sender is authorized to spend the input UTXOs)
29
+ /// - The input UTXOs and output UTXOs are valid in terms of obeying mass conservation rules
30
+ ///
31
+ /// Inherits {ZetoLockable} (linked {ZetoLockableLib}) so the
32
+ /// create/update/delegate/spend/cancel lock lifecycle is shared with the fungible siblings via
33
+ /// a single implementation. The two ZK-circuit-shaped hooks
34
+ /// ({_doLockTransition} and {_transferLocked}) are overridden here
35
+ /// to match the NF circuit's fixed 1-in/1-out shape — there is no
36
+ /// input/output padding and no batch verifier path.
37
+ abstract contract ZetoNonFungible is ZetoLockable {
38
+ function __ZetoNonFungible_init(
39
+ string calldata name_,
40
+ string calldata symbol_,
41
+ address initialOwner,
42
+ IZetoInitializable.VerifiersInfo calldata verifiers,
43
+ IZetoStorage storage_
44
+ ) internal onlyInitializing {
45
+ __ZetoCommon_init(name_, symbol_, initialOwner, verifiers, storage_);
46
+ }
47
+
48
+ /**
49
+ * @dev Single-input/single-output transfer.
50
+ *
51
+ * @param input The UTXO to be spent by the transaction.
52
+ * @param output The new UTXO to generate, for future transactions
53
+ * to spend.
54
+ * @param proof A zero knowledge proof that the submitter is
55
+ * authorized to spend the input, and that the output is valid
56
+ * in terms of obeying mass conservation rules.
57
+ * @param data Opaque data appended to the {UTXOTransfer} event for
58
+ * off-chain consumers.
59
+ *
60
+ * Emits a {UTXOTransfer} event.
61
+ */
62
+ function transfer(
63
+ uint256 input,
64
+ uint256 output,
65
+ bytes calldata proof,
66
+ bytes calldata data
67
+ ) public {
68
+ uint256[] memory inputs = new uint256[](1);
69
+ inputs[0] = input;
70
+ uint256[] memory outputs = new uint256[](1);
71
+ outputs[0] = output;
72
+ uint256[] memory lockedOutputs;
73
+
74
+ validateTransactionProposal(
75
+ inputs,
76
+ outputs,
77
+ lockedOutputs,
78
+ proof,
79
+ false
80
+ );
81
+
82
+ (
83
+ uint256[] memory publicInputs,
84
+ Commonlib.Proof memory proofStruct
85
+ ) = constructPublicInputs(inputs, outputs, proof, false);
86
+ verifyProof(proofStruct, publicInputs, false, false);
87
+ processInputsAndOutputs(inputs, outputs, false);
88
+ emit UTXOTransfer(inputs, outputs, msg.sender, data);
89
+ }
90
+
91
+ // ------------------------------------------------------------------
92
+ // ZetoLockable hook overrides — non-fungible flavour.
93
+ //
94
+ // The NF circuits are fixed 1-in/1-out (or 1-in/1-locked-out for
95
+ // create-lock, 1-locked-in/1-out for spend/cancel), so there is no
96
+ // padding step and the batch-verifier path is never selected.
97
+ //
98
+ // Caller-supplied `args` are validated by ZetoLockable to be
99
+ // {ZetoCreateLockArgs}/{ZetoSpendLockArgs}; this hook trusts that
100
+ // shape and additionally enforces that the array sizes match the
101
+ // NF circuit (single input plus a single locked or unlocked
102
+ // output).
103
+ // ------------------------------------------------------------------
104
+
105
+ /// @dev Thrown when an NF lock-lifecycle call is invoked with an
106
+ /// input/output array shape that does not match the fixed
107
+ /// 1-in/1-out circuit. Catching this at the contract layer
108
+ /// gives a typed revert before the proof verifier would fail
109
+ /// with a generic {InvalidProof}.
110
+ error InvalidNonFungibleArity(
111
+ uint256 inputs,
112
+ uint256 outputs,
113
+ uint256 lockedOutputs
114
+ );
115
+
116
+ function _doLockTransition(
117
+ ZetoCreateLockArgs calldata args
118
+ ) internal override {
119
+ // NF createLock: spend exactly one unlocked input and produce
120
+ // exactly one locked output. There is no regular (unlocked)
121
+ // output for NF lock creation — a single token cannot be split.
122
+ if (
123
+ args.inputs.length != 1 ||
124
+ args.outputs.length != 0 ||
125
+ args.lockedOutputs.length != 1
126
+ ) {
127
+ revert InvalidNonFungibleArity(
128
+ args.inputs.length,
129
+ args.outputs.length,
130
+ args.lockedOutputs.length
131
+ );
132
+ }
133
+
134
+ validateTransactionProposal(
135
+ args.inputs,
136
+ args.outputs,
137
+ args.lockedOutputs,
138
+ args.proof,
139
+ false
140
+ );
141
+
142
+ // The circuit treats the locked output as the "output"; combine
143
+ // for the public-inputs construction.
144
+ uint256[] memory allOutputs = new uint256[](1);
145
+ allOutputs[0] = args.lockedOutputs[0];
146
+
147
+ (
148
+ uint256[] memory publicInputs,
149
+ Commonlib.Proof memory proofStruct
150
+ ) = constructPublicInputs(args.inputs, allOutputs, args.proof, false);
151
+ verifyProof(proofStruct, publicInputs, false, false);
152
+
153
+ processInputsAndOutputs(args.inputs, args.outputs, false);
154
+ processLockedOutputs(args.lockedOutputs);
155
+ }
156
+
157
+ function _transferLocked(
158
+ bytes32 /* lockId */,
159
+ uint256[] calldata lockedInputs,
160
+ uint256[] calldata lockedOutputs,
161
+ uint256[] calldata outputs,
162
+ bytes calldata proof,
163
+ bytes calldata /* data */
164
+ ) internal override {
165
+ // NF spend/cancel: consume exactly one locked input and produce
166
+ // exactly one output. The output may be either a regular
167
+ // unlocked UTXO (the typical spend case) or a fresh locked UTXO
168
+ // (e.g. re-lock under a new spender via cancel-then-create).
169
+ if (
170
+ lockedInputs.length != 1 ||
171
+ lockedOutputs.length + outputs.length != 1
172
+ ) {
173
+ revert InvalidNonFungibleArity(
174
+ lockedInputs.length,
175
+ outputs.length,
176
+ lockedOutputs.length
177
+ );
178
+ }
179
+
180
+ validateTransactionProposal(
181
+ lockedInputs,
182
+ outputs,
183
+ lockedOutputs,
184
+ proof,
185
+ true
186
+ );
187
+
188
+ // The circuit treats locked and unlocked outputs identically, so
189
+ // both feed `constructPublicInputs` via the same single-element
190
+ // `allOutputs` array.
191
+ uint256[] memory allOutputs = new uint256[](1);
192
+ allOutputs[0] = lockedOutputs.length == 1
193
+ ? lockedOutputs[0]
194
+ : outputs[0];
195
+
196
+ (
197
+ uint256[] memory publicInputs,
198
+ Commonlib.Proof memory proofStruct
199
+ ) = constructPublicInputs(lockedInputs, allOutputs, proof, true);
200
+ verifyProof(proofStruct, publicInputs, false, true);
201
+
202
+ // Storage-side bookkeeping keeps the two ledgers strictly
203
+ // disjoint: the unlocked output (if any) goes through
204
+ // `processOutputs`, the locked output (if any) goes through
205
+ // `processLockedOutputs`. Mirroring `_doLockTransition` here
206
+ // avoids the locked-output being recorded as both unlocked and
207
+ // locked, which would let it be spent twice (once via the
208
+ // unlocked path, once via the lockable path).
209
+ processInputsAndOutputs(lockedInputs, outputs, true);
210
+ processLockedOutputs(lockedOutputs);
211
+ }
212
+ }
213
+
214
+ /// @dev ERC-7201 (`erc7201:zeto.storage.ZetoNonFungible`).
215
+ library ZetoNonFungibleStorage {
216
+ struct Layout {
217
+ uint256 __reserved;
218
+ }
219
+
220
+ bytes32 private constant STORAGE_LOCATION =
221
+ 0x70f918cef12f78aa293f0474363ccfa2a5e8bbdc86def1d4dd7d861fb8e6f600;
222
+
223
+ function layout() internal pure returns (Layout storage $) {
224
+ assembly {
225
+ $.slot := STORAGE_LOCATION
226
+ }
227
+ }
228
+ }
@@ -0,0 +1,61 @@
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 {IZetoInitializable} from "./interfaces/IZetoInitializable.sol";
19
+ import {ZetoNonFungible} from "./zeto_non_fungible.sol";
20
+ import {IZetoStorage} from "./interfaces/IZetoStorage.sol";
21
+ import {BaseStorage} from "./storage/base.sol";
22
+
23
+ /// @title A sample base implementation of a Zeto based non-fungible token contract
24
+ /// without using nullifiers. Each UTXO's spending status is explicitly tracked.
25
+ /// @author Kaleido, Inc.
26
+ /// @dev Wires {BaseStorage} into {ZetoNonFungible} for non-nullifier
27
+ /// flavours of Zeto NF tokens. See {ZetoNonFungible} for the
28
+ /// rationale behind the omitted lock lifecycle.
29
+ abstract contract ZetoNonFungibleBase is ZetoNonFungible {
30
+ function __ZetoNonFungibleBase_init(
31
+ string calldata name_,
32
+ string calldata symbol_,
33
+ address initialOwner,
34
+ IZetoInitializable.VerifiersInfo calldata verifiers
35
+ ) internal onlyInitializing {
36
+ IZetoStorage storage_ = new BaseStorage();
37
+ __ZetoNonFungible_init(
38
+ name_,
39
+ symbol_,
40
+ initialOwner,
41
+ verifiers,
42
+ storage_
43
+ );
44
+ }
45
+ }
46
+
47
+ /// @dev ERC-7201 (`erc7201:zeto.storage.ZetoNonFungibleBase`).
48
+ library ZetoNonFungibleBaseStorage {
49
+ struct Layout {
50
+ uint256 __reserved;
51
+ }
52
+
53
+ bytes32 private constant STORAGE_LOCATION =
54
+ 0x3b5aad0db95258b4583c7272ce26730b4879c3622cde60d71e7f2a14bdd3ae00;
55
+
56
+ function layout() internal pure returns (Layout storage $) {
57
+ assembly {
58
+ $.slot := STORAGE_LOCATION
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,61 @@
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 {IZetoInitializable} from "./interfaces/IZetoInitializable.sol";
19
+ import {ZetoNonFungible} from "./zeto_non_fungible.sol";
20
+ import {IZetoStorage} from "./interfaces/IZetoStorage.sol";
21
+ import {NullifierStorage} from "./storage/nullifier.sol";
22
+
23
+ /// @title A sample base implementation of a Zeto based non-fungible token
24
+ /// contract with nullifier-based history masking.
25
+ /// @author Kaleido, Inc.
26
+ /// @dev Wires {NullifierStorage} into {ZetoNonFungible} for the nullifier
27
+ /// flavours of Zeto NF tokens. See {ZetoNonFungible} for the
28
+ /// rationale behind the omitted lock lifecycle.
29
+ abstract contract ZetoNonFungibleNullifier is ZetoNonFungible {
30
+ function __ZetoNonFungibleNullifier_init(
31
+ string calldata name_,
32
+ string calldata symbol_,
33
+ address initialOwner,
34
+ IZetoInitializable.VerifiersInfo calldata verifiers
35
+ ) internal onlyInitializing {
36
+ IZetoStorage storage_ = new NullifierStorage();
37
+ __ZetoNonFungible_init(
38
+ name_,
39
+ symbol_,
40
+ initialOwner,
41
+ verifiers,
42
+ storage_
43
+ );
44
+ }
45
+ }
46
+
47
+ /// @dev ERC-7201 (`erc7201:zeto.storage.ZetoNonFungibleNullifier`).
48
+ library ZetoNonFungibleNullifierStorage {
49
+ struct Layout {
50
+ uint256 __reserved;
51
+ }
52
+
53
+ bytes32 private constant STORAGE_LOCATION =
54
+ 0x02976bb09873e8949dece591ee756708ea74c24901fa2000868b92802a9a5200;
55
+
56
+ function layout() internal pure returns (Layout storage $) {
57
+ assembly {
58
+ $.slot := STORAGE_LOCATION
59
+ }
60
+ }
61
+ }
@@ -15,16 +15,50 @@
15
15
  // limitations under the License.
16
16
  pragma solidity ^0.8.27;
17
17
 
18
- import {Commonlib} from "../lib/common.sol";
18
+ import {Commonlib} from "../lib/common/common.sol";
19
19
  import {Zeto_Anon} from "../zeto_anon.sol";
20
- // import {console} from "hardhat/console.sol";
20
+ import {ILockableCapability} from "../lib/interfaces/ILockableCapability.sol";
21
+ import {IZetoLockableCapability} from "../lib/interfaces/IZetoLockableCapability.sol";
21
22
 
22
- /// @title A sample on-chain implementation of an escrow contract using Zeto tokens
23
+ /// @title zkEscrow1
23
24
  /// @author Kaleido, Inc.
24
- /// @dev Implements escrow based payment flows with Zeto_Anon tokens
25
+ /// @notice Sample on-chain escrow built on top of {Zeto_Anon} that brokers a
26
+ /// payment between a payer and a payee using the new
27
+ /// {ILockableCapability} lifecycle.
28
+ ///
29
+ /// Lifecycle of a single escrowed payment:
30
+ /// 1. The payer calls {Zeto_Anon.createLock} to lock one or more
31
+ /// UTXOs they own. The payer is initially both the lock owner
32
+ /// and spender.
33
+ /// 2. The payer calls {Zeto_Anon.delegateLock} naming this escrow
34
+ /// as the new spender. From this point on, only this escrow
35
+ /// can spend or cancel the lock.
36
+ /// 3. The payer (or anyone) calls {initiatePayment} on this
37
+ /// escrow with the lockId and the proposed unlocked output
38
+ /// UTXOs. The escrow asserts it is the current spender of the
39
+ /// lock before recording the payment.
40
+ /// 4. An authorised approver calls {approvePayment} with a ZK
41
+ /// proof attesting that `(lockedInputs, outputs)` is a valid
42
+ /// transition under {Zeto_Anon}'s circuit. The escrow stores
43
+ /// the proof but does not yet consume the lock.
44
+ /// 5. Anyone (typically the payee) calls {completePayment}. The
45
+ /// escrow forwards the stored proof to {Zeto_Anon.spendLock},
46
+ /// which consumes the locked inputs and mints the unlocked
47
+ /// outputs to their recipients in a single atomic step.
48
+ ///
49
+ /// Notes on the new lock model:
50
+ /// * The escrow does NOT choose the locked inputs at approval
51
+ /// or completion time. They are pinned by `_locks[lockId]`
52
+ /// inside {Zeto_Anon} at create-time, so "spending lock A
53
+ /// always consumes lock A's UTXOs" is a hard contract
54
+ /// invariant rather than a soft hash check on user-supplied
55
+ /// arrays.
56
+ /// * The escrow likewise does not choose `lockedOutputs` (it
57
+ /// always sends them empty); the spend completes by minting
58
+ /// plain unlocked UTXOs to the recipients.
25
59
  contract zkEscrow1 {
26
60
  enum PaymentStatus {
27
- UNKNOWN, // this is the default value for the empty payment slots
61
+ UNKNOWN, // default value for empty payment slots
28
62
  INITIATED,
29
63
  APPROVED,
30
64
  COMPLETED,
@@ -32,10 +66,10 @@ contract zkEscrow1 {
32
66
  }
33
67
 
34
68
  struct Payment {
35
- uint256[] lockedInputs;
69
+ bytes32 lockId;
36
70
  uint256[] outputs;
37
71
  PaymentStatus status;
38
- Commonlib.Proof proof;
72
+ bytes proof;
39
73
  }
40
74
 
41
75
  mapping(uint256 => Payment) public payments;
@@ -45,7 +79,7 @@ contract zkEscrow1 {
45
79
 
46
80
  event PaymentInitiated(
47
81
  uint256 paymentId,
48
- uint256[] lockedInputs,
82
+ bytes32 lockId,
49
83
  uint256[] outputs,
50
84
  bytes data
51
85
  );
@@ -56,35 +90,41 @@ contract zkEscrow1 {
56
90
  zeto = Zeto_Anon(zetoAddress);
57
91
  }
58
92
 
93
+ /// @notice Record a new escrowed payment against an existing lock.
94
+ /// @dev The escrow MUST already be the current spender of the lock
95
+ /// (the payer must have called {Zeto_Anon.delegateLock} naming
96
+ /// this contract as the new spender before calling here).
97
+ /// The locked inputs themselves are not stored on the
98
+ /// payment; they are read fresh from {Zeto_Anon.getLockedInputs}
99
+ /// at approval and completion time so the escrow always
100
+ /// operates on the lock's storage-pinned content.
59
101
  function initiatePayment(
60
- uint256[] memory lockedInputs,
102
+ bytes32 lockId,
61
103
  uint256[] memory outputs,
62
104
  bytes calldata data
63
105
  ) public {
64
- for (uint256 i = 0; i < lockedInputs.length; i++) {
65
- bool locked;
66
- address delegate;
67
- (locked, delegate) = zeto.locked(lockedInputs[i]);
68
- require(locked, "Input not locked");
69
- require(
70
- delegate == address(this),
71
- "Input not locked to this contract"
72
- );
73
- }
106
+ ILockableCapability.LockInfo memory info = zeto.getLock(lockId);
107
+ require(info.spender == address(this), "Escrow is not the spender");
74
108
  inflightCount++;
75
- Commonlib.Proof memory emptyProof;
109
+ bytes memory emptyProof;
76
110
  payments[inflightCount] = Payment(
77
- lockedInputs,
111
+ lockId,
78
112
  outputs,
79
113
  PaymentStatus.INITIATED,
80
114
  emptyProof
81
115
  );
82
- emit PaymentInitiated(inflightCount, lockedInputs, outputs, data);
116
+ emit PaymentInitiated(inflightCount, lockId, outputs, data);
83
117
  }
84
118
 
119
+ /// @notice Verify the spend ZK proof for an initiated payment and
120
+ /// move the payment into the APPROVED state.
121
+ /// @dev The verification mirrors what {Zeto_Anon._transferLocked}
122
+ /// would do later (same {checkAndPadCommitments} + locked-input
123
+ /// verifier path), so a successful approval here guarantees
124
+ /// that {completePayment} will not revert on proof grounds.
85
125
  function approvePayment(
86
126
  uint256 paymentId,
87
- Commonlib.Proof memory proof,
127
+ bytes memory proof,
88
128
  bytes calldata data
89
129
  ) public {
90
130
  Payment storage payment = payments[paymentId];
@@ -92,12 +132,18 @@ contract zkEscrow1 {
92
132
  payment.status == PaymentStatus.INITIATED,
93
133
  "Payment not initiated"
94
134
  );
95
- payment.lockedInputs = zeto.checkAndPadCommitments(
96
- payment.lockedInputs
97
- );
98
- payment.outputs = zeto.checkAndPadCommitments(payment.outputs);
135
+ uint256[] memory lockedInputs = zeto.getLockedInputs(payment.lockId);
136
+ (
137
+ uint256[] memory paddedInputs,
138
+ uint256[] memory paddedOutputs
139
+ ) = zeto.checkAndPadCommitments(lockedInputs, payment.outputs);
99
140
  require(
100
- zeto.verifyProof(payment.lockedInputs, payment.outputs, proof),
141
+ zeto.constructPublicSignalsAndVerifyProof(
142
+ paddedInputs,
143
+ paddedOutputs,
144
+ proof,
145
+ true
146
+ ),
101
147
  "Invalid proof"
102
148
  );
103
149
  payment.proof = proof;
@@ -105,18 +151,28 @@ contract zkEscrow1 {
105
151
  emit PaymentApproved(paymentId, data);
106
152
  }
107
153
 
154
+ /// @notice Forward the approved spend proof to {Zeto_Anon.spendLock}.
155
+ /// @dev Encodes the {IZetoLockableCapability.ZetoSpendLockArgs}
156
+ /// payload from `payment` and invokes `spendLock(lockId, ...)`
157
+ /// as the lock's current spender. After this call returns the
158
+ /// lock is consumed, the locked UTXOs are marked spent on the
159
+ /// underlying Zeto storage, and the unlocked outputs are
160
+ /// emitted to their recipients.
108
161
  function completePayment(uint256 paymentId, bytes calldata data) public {
109
162
  Payment storage payment = payments[paymentId];
110
163
  require(
111
164
  payment.status == PaymentStatus.APPROVED,
112
165
  "Payment not approved"
113
166
  );
114
- zeto.transferLocked(
115
- payment.lockedInputs,
116
- payment.outputs,
117
- payment.proof,
118
- "0x"
119
- );
167
+ IZetoLockableCapability.ZetoSpendLockArgs
168
+ memory spendArgs = IZetoLockableCapability.ZetoSpendLockArgs({
169
+ txId: bytes32(paymentId),
170
+ lockedOutputs: new uint256[](0),
171
+ outputs: payment.outputs,
172
+ proof: payment.proof,
173
+ data: ""
174
+ });
175
+ zeto.spendLock(payment.lockId, abi.encode(spendArgs), "");
120
176
  payment.status = PaymentStatus.COMPLETED;
121
177
  emit PaymentCompleted(paymentId, data);
122
178
  }