@lfdecentralizedtrust/zeto-contracts 0.2.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -162
- 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/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 +451 -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 +613 -0
- package/contracts/lib/zeto_non_fungible.sol +236 -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 +9 -3
- package/ignition/modules/lib/deps.ts +8 -0
- package/ignition/modules/zeto_anon_burnable.ts +8 -7
- package/ignition/modules/zeto_anon_enc_nullifier.ts +31 -0
- package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +2 -2
- package/ignition/modules/zeto_anon_nullifier.ts +28 -4
- package/ignition/modules/zeto_anon_nullifier_burnable.ts +50 -16
- package/ignition/modules/zeto_anon_nullifier_kyc.ts +27 -12
- package/ignition/modules/zeto_nf_anon_nullifier.ts +14 -10
- package/package.json +4 -2
- package/scripts/deploy_cloneable.ts +19 -10
- package/scripts/deploy_upgradeable.ts +9 -5
- package/scripts/tokens/Zeto_Anon.ts +3 -3
- package/scripts/tokens/Zeto_AnonBurnable.ts +1 -1
- package/scripts/tokens/Zeto_AnonEnc.ts +12 -3
- package/scripts/tokens/Zeto_AnonEncNullifier.ts +5 -3
- package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +1 -1
- package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifier.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifierKyc.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +1 -1
- package/scripts/tokens/Zeto_NfAnon.ts +2 -2
- package/scripts/tokens/Zeto_NfAnonNullifier.ts +1 -1
- package/test/factory.ts +46 -73
- package/test/lib/anon_nullifier_helpers.ts +89 -0
- package/test/lib/anon_zeto_helpers.ts +76 -0
- package/test/lib/deploy.ts +3 -2
- 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 -26
- package/test/utils.ts +144 -21
- package/test/zeto_anon.ts +956 -465
- package/test/zeto_anon_enc.ts +881 -142
- package/test/zeto_anon_enc_nullifier.ts +847 -38
- package/test/zeto_anon_enc_nullifier_kyc.ts +120 -181
- package/test/zeto_anon_enc_nullifier_non_repudiation.ts +77 -46
- package/test/zeto_anon_nullifier.ts +1212 -953
- package/test/zeto_anon_nullifier_kyc.ts +674 -655
- package/test/zeto_anon_nullifier_qurrency.ts +452 -306
- package/test/zeto_nf_anon.ts +737 -137
- package/test/zeto_nf_anon_nullifier.ts +876 -246
- 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
package/test/test/escrow1.ts
CHANGED
|
@@ -15,11 +15,16 @@
|
|
|
15
15
|
// limitations under the License.
|
|
16
16
|
|
|
17
17
|
import { ethers, ignition, network } from "hardhat";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
Signer,
|
|
20
|
+
AbiCoder,
|
|
21
|
+
BigNumberish,
|
|
22
|
+
ContractTransactionReceipt,
|
|
23
|
+
} from "ethers";
|
|
19
24
|
import { expect } from "chai";
|
|
20
|
-
import { loadCircuit
|
|
25
|
+
import { loadCircuit } from "zeto-js";
|
|
21
26
|
import zkEscrowModule from "../../ignition/modules/test/escrow1";
|
|
22
|
-
import
|
|
27
|
+
import { prepareProof } from "../lib/anon_zeto_helpers";
|
|
23
28
|
import {
|
|
24
29
|
UTXO,
|
|
25
30
|
User,
|
|
@@ -27,11 +32,36 @@ import {
|
|
|
27
32
|
newUTXO,
|
|
28
33
|
doMint,
|
|
29
34
|
ZERO_UTXO,
|
|
30
|
-
|
|
35
|
+
logger,
|
|
31
36
|
} from "../lib/utils";
|
|
32
37
|
import { loadProvingKeys } from "../utils";
|
|
33
38
|
import { deployZeto } from "../lib/deploy";
|
|
34
39
|
|
|
40
|
+
// ABI fragments for the ZetoLockableCapability *Args payloads.
|
|
41
|
+
// These mirror the canonical encodings used by every Zeto token that
|
|
42
|
+
// implements ILockableCapability.
|
|
43
|
+
const CREATE_ARGS_ABI =
|
|
44
|
+
"tuple(bytes32 txId, uint256[] inputs, uint256[] outputs, uint256[] lockedOutputs, bytes proof)";
|
|
45
|
+
const DELEGATE_ARGS_ABI = "tuple(bytes32 txId)";
|
|
46
|
+
|
|
47
|
+
function encodeCreateArgs(args: {
|
|
48
|
+
txId: string;
|
|
49
|
+
inputs: BigNumberish[];
|
|
50
|
+
outputs: BigNumberish[];
|
|
51
|
+
lockedOutputs: BigNumberish[];
|
|
52
|
+
proof: string;
|
|
53
|
+
}) {
|
|
54
|
+
return new AbiCoder().encode([CREATE_ARGS_ABI], [args]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function encodeDelegateArgs(txId: string) {
|
|
58
|
+
return new AbiCoder().encode([DELEGATE_ARGS_ABI], [{ txId }]);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function randomBytes32(): string {
|
|
62
|
+
return ethers.hexlify(ethers.randomBytes(32));
|
|
63
|
+
}
|
|
64
|
+
|
|
35
65
|
describe("Escrow flow for payment with Zeto_Anon", function () {
|
|
36
66
|
let Alice: User;
|
|
37
67
|
let Bob: User;
|
|
@@ -48,6 +78,7 @@ describe("Escrow flow for payment with Zeto_Anon", function () {
|
|
|
48
78
|
// UTXOs involved in the escrow flow
|
|
49
79
|
let lockedPayment1: UTXO;
|
|
50
80
|
let paymentToBob: UTXO;
|
|
81
|
+
let lockId: string;
|
|
51
82
|
|
|
52
83
|
// other variables
|
|
53
84
|
let deployer: Signer;
|
|
@@ -66,11 +97,15 @@ describe("Escrow flow for payment with Zeto_Anon", function () {
|
|
|
66
97
|
Bob = await newUser(b);
|
|
67
98
|
Charlie = await newUser(c);
|
|
68
99
|
|
|
100
|
+
// The Zeto_Anon token uses the same `anon` circuit for both regular
|
|
101
|
+
// transfers and the locked-input branch (the lockVerifier is wired
|
|
102
|
+
// to Groth16Verifier_Anon in the ignition module). One circuit/key
|
|
103
|
+
// pair therefore covers both the createLock and spendLock proofs.
|
|
69
104
|
circuit = await loadCircuit("anon");
|
|
70
105
|
({ provingKeyFile: provingKey } = loadProvingKeys("anon"));
|
|
71
106
|
|
|
72
107
|
({ deployer, zeto: zkPayment } = await deployZeto("Zeto_Anon"));
|
|
73
|
-
|
|
108
|
+
logger.debug(`ZK Payment contract deployed at ${zkPayment.target}`);
|
|
74
109
|
({ zkEscrow } = await ignition.deploy(zkEscrowModule, {
|
|
75
110
|
parameters: {
|
|
76
111
|
zkEscrow1: {
|
|
@@ -85,62 +120,101 @@ describe("Escrow flow for payment with Zeto_Anon", function () {
|
|
|
85
120
|
payment2 = newUTXO(20, Alice);
|
|
86
121
|
const result = await doMint(zkPayment, deployer, [payment1, payment2]);
|
|
87
122
|
|
|
88
|
-
// simulate Alice and Bob listening to minting events and updating
|
|
123
|
+
// simulate Alice and Bob listening to minting events and updating
|
|
124
|
+
// their local merkle trees
|
|
89
125
|
for (const log of result.logs) {
|
|
90
126
|
const event = zkPayment.interface.parseLog(log as any);
|
|
91
127
|
expect(event.args.outputs.length).to.equal(2);
|
|
92
128
|
}
|
|
93
129
|
});
|
|
94
130
|
|
|
95
|
-
it("Alice locks
|
|
131
|
+
it("Alice locks payment1 by calling createLock on the Zeto token", async function () {
|
|
132
|
+
// The locked output preserves the value but is a fresh commitment
|
|
133
|
+
// (new salt). The createLock proof attests to the standard transfer
|
|
134
|
+
// payment1 -> lockedPayment1.
|
|
96
135
|
lockedPayment1 = newUTXO(payment1.value!, Alice);
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
136
|
+
const encodedZkProof = await prepareProof(
|
|
137
|
+
circuit,
|
|
138
|
+
provingKey,
|
|
139
|
+
Alice,
|
|
140
|
+
[payment1, ZERO_UTXO],
|
|
141
|
+
[lockedPayment1, ZERO_UTXO],
|
|
142
|
+
[Alice, {}],
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const createArgs = encodeCreateArgs({
|
|
146
|
+
txId: randomBytes32(),
|
|
147
|
+
inputs: [payment1.hash],
|
|
148
|
+
// For the fungible Zeto_Anon createLock, lockedOutputs holds the
|
|
149
|
+
// freshly-locked UTXO and outputs is empty (no change is being
|
|
150
|
+
// returned to Alice, since payment1's full value is moved into
|
|
151
|
+
// the lock).
|
|
152
|
+
outputs: [],
|
|
153
|
+
lockedOutputs: [lockedPayment1.hash],
|
|
154
|
+
proof: encodeProofOnly(encodedZkProof),
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Pre-compute the lockId off-chain to assert the contract derives
|
|
158
|
+
// the same value (deterministic from caller + txId).
|
|
159
|
+
lockId = await zkPayment.connect(Alice.signer).computeLockId(createArgs);
|
|
160
|
+
|
|
161
|
+
const tx = await zkPayment
|
|
162
|
+
.connect(Alice.signer)
|
|
163
|
+
.createLock(createArgs, ethers.ZeroHash, ethers.ZeroHash, "0x");
|
|
164
|
+
const result: ContractTransactionReceipt | null = await tx.wait();
|
|
165
|
+
logger.debug(`createLock() complete. Gas used: ${result?.gasUsed}`);
|
|
166
|
+
|
|
167
|
+
// Sanity-check the lock state after creation.
|
|
168
|
+
const info = await zkPayment.getLock(lockId);
|
|
169
|
+
expect(info.owner).to.equal(Alice.ethAddress);
|
|
170
|
+
expect(info.spender).to.equal(Alice.ethAddress);
|
|
171
|
+
expect(await zkPayment.locked(lockedPayment1.hash)).to.deep.equal([
|
|
172
|
+
true,
|
|
173
|
+
Alice.ethAddress,
|
|
174
|
+
]);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("Alice delegates the lock to the escrow contract", async function () {
|
|
106
178
|
const tx = await zkPayment
|
|
107
179
|
.connect(Alice.signer)
|
|
108
|
-
.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
outputCommitments,
|
|
112
|
-
encodedProof,
|
|
180
|
+
.delegateLock(
|
|
181
|
+
lockId,
|
|
182
|
+
encodeDelegateArgs(randomBytes32()),
|
|
113
183
|
zkEscrow.target,
|
|
114
184
|
"0x",
|
|
115
185
|
);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
//
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
186
|
+
await tx.wait();
|
|
187
|
+
|
|
188
|
+
// After delegation the escrow is the sole spender; Alice can no
|
|
189
|
+
// longer spend the lock directly.
|
|
190
|
+
const info = await zkPayment.getLock(lockId);
|
|
191
|
+
expect(info.spender).to.equal(zkEscrow.target);
|
|
192
|
+
expect(await zkPayment.locked(lockedPayment1.hash)).to.deep.equal([
|
|
193
|
+
true,
|
|
194
|
+
zkEscrow.target,
|
|
195
|
+
]);
|
|
126
196
|
});
|
|
127
197
|
|
|
128
198
|
it("Alice initiates a payment transaction to Bob through the escrow", async function () {
|
|
129
|
-
paymentToBob = newUTXO(lockedPayment1.value!, Bob
|
|
199
|
+
paymentToBob = newUTXO(lockedPayment1.value!, Bob);
|
|
130
200
|
const tx = await zkEscrow
|
|
131
201
|
.connect(Alice.signer)
|
|
132
|
-
.initiatePayment(
|
|
202
|
+
.initiatePayment(lockId, [paymentToBob.hash], "0x");
|
|
133
203
|
const result = await tx.wait();
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
204
|
+
const initiated = parseEscrowEvent(zkEscrow, result, "PaymentInitiated");
|
|
205
|
+
expect(initiated, "PaymentInitiated event not emitted").to.not.be.undefined;
|
|
206
|
+
|
|
207
|
+
// Bob listens to the payment events and verifies the proposed
|
|
208
|
+
// payment matches what Alice promised off-chain.
|
|
209
|
+
expect(initiated!.outputs[0]).to.equal(paymentToBob.hash);
|
|
210
|
+
expect(initiated!.lockId).to.equal(lockId);
|
|
211
|
+
paymentId = initiated!.paymentId;
|
|
140
212
|
});
|
|
141
213
|
|
|
142
|
-
it("Alice approves the payment by submitting a valid proof
|
|
143
|
-
|
|
214
|
+
it("Alice approves the payment by submitting a valid locked-input proof", async function () {
|
|
215
|
+
// The spend proof transfers lockedPayment1 -> paymentToBob (now
|
|
216
|
+
// owned by Bob). Same `anon` circuit as the createLock step.
|
|
217
|
+
const encodedZkProof = await prepareProof(
|
|
144
218
|
circuit,
|
|
145
219
|
provingKey,
|
|
146
220
|
Alice,
|
|
@@ -150,29 +224,82 @@ describe("Escrow flow for payment with Zeto_Anon", function () {
|
|
|
150
224
|
);
|
|
151
225
|
const tx = await zkEscrow
|
|
152
226
|
.connect(Alice.signer)
|
|
153
|
-
.approvePayment(paymentId,
|
|
227
|
+
.approvePayment(paymentId, encodeProofOnly(encodedZkProof), "0x");
|
|
154
228
|
const result = await tx.wait();
|
|
155
|
-
|
|
156
|
-
// the escrow
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
229
|
+
|
|
230
|
+
// Bob listens to the escrow's PaymentApproved event; the escrow
|
|
231
|
+
// having stored the proof guarantees completePayment cannot fail
|
|
232
|
+
// on proof grounds later.
|
|
233
|
+
const approved = parseEscrowEvent(zkEscrow, result, "PaymentApproved");
|
|
234
|
+
expect(approved, "PaymentApproved event not emitted").to.not.be.undefined;
|
|
235
|
+
expect(approved!.paymentId).to.equal(paymentId);
|
|
160
236
|
});
|
|
161
237
|
|
|
162
|
-
it("Bob, or anyone, can call the escrow to finalize the payment and receive the
|
|
238
|
+
it("Bob, or anyone, can call the escrow to finalize the payment and receive the unlocked UTXO", async function () {
|
|
163
239
|
const tx = await zkEscrow
|
|
164
240
|
.connect(Bob.signer)
|
|
165
241
|
.completePayment(paymentId, "0x");
|
|
166
242
|
const result = await tx.wait();
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
243
|
+
|
|
244
|
+
// The Zeto token emits ZetoLockSpent containing the new unlocked
|
|
245
|
+
// outputs.
|
|
246
|
+
const lockSpent = result!.logs
|
|
247
|
+
.map((l) => {
|
|
248
|
+
try {
|
|
249
|
+
return zkPayment.interface.parseLog(l as any);
|
|
250
|
+
} catch (_e) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
.find((p: any) => p && p.name === "ZetoLockSpent");
|
|
255
|
+
expect(lockSpent, "ZetoLockSpent event not emitted").to.not.be.undefined;
|
|
256
|
+
expect(lockSpent!.args.outputs[0]).to.equal(paymentToBob.hash);
|
|
257
|
+
|
|
258
|
+
// Lock is consumed; the locked-UTXO ledger no longer carries
|
|
259
|
+
// lockedPayment1.
|
|
260
|
+
expect(await zkPayment.isLockActive(lockId)).to.equal(false);
|
|
261
|
+
expect((await zkPayment.locked(lockedPayment1.hash))[0]).to.be.false;
|
|
262
|
+
|
|
263
|
+
// Escrow's PaymentCompleted event fires for the same paymentId.
|
|
264
|
+
const completed = parseEscrowEvent(zkEscrow, result, "PaymentCompleted");
|
|
265
|
+
expect(completed, "PaymentCompleted event not emitted").to.not.be.undefined;
|
|
266
|
+
expect(completed!.paymentId).to.equal(paymentId);
|
|
177
267
|
});
|
|
178
268
|
});
|
|
269
|
+
|
|
270
|
+
// parseEscrowEvent extracts the first event of a given name from a
|
|
271
|
+
// transaction receipt by parsing logs through the escrow contract's
|
|
272
|
+
// own ABI. Unlike `parseUTXOEvents`, which only knows about the Zeto
|
|
273
|
+
// token's UTXO event family, this helper handles the escrow's
|
|
274
|
+
// custom Payment* events.
|
|
275
|
+
function parseEscrowEvent(
|
|
276
|
+
escrowContract: any,
|
|
277
|
+
receipt: ContractTransactionReceipt | null,
|
|
278
|
+
name: string,
|
|
279
|
+
): any | undefined {
|
|
280
|
+
if (!receipt) return undefined;
|
|
281
|
+
for (const log of receipt.logs || []) {
|
|
282
|
+
let parsed;
|
|
283
|
+
try {
|
|
284
|
+
parsed = escrowContract.interface.parseLog(log as any);
|
|
285
|
+
} catch (_e) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (parsed && parsed.name === name) {
|
|
289
|
+
// Return the args Result directly; ethers exposes named fields
|
|
290
|
+
// (e.g. result.paymentId) alongside positional ones.
|
|
291
|
+
return parsed.args;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// encodeProofOnly mirrors the wire format that
|
|
298
|
+
// {Zeto_Anon.constructPublicInputs} expects: a bare `Commonlib.Proof`
|
|
299
|
+
// tuple (no merkle root prefix, since Zeto_Anon is non-nullifier).
|
|
300
|
+
function encodeProofOnly(proof: any) {
|
|
301
|
+
return new AbiCoder().encode(
|
|
302
|
+
["tuple(uint256[2] pA, uint256[2][2] pB, uint256[2] pC)"],
|
|
303
|
+
[proof],
|
|
304
|
+
);
|
|
305
|
+
}
|