@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
@@ -15,155 +15,80 @@
15
15
  // limitations under the License.
16
16
  pragma solidity ^0.8.27;
17
17
 
18
- import {IZeto} from "./lib/interfaces/izeto.sol";
19
- import {Groth16Verifier_NfAnon} from "./verifiers/verifier_nf_anon.sol";
20
- import {ZetoBase} from "./lib/zeto_base.sol";
21
- import {Commonlib} from "./lib/common.sol";
22
- import {IZetoInitializable} from "./lib/interfaces/izeto_initializable.sol";
18
+ import {ZetoNonFungibleBase} from "./lib/zeto_non_fungible_base.sol";
19
+ import {Commonlib} from "./lib/common/common.sol";
20
+ import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
23
21
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
24
22
 
25
- /// @title A sample implementation of a Zeto based non-fungible token with anonymity and no encryption
23
+ /// @title A sample implementation of a Zeto based non-fungible token with
24
+ /// anonymity (no encryption, no nullifier history masking).
26
25
  /// @author Kaleido, Inc.
26
+ /// @notice Decimals: this token uses **4** decimals, inherited from
27
+ /// {ZetoCommon.decimals}. NFT integrators rarely consult
28
+ /// `decimals()` but it is preserved for ABI symmetry with the
29
+ /// fungible siblings.
27
30
  /// @dev The proof has the following statements:
28
- /// - The sender owns the private key whose public key is part of the pre-image of the input UTXOs commitments
29
- /// (aka the sender is authorized to spend the input UTXOs)
30
- /// - The input UTXOs and output UTXOs are valid in terms of obeying mass conservation rules
31
- contract Zeto_NfAnon is IZeto, IZetoInitializable, ZetoBase, UUPSUpgradeable {
32
- Groth16Verifier_NfAnon internal _verifier;
31
+ /// - The sender owns the private key whose public key is part of the pre-image of the input UTXO commitment
32
+ /// - The output UTXO commitment is well-formed
33
+ ///
34
+ /// Single-input/single-output transfer. The lock lifecycle is
35
+ /// intentionally omitted in this revival; see {ZetoNonFungible}.
36
+ contract Zeto_NfAnon is ZetoNonFungibleBase, UUPSUpgradeable {
37
+ /// @dev Lock the implementation contract on construction.
38
+ /// @custom:oz-upgrades-unsafe-allow constructor
39
+ constructor() {
40
+ _disableInitializers();
41
+ }
33
42
 
34
43
  function initialize(
35
- string memory name,
36
- string memory symbol,
44
+ string calldata name,
45
+ string calldata symbol,
37
46
  address initialOwner,
38
47
  IZetoInitializable.VerifiersInfo calldata verifiers
39
48
  ) public initializer {
40
- __ZetoBase_init(name, symbol, initialOwner);
41
- _verifier = (Groth16Verifier_NfAnon)(verifiers.verifier);
49
+ __ZetoNonFungibleBase_init(name, symbol, initialOwner, verifiers);
42
50
  }
43
51
 
44
52
  function _authorizeUpgrade(address) internal override onlyOwner {}
45
53
 
46
- /**
47
- * @dev the main function of the contract.
48
- *
49
- * @param input The UTXO to be spent by the transaction.
50
- * @param output The new UTXO to generate, for future transactions to spend.
51
- * @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
52
- * that the outputs are valid in terms of obeying mass conservation rules.
53
- *
54
- * Emits a {UTXOTransfer} event.
55
- */
56
- function transfer(
57
- uint256 input,
58
- uint256 output,
59
- Commonlib.Proof calldata proof,
60
- bytes calldata data
61
- ) public returns (bool) {
62
- uint256[] memory inputs = new uint256[](1);
63
- inputs[0] = input;
64
- uint256[] memory outputs = new uint256[](1);
65
- outputs[0] = output;
66
- uint256[] memory lockedOutputs;
67
- validateTransactionProposal(inputs, outputs, lockedOutputs, false);
68
-
69
- // construct the public inputs
70
- uint256[2] memory publicInputs;
71
- publicInputs[0] = input;
72
- publicInputs[1] = output;
73
-
74
- // Check the proof
75
- require(
76
- _verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
77
- "Invalid proof"
78
- );
79
-
80
- processInputsAndOutputs(inputs, outputs, lockedOutputs, false);
81
-
82
- emit UTXOTransfer(inputs, outputs, msg.sender, data);
83
- return true;
84
- }
85
-
86
- /**
87
- * @dev the main function of the contract.
88
- *
89
- * @param input The UTXO to be spent by the transaction.
90
- * @param output The new UTXO to generate, for future transactions to spend.
91
- * @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
92
- * that the outputs are valid in terms of obeying mass conservation rules.
93
- *
94
- * Emits a {UTXOTransfer} event.
95
- */
96
- function transferLocked(
97
- uint256 input,
98
- uint256 output,
99
- Commonlib.Proof calldata proof,
100
- bytes calldata data
101
- ) public returns (bool) {
102
- uint256[] memory inputs = new uint256[](1);
103
- inputs[0] = input;
104
- uint256[] memory outputs = new uint256[](1);
105
- outputs[0] = output;
106
- uint256[] memory lockedOutputs;
107
- validateTransactionProposal(inputs, outputs, lockedOutputs, true);
108
-
109
- // construct the public inputs
110
- uint256[2] memory publicInputs;
111
- publicInputs[0] = input;
112
- publicInputs[1] = output;
113
-
114
- // Check the proof
115
- require(
116
- _verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
117
- "Invalid proof"
54
+ /// @dev Public-inputs layout: [input, output]. `inputsLocked` is
55
+ /// ignored because this token does not implement the lock
56
+ /// lifecycle.
57
+ function constructPublicInputs(
58
+ uint256[] memory inputs,
59
+ uint256[] memory outputs,
60
+ bytes memory proof,
61
+ bool /* inputsLocked */
62
+ )
63
+ internal
64
+ pure
65
+ override
66
+ returns (uint256[] memory, Commonlib.Proof memory)
67
+ {
68
+ Commonlib.Proof memory proofStruct = abi.decode(
69
+ proof,
70
+ (Commonlib.Proof)
118
71
  );
72
+ uint256[] memory publicInputs = new uint256[](2);
73
+ publicInputs[0] = inputs[0];
74
+ publicInputs[1] = outputs[0];
119
75
 
120
- processInputsAndOutputs(inputs, outputs, lockedOutputs, true);
121
-
122
- emit UTXOTransfer(inputs, outputs, msg.sender, data);
123
- return true;
76
+ return (publicInputs, proofStruct);
124
77
  }
78
+ }
125
79
 
126
- function mint(uint256[] memory utxos, bytes calldata data) public {
127
- _mint(utxos, data);
80
+ /// @dev ERC-7201 (`erc7201:zeto.storage.Zeto_NfAnon`).
81
+ library Zeto_NfAnonStorage {
82
+ struct Layout {
83
+ uint256 __reserved;
128
84
  }
129
85
 
130
- function lock(
131
- uint256 input,
132
- uint256 lockedOutput,
133
- Commonlib.Proof calldata proof,
134
- address delegate,
135
- bytes calldata data
136
- ) public {
137
- uint256[] memory inputs = new uint256[](1);
138
- inputs[0] = input;
139
- uint256[] memory outputs;
140
- uint256[] memory lockedOutputs = new uint256[](1);
141
- lockedOutputs[0] = lockedOutput;
142
- validateTransactionProposal(inputs, outputs, lockedOutputs, false);
143
-
144
- // construct the public inputs
145
- uint256[2] memory publicInputs;
146
- publicInputs[0] = input;
147
- publicInputs[1] = lockedOutput;
148
-
149
- // Check the proof
150
- require(
151
- _verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
152
- "Invalid proof"
153
- );
154
-
155
- processInputsAndOutputs(inputs, outputs, lockedOutputs, false);
156
-
157
- // lock the intended outputs
158
- _lock(inputs, outputs, lockedOutputs, delegate, data);
159
- }
86
+ bytes32 private constant STORAGE_LOCATION =
87
+ 0xafcd749646d899cf78964151db8f542448d05467330245e10728559327401500;
160
88
 
161
- function unlock(
162
- uint256 input,
163
- uint256 output,
164
- Commonlib.Proof calldata proof,
165
- bytes calldata data
166
- ) public {
167
- transferLocked(input, output, proof, data);
89
+ function layout() internal pure returns (Layout storage $) {
90
+ assembly {
91
+ $.slot := STORAGE_LOCATION
92
+ }
168
93
  }
169
94
  }
@@ -15,177 +15,115 @@
15
15
  // limitations under the License.
16
16
  pragma solidity ^0.8.27;
17
17
 
18
- import {IZeto} from "./lib/interfaces/izeto.sol";
19
- import {Groth16Verifier_NfAnonNullifierTransfer} from "./verifiers/verifier_nf_anon_nullifier_transfer.sol";
20
- import {Groth16Verifier_NfAnonNullifierTransferLocked} from "./verifiers/verifier_nf_anon_nullifier_transferLocked.sol";
21
- import {ZetoNullifier} from "./lib/zeto_nullifier.sol";
22
- import {Commonlib} from "./lib/common.sol";
23
- import {IZetoInitializable} from "./lib/interfaces/izeto_initializable.sol";
18
+ import {ZetoNonFungibleNullifier} from "./lib/zeto_non_fungible_nullifier.sol";
19
+ import {Commonlib} from "./lib/common/common.sol";
20
+ import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
24
21
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
25
22
 
26
- /// @title A sample implementation of a Zeto based non-fungible token with anonymity and history masking
23
+ /// @title A sample implementation of a Zeto based non-fungible token with
24
+ /// anonymity and history masking via nullifiers.
27
25
  /// @author Kaleido, Inc.
26
+ /// @notice Decimals: this token uses **4** decimals, inherited from
27
+ /// {ZetoCommon.decimals}. NFT integrators rarely consult
28
+ /// `decimals()` but it is preserved for ABI symmetry with the
29
+ /// fungible siblings.
28
30
  /// @dev The proof has the following statements:
29
- /// - each value in the output commitments must be a positive number in the range 0 ~ (2\*\*40 - 1)
30
- /// - the sum of the nullified values match the sum of output values
31
- /// - the hashes in the input and output match the hash(value, salt, owner public key) formula
32
- /// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes, which match the corresponding nullifiers
33
- /// - the nullifiers represent input commitments that are included in a Sparse Merkle Tree represented by the root hash
34
- contract Zeto_NfAnonNullifier is
35
- IZeto,
36
- IZetoInitializable,
37
- ZetoNullifier,
38
- UUPSUpgradeable
39
- {
40
- Groth16Verifier_NfAnonNullifierTransfer _verifier;
41
- Groth16Verifier_NfAnonNullifierTransferLocked _lockVerifier;
31
+ /// - The sender owns the private key whose public key is part of the pre-image of the input UTXO commitment
32
+ /// (which corresponds to the nullifier).
33
+ /// - The nullifier represents an input commitment included in a Sparse Merkle Tree represented by the root hash.
34
+ /// - The output UTXO commitment is well-formed.
35
+ ///
36
+ /// Two public-inputs layouts are produced depending on whether the
37
+ /// transition is consuming an unlocked input (a nullifier proven
38
+ /// against the unlocked-commitments SMT) or a locked input (a raw
39
+ /// UTXO hash whose locked status is verified by the storage layer
40
+ /// itself):
41
+ /// - unlocked: `[nullifier, root, output]` -> verified by
42
+ /// {Groth16Verifier_NfAnonNullifierTransfer}.
43
+ /// - locked: `[input, output]` -> verified by the
44
+ /// simpler {Groth16Verifier_NfAnon}.
45
+ /// This mirrors how {Zeto_AnonNullifier} reuses the non-nullifier
46
+ /// verifier for its lock path. The locked branch does not require
47
+ /// a Merkle inclusion proof because the contract has already
48
+ /// validated the input via {NullifierStorage.validateInputs} (it
49
+ /// defers to {BaseStorage.validateInputs} when `inputsLocked`).
50
+ contract Zeto_NfAnonNullifier is ZetoNonFungibleNullifier, UUPSUpgradeable {
51
+ /// @dev Lock the implementation contract on construction.
52
+ /// @custom:oz-upgrades-unsafe-allow constructor
53
+ constructor() {
54
+ _disableInitializers();
55
+ }
42
56
 
43
57
  function initialize(
44
- string memory name,
45
- string memory symbol,
58
+ string calldata name,
59
+ string calldata symbol,
46
60
  address initialOwner,
47
61
  IZetoInitializable.VerifiersInfo calldata verifiers
48
62
  ) public initializer {
49
- __ZetoNullifier_init(name, symbol, initialOwner);
50
- _verifier = (Groth16Verifier_NfAnonNullifierTransfer)(
51
- verifiers.verifier
52
- );
53
- _lockVerifier = (Groth16Verifier_NfAnonNullifierTransferLocked)(
54
- verifiers.lockVerifier
55
- );
63
+ __ZetoNonFungibleNullifier_init(name, symbol, initialOwner, verifiers);
56
64
  }
57
65
 
58
66
  function _authorizeUpgrade(address) internal override onlyOwner {}
59
67
 
60
- /**
61
- * @dev the main function of the contract.
62
- *
63
- * @param nullifier A nullifier that are secretly bound to the UTXO to be spent by the transaction.
64
- * @param output new UTXO to generate, for future transactions to spend.
65
- * @param root The root hash of the Sparse Merkle Tree that contains the nullifier.
66
- * @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
67
- * that the outputs are valid in terms of obeying mass conservation rules.
68
- *
69
- * Emits a {UTXOTransfer} event.
70
- */
71
- function transfer(
72
- uint256 nullifier,
73
- uint256 output,
74
- uint256 root,
75
- Commonlib.Proof calldata proof,
76
- bytes calldata data
77
- ) public returns (bool) {
78
- uint256[] memory nullifiers = new uint256[](1);
79
- nullifiers[0] = nullifier;
80
- uint256[] memory outputs = new uint256[](1);
81
- outputs[0] = output;
82
- validateTransactionProposal(nullifiers, outputs, root, false);
83
- checkProof(nullifiers, outputs, root, proof);
84
- uint256[] memory empty;
85
- processInputsAndOutputs(nullifiers, outputs, empty, address(0));
86
-
87
- emit UTXOTransfer(nullifiers, outputs, msg.sender, data);
88
- return true;
89
- }
90
-
91
- /**
92
- * @dev the main function of the contract.
93
- *
94
- * @param nullifier A nullifier that are secretly bound to the UTXO to be spent by the transaction.
95
- * @param output new UTXO to generate, for future transactions to spend.
96
- * @param root The root hash of the Sparse Merkle Tree that contains the nullifier.
97
- * @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
98
- * that the outputs are valid in terms of obeying mass conservation rules.
99
- *
100
- * Emits a {UTXOTransfer} event.
101
- */
102
- function transferLocked(
103
- uint256 nullifier,
104
- uint256 output,
105
- uint256 root,
106
- Commonlib.Proof calldata proof,
107
- bytes calldata data
108
- ) public returns (bool) {
109
- uint256[] memory nullifiers = new uint256[](1);
110
- nullifiers[0] = nullifier;
111
- uint256[] memory outputs = new uint256[](1);
112
- outputs[0] = output;
113
- validateTransactionProposal(nullifiers, outputs, root, true);
114
- checkProofLocked(nullifiers, outputs, root, proof);
115
- uint256[] memory empty;
116
- processInputsAndOutputs(nullifiers, outputs, empty, address(0));
117
-
118
- emit UTXOTransfer(nullifiers, outputs, msg.sender, data);
119
- return true;
120
- }
121
-
122
- function mint(uint256[] memory utxos, bytes calldata data) public {
123
- _mint(utxos, data);
124
- }
125
-
126
- function lock(
127
- uint256 nullifier,
128
- uint256 lockedOutput,
129
- uint256 root,
130
- Commonlib.Proof calldata proof,
131
- address delegate,
132
- bytes calldata data
133
- ) public {
134
- uint256[] memory nullifiers = new uint256[](1);
135
- nullifiers[0] = nullifier;
136
- uint256[] memory lockedOutputs = new uint256[](1);
137
- lockedOutputs[0] = lockedOutput;
138
- validateTransactionProposal(nullifiers, lockedOutputs, root, false);
139
- checkProof(nullifiers, lockedOutputs, root, proof);
140
-
141
- processNullifiers(nullifiers);
142
-
143
- // lock the intended outputs
144
- uint256[] memory outputs;
145
- _lock(nullifiers, outputs, lockedOutputs, delegate, data);
146
- }
147
-
148
- function checkProof(
149
- uint256[] memory nullifiers,
68
+ /// @dev Public-inputs layout depends on `inputsLocked`:
69
+ /// - !inputsLocked: `[nullifier, root, output]` paired with the
70
+ /// `nf_anon_nullifier_transfer` circuit. The proof carries
71
+ /// `(uint256 root, Commonlib.Proof)`; the root is decoded
72
+ /// and validated here so that `validateTransactionProposal`
73
+ /// does not need to pre-decode the proof.
74
+ /// - inputsLocked: `[input, output]` paired with the simpler
75
+ /// `nf_anon` circuit. No root: the storage layer has
76
+ /// already verified the input is in `_lockedUtxos`, so we
77
+ /// do not re-prove inclusion in a locked-SMT. The proof
78
+ /// payload is just `Commonlib.Proof`.
79
+ function constructPublicInputs(
80
+ uint256[] memory inputs,
150
81
  uint256[] memory outputs,
151
- uint256 root,
152
- Commonlib.Proof calldata proof
153
- ) internal view {
154
- // construct the public inputs
155
- uint256[3] memory publicInputs;
156
- publicInputs[0] = nullifiers[0];
82
+ bytes memory proof,
83
+ bool inputsLocked
84
+ )
85
+ internal
86
+ view
87
+ override
88
+ returns (uint256[] memory, Commonlib.Proof memory)
89
+ {
90
+ if (inputsLocked) {
91
+ Commonlib.Proof memory proofStruct = abi.decode(
92
+ proof,
93
+ (Commonlib.Proof)
94
+ );
95
+ uint256[] memory publicInputs = new uint256[](2);
96
+ publicInputs[0] = inputs[0];
97
+ publicInputs[1] = outputs[0];
98
+ return (publicInputs, proofStruct);
99
+ }
100
+
101
+ (uint256 root, Commonlib.Proof memory proofStruct) = abi.decode(
102
+ proof,
103
+ (uint256, Commonlib.Proof)
104
+ );
105
+ validateRoot(root);
106
+
107
+ uint256[] memory publicInputs = new uint256[](3);
108
+ publicInputs[0] = inputs[0];
157
109
  publicInputs[1] = root;
158
110
  publicInputs[2] = outputs[0];
111
+ return (publicInputs, proofStruct);
112
+ }
113
+ }
159
114
 
160
- // Check the proof
161
- require(
162
- _verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
163
- "Invalid proof"
164
- );
115
+ /// @dev ERC-7201 (`erc7201:zeto.storage.Zeto_NfAnonNullifier`).
116
+ library Zeto_NfAnonNullifierStorage {
117
+ struct Layout {
118
+ uint256 __reserved;
165
119
  }
166
120
 
167
- function checkProofLocked(
168
- uint256[] memory nullifiers,
169
- uint256[] memory outputs,
170
- uint256 root,
171
- Commonlib.Proof calldata proof
172
- ) internal view {
173
- // construct the public inputs
174
- uint256[4] memory publicInputs;
175
- publicInputs[0] = nullifiers[0];
176
- publicInputs[1] = uint256(uint160(msg.sender));
177
- publicInputs[2] = root;
178
- publicInputs[3] = outputs[0];
121
+ bytes32 private constant STORAGE_LOCATION =
122
+ 0xb42e743e63c75bf1f2c05ab181e1371afad8f4114706ec6cfc12171a24893700;
179
123
 
180
- // Check the proof
181
- require(
182
- _lockVerifier.verifyProof(
183
- proof.pA,
184
- proof.pB,
185
- proof.pC,
186
- publicInputs
187
- ),
188
- "Invalid proof"
189
- );
124
+ function layout() internal pure returns (Layout storage $) {
125
+ assembly {
126
+ $.slot := STORAGE_LOCATION
127
+ }
190
128
  }
191
129
  }
package/hardhat.config.ts CHANGED
@@ -17,11 +17,13 @@
17
17
  import { HardhatUserConfig, vars } from "hardhat/config";
18
18
  import "@nomicfoundation/hardhat-toolbox";
19
19
  import "@openzeppelin/hardhat-upgrades";
20
+ import "hardhat-contract-sizer";
20
21
  import crypto from "crypto";
22
+ import { EIP170_EXEMPT_CONTRACTS } from "./config/eip170";
21
23
 
22
24
  const keys = [
23
- crypto.randomBytes(32).toString("hex"),
24
- crypto.randomBytes(32).toString("hex"),
25
+ process.env.ETH_PRIVATE_KEY_1 || crypto.randomBytes(32).toString("hex"),
26
+ process.env.ETH_PRIVATE_KEY_2 || crypto.randomBytes(32).toString("hex"),
25
27
  crypto.randomBytes(32).toString("hex"),
26
28
  crypto.randomBytes(32).toString("hex"),
27
29
  crypto.randomBytes(32).toString("hex"),
@@ -41,14 +43,27 @@ const config: HardhatUserConfig = {
41
43
  settings: {
42
44
  optimizer: {
43
45
  enabled: true,
44
- runs: 1000,
46
+ runs: 25,
45
47
  },
48
+ viaIR: true,
46
49
  },
47
50
  },
48
51
  paths: {
49
52
  sources: "contracts"
50
53
  },
54
+ contractSizer: {
55
+ alphaSort: true,
56
+ runOnCompile: true,
57
+ strict: true,
58
+ except: [...EIP170_EXEMPT_CONTRACTS],
59
+ },
51
60
  networks: {
61
+ hardhat: {
62
+ // EIP-170 runtime limit is enforced for non-exempt tokens in deployZeto().
63
+ // Must be true here so exempt oversize implementations can deploy in tests:
64
+ // hardhat_reset does not reliably toggle allowUnlimitedContractSize (HH 2.26+).
65
+ allowUnlimitedContractSize: true,
66
+ },
52
67
  besu: {
53
68
  url: "http://localhost:8545",
54
69
  accounts: keys,
@@ -27,6 +27,11 @@ export const SmtLibModule = buildModule("SmtLib", (m) => {
27
27
  return { smtLib, poseidon2, poseidon3, poseidon5, poseidon6 };
28
28
  });
29
29
 
30
+ export const ZetoLockableLibModule = buildModule("ZetoLockableLib", (m) => {
31
+ const zetoLockableLib = m.library("ZetoLockableLib", []);
32
+ return { zetoLockableLib };
33
+ });
34
+
30
35
  export const DepositVerifierModule = buildModule(
31
36
  "Groth16Verifier_Deposit",
32
37
  (m) => {
@@ -35,6 +40,14 @@ export const DepositVerifierModule = buildModule(
35
40
  },
36
41
  );
37
42
 
43
+ export const DepositKycVerifierModule = buildModule(
44
+ "Groth16Verifier_DepositKyc",
45
+ (m) => {
46
+ const verifier = m.contract("Groth16Verifier_DepositKyc", []);
47
+ return { verifier };
48
+ },
49
+ );
50
+
38
51
  export const WithdrawNullifierVerifierModule = buildModule(
39
52
  "Groth16Verifier_WithdrawNullifier",
40
53
  (m) => {
@@ -15,8 +15,14 @@
15
15
  // limitations under the License.
16
16
 
17
17
  import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
18
+ import { ZetoLockableLibModule } from "../lib/deps";
18
19
 
19
20
  export default buildModule("TenDecimals", (m) => {
20
- const tendecimals = m.contract("TenDecimals", []);
21
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
22
+ const tendecimals = m.contract("TenDecimals", [], {
23
+ libraries: {
24
+ ZetoLockableLib: zetoLockableLib,
25
+ },
26
+ });
21
27
  return { tendecimals };
22
28
  });
@@ -19,6 +19,7 @@ import {
19
19
  DepositVerifierModule,
20
20
  WithdrawVerifierModule,
21
21
  BatchWithdrawVerifierModule,
22
+ ZetoLockableLibModule,
22
23
  } from "./lib/deps";
23
24
 
24
25
  const VerifierModule = buildModule("Groth16Verifier_Anon", (m) => {
@@ -32,6 +33,7 @@ const BatchVerifierModule = buildModule("Groth16Verifier_AnonBatch", (m) => {
32
33
  });
33
34
 
34
35
  export default buildModule("Zeto_Anon", (m) => {
36
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
35
37
  const { verifier } = m.useModule(VerifierModule);
36
38
  const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
37
39
  const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
@@ -45,5 +47,6 @@ export default buildModule("Zeto_Anon", (m) => {
45
47
  verifier,
46
48
  batchVerifier,
47
49
  batchWithdrawVerifier,
50
+ zetoLockableLib,
48
51
  };
49
52
  });
@@ -19,6 +19,7 @@ import {
19
19
  DepositVerifierModule,
20
20
  WithdrawVerifierModule,
21
21
  BatchWithdrawVerifierModule,
22
+ ZetoLockableLibModule,
22
23
  } from "./lib/deps";
23
24
 
24
25
  const VerifierModule = buildModule("Groth16Verifier_Anon", (m) => {
@@ -36,12 +37,16 @@ const BurnVerifierModule = buildModule("Groth16Verifier_Burn", (m) => {
36
37
  return { verifier };
37
38
  });
38
39
 
39
- const BatchBurnVerifierModule = buildModule("Groth16Verifier_BurnBatch", (m) => {
40
- const verifier = m.contract("Groth16Verifier_BurnBatch", []);
41
- return { verifier };
42
- });
40
+ const BatchBurnVerifierModule = buildModule(
41
+ "Groth16Verifier_BurnBatch",
42
+ (m) => {
43
+ const verifier = m.contract("Groth16Verifier_BurnBatch", []);
44
+ return { verifier };
45
+ },
46
+ );
43
47
 
44
48
  export default buildModule("Zeto_AnonBurnable", (m) => {
49
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
45
50
  const { verifier } = m.useModule(VerifierModule);
46
51
  const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
47
52
  const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
@@ -50,9 +55,7 @@ export default buildModule("Zeto_AnonBurnable", (m) => {
50
55
  BatchWithdrawVerifierModule,
51
56
  );
52
57
  const { verifier: burnVerifier } = m.useModule(BurnVerifierModule);
53
- const { verifier: batchBurnVerifier } = m.useModule(
54
- BatchBurnVerifierModule,
55
- );
58
+ const { verifier: batchBurnVerifier } = m.useModule(BatchBurnVerifierModule);
56
59
  return {
57
60
  depositVerifier,
58
61
  withdrawVerifier,
@@ -61,5 +64,6 @@ export default buildModule("Zeto_AnonBurnable", (m) => {
61
64
  batchVerifier,
62
65
  batchWithdrawVerifier,
63
66
  batchBurnVerifier,
67
+ zetoLockableLib,
64
68
  };
65
69
  });
@@ -19,6 +19,7 @@ import {
19
19
  DepositVerifierModule,
20
20
  WithdrawVerifierModule,
21
21
  BatchWithdrawVerifierModule,
22
+ ZetoLockableLibModule,
22
23
  } from "./lib/deps";
23
24
 
24
25
  const VerifierModule = buildModule("Groth16Verifier_AnonEnc", (m) => {
@@ -32,6 +33,7 @@ const BatchVerifierModule = buildModule("Groth16Verifier_AnonEncBatch", (m) => {
32
33
  });
33
34
 
34
35
  export default buildModule("Zeto_AnonEnc", (m) => {
36
+ const { zetoLockableLib } = m.useModule(ZetoLockableLibModule);
35
37
  const { verifier } = m.useModule(VerifierModule);
36
38
  const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
37
39
  const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
@@ -45,5 +47,6 @@ export default buildModule("Zeto_AnonEnc", (m) => {
45
47
  verifier,
46
48
  batchVerifier,
47
49
  batchWithdrawVerifier,
50
+ zetoLockableLib,
48
51
  };
49
52
  });