@cofhe/sdk 0.6.0 → 0.7.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/CHANGELOG.md +49 -0
- package/acps/acp.ts +411 -0
- package/acps/index.ts +70 -0
- package/{permits → acps}/onchain-utils.ts +49 -24
- package/acps/sealing.ts +90 -0
- package/acps/signature.ts +89 -0
- package/acps/store.ts +172 -0
- package/acps/test/acp.test.ts +615 -0
- package/acps/test/localstorage.test.ts +105 -0
- package/acps/test/sealing.test.ts +77 -0
- package/acps/test/store.test.ts +88 -0
- package/acps/test/validation.test.ts +361 -0
- package/acps/test-utils.ts +32 -0
- package/acps/types.ts +252 -0
- package/acps/validation.ts +392 -0
- package/adapters/test/ethers5.test.ts +4 -1
- package/adapters/test/ethers6.test.ts +4 -1
- package/adapters/test/wagmi.test.ts +5 -2
- package/chains/chains/stagingCofhe.ts +21 -0
- package/chains/index.ts +3 -1
- package/chains/test/chains.test.ts +2 -1
- package/core/acps.ts +625 -0
- package/core/client.ts +136 -39
- package/core/clientTypes.ts +52 -41
- package/core/config.ts +66 -5
- package/core/debug.ts +72 -0
- package/core/decrypt/MockThresholdNetworkAbi.ts +20 -11
- package/core/decrypt/apiError.ts +104 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
- package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
- package/core/decrypt/decryptForTxBuilder.ts +102 -102
- package/core/decrypt/decryptForViewBuilder.ts +90 -90
- package/core/decrypt/submitRetry.ts +38 -30
- package/core/decrypt/tnDecryptV1.ts +5 -5
- package/core/decrypt/tnDecryptV2.ts +45 -34
- package/core/decrypt/tnSealOutputV1.ts +4 -3
- package/core/decrypt/tnSealOutputV2.ts +44 -31
- package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
- package/core/encrypt/encryptInputsBuilder.ts +86 -52
- package/core/encrypt/zkPackProveVerify.ts +25 -18
- package/core/error.ts +34 -6
- package/core/index.ts +14 -14
- package/core/test/acpDefaults.test.ts +52 -0
- package/core/test/acps.test.ts +596 -0
- package/core/test/apiError.test.ts +130 -0
- package/core/test/client.test.ts +22 -19
- package/core/test/config.test.ts +25 -5
- package/core/test/decrypt.test.ts +40 -35
- package/core/test/decryptBuilders.test.ts +68 -68
- package/core/test/decryptErrorCodes.test.ts +217 -0
- package/core/test/encryptInputsBuilder.test.ts +72 -41
- package/core/test/pollCallbacks.test.ts +89 -18
- package/core/test/stagingRedirect.ts +18 -0
- package/core/test/submitRetry.test.ts +182 -0
- package/core/types.ts +9 -69
- package/dist/acp-Wi6isVQI.d.cts +407 -0
- package/dist/acp-Wi6isVQI.d.ts +407 -0
- package/dist/acps.cjs +1081 -0
- package/dist/acps.d.cts +480 -0
- package/dist/acps.d.ts +480 -0
- package/dist/acps.js +2 -0
- package/dist/chains.cjs +14 -1
- package/dist/chains.d.cts +30 -1
- package/dist/chains.d.ts +30 -1
- package/dist/chains.js +1 -1
- package/dist/{chunk-PE5V5CCV.js → chunk-43USWPEH.js} +1000 -604
- package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
- package/dist/chunk-Q7CBWGQX.js +1029 -0
- package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
- package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
- package/dist/core.cjs +1431 -1026
- package/dist/core.d.cts +55 -10
- package/dist/core.d.ts +55 -10
- package/dist/core.js +3 -3
- package/dist/node.cjs +1356 -976
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +3 -3
- package/dist/web.cjs +1356 -976
- package/dist/web.d.cts +2 -2
- package/dist/web.d.ts +2 -2
- package/dist/web.js +3 -3
- package/node/test/inherited.test.ts +75 -65
- package/node/test/tfheinit.test.ts +23 -8
- package/package.json +6 -6
- package/web/test/client.web.test.ts +5 -1
- package/web/test/inherited.web.test.ts +75 -65
- package/web/test/tfheinit.web.test.ts +14 -5
- package/web/test/worker.config.web.test.ts +38 -23
- package/web/test/worker.output.web.test.ts +25 -24
- package/core/encrypt/encryptUtils.ts +0 -67
- package/core/permits.ts +0 -206
- package/core/test/permits.test.ts +0 -534
- package/dist/chunk-VB62WYPL.js +0 -978
- package/dist/permit-DnVMDT5h.d.cts +0 -376
- package/dist/permit-DnVMDT5h.d.ts +0 -376
- package/dist/permits.cjs +0 -1026
- package/dist/permits.d.cts +0 -353
- package/dist/permits.d.ts +0 -353
- package/dist/permits.js +0 -2
- package/permits/index.ts +0 -68
- package/permits/permit.ts +0 -385
- package/permits/sealing.ts +0 -131
- package/permits/signature.ts +0 -79
- package/permits/store.ts +0 -157
- package/permits/test/localstorage.test.ts +0 -113
- package/permits/test/permit.test.ts +0 -557
- package/permits/test/sealing.test.ts +0 -84
- package/permits/test/store.test.ts +0 -88
- package/permits/test/validation.test.ts +0 -361
- package/permits/test-utils.ts +0 -28
- package/permits/types.ts +0 -204
- package/permits/validation.ts +0 -327
- /package/{permits → acps}/utils.ts +0 -0
|
@@ -47,8 +47,8 @@ const parseWithBigInt = (str: string): any =>
|
|
|
47
47
|
|
|
48
48
|
// packMetadata function removed as it's no longer needed
|
|
49
49
|
const unpackMetadata = (metadata: string) => {
|
|
50
|
-
const [signer, securityZone, chainId] = metadata.split('-');
|
|
51
|
-
return { signer, securityZone: parseInt(securityZone), chainId: parseInt(chainId) };
|
|
50
|
+
const [signer, securityZone, chainId, contractAddr] = metadata.split('-');
|
|
51
|
+
return { signer, securityZone: parseInt(securityZone), chainId: parseInt(chainId), contractAddr };
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
export const deconstructZkPoKMetadata = (
|
|
@@ -125,17 +125,19 @@ const MockCrs = {
|
|
|
125
125
|
safe_serialize: (_serializedSizeLimit: bigint) => new Uint8Array(),
|
|
126
126
|
};
|
|
127
127
|
|
|
128
|
-
// Setup fetch mock for http://localhost:3001/
|
|
129
|
-
// Simulates verification of zk proof
|
|
130
|
-
//
|
|
131
|
-
//
|
|
128
|
+
// Setup fetch mock for http://localhost:3001/verifyBatch
|
|
129
|
+
// Simulates batch verification of a zk proof: one signature covering the whole batch.
|
|
130
|
+
// The signature is `${account_addr}-${security_zone}-${chain_id}-${contract_address}-` (a debug
|
|
131
|
+
// string, not a real signature) so tests can recover the request payload that was sent for a
|
|
132
|
+
// given result. Expects the proof to be created by the MockZkListBuilder `build_with_proof_packed`
|
|
133
|
+
// above
|
|
132
134
|
const mockFetch = vi.fn();
|
|
133
135
|
global.fetch = mockFetch;
|
|
134
136
|
const setupZkVerifyMock = () => {
|
|
135
137
|
mockFetch.mockImplementation((url: string, options: any) => {
|
|
136
|
-
if (url === `${MockZkVerifierUrl}/
|
|
138
|
+
if (url === `${MockZkVerifierUrl}/verifyBatch`) {
|
|
137
139
|
const body = JSON.parse(options.body as string);
|
|
138
|
-
const { packed_list, account_addr, security_zone, chain_id } = body;
|
|
140
|
+
const { packed_list, account_addr, security_zone, chain_id, contract_address } = body;
|
|
139
141
|
|
|
140
142
|
// Decode the proof data
|
|
141
143
|
const arr = fromHexString(packed_list);
|
|
@@ -143,11 +145,10 @@ const setupZkVerifyMock = () => {
|
|
|
143
145
|
const decodedData = parseWithBigInt(decoded);
|
|
144
146
|
const { items } = decodedData;
|
|
145
147
|
|
|
146
|
-
// Create mock verify
|
|
147
|
-
const
|
|
148
|
+
// Create a mock batch verify result: per-item ct_hash/ct_type, and one shared signature
|
|
149
|
+
const ciphertexts = items.map((item: EncryptableItem) => ({
|
|
148
150
|
ct_hash: BigInt(item.data).toString(),
|
|
149
|
-
|
|
150
|
-
recid: 0,
|
|
151
|
+
ct_type: item.utype,
|
|
151
152
|
}));
|
|
152
153
|
|
|
153
154
|
return Promise.resolve({
|
|
@@ -155,7 +156,11 @@ const setupZkVerifyMock = () => {
|
|
|
155
156
|
json: () =>
|
|
156
157
|
Promise.resolve({
|
|
157
158
|
status: 'success',
|
|
158
|
-
data:
|
|
159
|
+
data: {
|
|
160
|
+
ciphertexts,
|
|
161
|
+
signature: `${account_addr}-${security_zone}-${chain_id}-${contract_address}-`,
|
|
162
|
+
recid: 0,
|
|
163
|
+
},
|
|
159
164
|
error: null,
|
|
160
165
|
}),
|
|
161
166
|
});
|
|
@@ -232,6 +237,7 @@ class MockZkProvenList {
|
|
|
232
237
|
describe('EncryptInputsBuilder', () => {
|
|
233
238
|
const defaultSender = '0x1234567890123456789012345678901234567890';
|
|
234
239
|
const defaultChainId = 1;
|
|
240
|
+
const defaultConsumingContract = '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef';
|
|
235
241
|
const createDefaultParams = () => {
|
|
236
242
|
return {
|
|
237
243
|
inputs: [Encryptable.uint128(100n)] as [EncryptableUint128],
|
|
@@ -260,6 +266,7 @@ describe('EncryptInputsBuilder', () => {
|
|
|
260
266
|
setupZkVerifyMock();
|
|
261
267
|
insertMockKeys(defaultChainId, 0);
|
|
262
268
|
builder = new EncryptInputsBuilder(createDefaultParams());
|
|
269
|
+
builder.setConsumingContract(defaultConsumingContract);
|
|
263
270
|
});
|
|
264
271
|
|
|
265
272
|
describe('constructor and initialization', () => {
|
|
@@ -320,7 +327,9 @@ describe('EncryptInputsBuilder', () => {
|
|
|
320
327
|
await new EncryptInputsBuilder({
|
|
321
328
|
...createDefaultParams(),
|
|
322
329
|
initTfhe: vi.fn().mockRejectedValue(new Error('Failed to initialize TFHE')),
|
|
323
|
-
})
|
|
330
|
+
})
|
|
331
|
+
.setConsumingContract(defaultConsumingContract)
|
|
332
|
+
.execute();
|
|
324
333
|
} catch (error) {
|
|
325
334
|
expect(error).toBeInstanceOf(CofheError);
|
|
326
335
|
expect((error as CofheError).code).toBe(CofheErrorCode.InitTfheFailed);
|
|
@@ -331,7 +340,9 @@ describe('EncryptInputsBuilder', () => {
|
|
|
331
340
|
const result = await new EncryptInputsBuilder({
|
|
332
341
|
...createDefaultParams(),
|
|
333
342
|
initTfhe: mockInitTfhe,
|
|
334
|
-
})
|
|
343
|
+
})
|
|
344
|
+
.setConsumingContract(defaultConsumingContract)
|
|
345
|
+
.execute();
|
|
335
346
|
expect(result).toBeDefined();
|
|
336
347
|
});
|
|
337
348
|
});
|
|
@@ -417,6 +428,25 @@ describe('EncryptInputsBuilder', () => {
|
|
|
417
428
|
});
|
|
418
429
|
});
|
|
419
430
|
|
|
431
|
+
describe('setConsumingContract', () => {
|
|
432
|
+
it('should set consuming contract and return builder for chaining', () => {
|
|
433
|
+
const contract = '0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead';
|
|
434
|
+
const result = builder.setConsumingContract(contract);
|
|
435
|
+
expect(result).toBe(builder);
|
|
436
|
+
expect(result.getConsumingContract()).toBe(contract);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it('should throw an error if consumingContract is not set', async () => {
|
|
440
|
+
try {
|
|
441
|
+
await new EncryptInputsBuilder(createDefaultParams()).execute();
|
|
442
|
+
expect.unreachable('execute() should have thrown');
|
|
443
|
+
} catch (error) {
|
|
444
|
+
expect(error).toBeInstanceOf(CofheError);
|
|
445
|
+
expect((error as CofheError).code).toBe(CofheErrorCode.ConsumingContractUninitialized);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
|
|
420
450
|
describe('zkVerifierUrl', () => {
|
|
421
451
|
it('should throw if zkVerifierUrl is not set', async () => {
|
|
422
452
|
try {
|
|
@@ -426,7 +456,9 @@ describe('EncryptInputsBuilder', () => {
|
|
|
426
456
|
account: '0x1234567890123456789012345678901234567890',
|
|
427
457
|
chainId: 1,
|
|
428
458
|
config: createMockCofheConfig(defaultChainId, undefined as unknown as string),
|
|
429
|
-
})
|
|
459
|
+
})
|
|
460
|
+
.setConsumingContract(defaultConsumingContract)
|
|
461
|
+
.execute();
|
|
430
462
|
} catch (error) {
|
|
431
463
|
expect(error).toBeInstanceOf(CofheError);
|
|
432
464
|
expect((error as CofheError).code).toBe(CofheErrorCode.ZkVerifierUrlUninitialized);
|
|
@@ -555,8 +587,8 @@ describe('EncryptInputsBuilder', () => {
|
|
|
555
587
|
expect(Array.isArray(result)).toBe(true);
|
|
556
588
|
|
|
557
589
|
// Verify result embedded metadata
|
|
558
|
-
const [
|
|
559
|
-
const encryptedMetadata = unpackMetadata(
|
|
590
|
+
const signature = result[result.length - 1] as string;
|
|
591
|
+
const encryptedMetadata = unpackMetadata(signature);
|
|
560
592
|
expect(encryptedMetadata).toBeDefined();
|
|
561
593
|
expect(encryptedMetadata.signer).toBe(defaultSender);
|
|
562
594
|
expect(encryptedMetadata.securityZone).toBe(0);
|
|
@@ -570,8 +602,8 @@ describe('EncryptInputsBuilder', () => {
|
|
|
570
602
|
const result = await builder.execute();
|
|
571
603
|
|
|
572
604
|
// Verify result embedded metadata
|
|
573
|
-
const [
|
|
574
|
-
const encryptedMetadata = unpackMetadata(
|
|
605
|
+
const signature = result[result.length - 1] as string;
|
|
606
|
+
const encryptedMetadata = unpackMetadata(signature);
|
|
575
607
|
expect(encryptedMetadata).toBeDefined();
|
|
576
608
|
expect(encryptedMetadata.signer).toBe(overriddenSender);
|
|
577
609
|
expect(encryptedMetadata.securityZone).toBe(0);
|
|
@@ -587,8 +619,8 @@ describe('EncryptInputsBuilder', () => {
|
|
|
587
619
|
const result = await builder.execute();
|
|
588
620
|
|
|
589
621
|
// Verify result embedded metadata
|
|
590
|
-
const [
|
|
591
|
-
const encryptedMetadata = unpackMetadata(
|
|
622
|
+
const signature = result[result.length - 1] as string;
|
|
623
|
+
const encryptedMetadata = unpackMetadata(signature);
|
|
592
624
|
expect(encryptedMetadata).toBeDefined();
|
|
593
625
|
expect(encryptedMetadata.signer).toBe(defaultSender);
|
|
594
626
|
expect(encryptedMetadata.securityZone).toBe(overriddenZone);
|
|
@@ -612,6 +644,7 @@ describe('EncryptInputsBuilder', () => {
|
|
|
612
644
|
ReturnType<typeof Encryptable.bool>,
|
|
613
645
|
],
|
|
614
646
|
});
|
|
647
|
+
multiInputBuilder.setConsumingContract(defaultConsumingContract);
|
|
615
648
|
|
|
616
649
|
const result = await multiInputBuilder.execute();
|
|
617
650
|
|
|
@@ -645,7 +678,9 @@ describe('EncryptInputsBuilder', () => {
|
|
|
645
678
|
Encryptable.uint128(100n),
|
|
646
679
|
Encryptable.uint128(100n),
|
|
647
680
|
],
|
|
648
|
-
})
|
|
681
|
+
})
|
|
682
|
+
.setConsumingContract(defaultConsumingContract)
|
|
683
|
+
.execute();
|
|
649
684
|
} catch (error) {
|
|
650
685
|
expect(error).toBeInstanceOf(CofheError);
|
|
651
686
|
expect((error as CofheError).code).toBe(CofheErrorCode.ZkPackFailed);
|
|
@@ -702,8 +737,8 @@ describe('EncryptInputsBuilder', () => {
|
|
|
702
737
|
expect(stepCallback).toHaveBeenCalledTimes(10);
|
|
703
738
|
|
|
704
739
|
// Verify result embedded metadata
|
|
705
|
-
const [
|
|
706
|
-
const encryptedMetadata = unpackMetadata(
|
|
740
|
+
const signature = result[result.length - 1] as string;
|
|
741
|
+
const encryptedMetadata = unpackMetadata(signature);
|
|
707
742
|
expect(encryptedMetadata).toBeDefined();
|
|
708
743
|
expect(encryptedMetadata.signer).toBe(sender);
|
|
709
744
|
expect(encryptedMetadata.securityZone).toBe(securityZone);
|
|
@@ -727,16 +762,16 @@ describe('EncryptInputsBuilder', () => {
|
|
|
727
762
|
expect(result2).toBeDefined();
|
|
728
763
|
|
|
729
764
|
// Verify result embedded metadata
|
|
730
|
-
const [
|
|
731
|
-
const encryptedMetadata1 = unpackMetadata(
|
|
765
|
+
const signature1 = result1[result1.length - 1] as string;
|
|
766
|
+
const encryptedMetadata1 = unpackMetadata(signature1);
|
|
732
767
|
expect(encryptedMetadata1).toBeDefined();
|
|
733
768
|
expect(encryptedMetadata1.signer).toBe(sender);
|
|
734
769
|
expect(encryptedMetadata1.securityZone).toBe(securityZone);
|
|
735
770
|
expect(encryptedMetadata1.chainId).toBe(defaultChainId);
|
|
736
771
|
|
|
737
772
|
// Verify result embedded metadata
|
|
738
|
-
const [
|
|
739
|
-
const encryptedMetadata2 = unpackMetadata(
|
|
773
|
+
const signature2 = result2[result2.length - 1] as string;
|
|
774
|
+
const encryptedMetadata2 = unpackMetadata(signature2);
|
|
740
775
|
expect(encryptedMetadata2).toBeDefined();
|
|
741
776
|
expect(encryptedMetadata2.signer).toBe(sender);
|
|
742
777
|
expect(encryptedMetadata2.securityZone).toBe(securityZone);
|
|
@@ -744,18 +779,14 @@ describe('EncryptInputsBuilder', () => {
|
|
|
744
779
|
});
|
|
745
780
|
});
|
|
746
781
|
|
|
747
|
-
describe('
|
|
748
|
-
it('
|
|
749
|
-
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
it('execute() returns [hash, proof] for a single input', async () => {
|
|
753
|
-
const result = await builder.asHashPlusProof().execute();
|
|
782
|
+
describe('execute() batch result shape', () => {
|
|
783
|
+
it('execute() returns [hash, signature] for a single input', async () => {
|
|
784
|
+
const result = await builder.execute();
|
|
754
785
|
expect(Array.isArray(result)).toBe(true);
|
|
755
|
-
expect(result).toHaveLength(2); // 1 hash + 1
|
|
786
|
+
expect(result).toHaveLength(2); // 1 hash + 1 signature
|
|
756
787
|
});
|
|
757
788
|
|
|
758
|
-
it('execute() returns [hash1, hash2,
|
|
789
|
+
it('execute() returns [hash1, hash2, signature] for two inputs', async () => {
|
|
759
790
|
const result = await new EncryptInputsBuilder({
|
|
760
791
|
...createDefaultParams(),
|
|
761
792
|
inputs: [Encryptable.uint128(100n), Encryptable.bool(true)] as [
|
|
@@ -763,16 +794,16 @@ describe('EncryptInputsBuilder', () => {
|
|
|
763
794
|
ReturnType<typeof Encryptable.bool>,
|
|
764
795
|
],
|
|
765
796
|
})
|
|
766
|
-
.
|
|
797
|
+
.setConsumingContract(defaultConsumingContract)
|
|
767
798
|
.execute();
|
|
768
799
|
|
|
769
800
|
expect(Array.isArray(result)).toBe(true);
|
|
770
|
-
expect(result).toHaveLength(3); // 2 hashes + 1
|
|
801
|
+
expect(result).toHaveLength(3); // 2 hashes + 1 signature
|
|
771
802
|
});
|
|
772
803
|
|
|
773
804
|
it('should be composable with other builder methods', async () => {
|
|
774
805
|
const overriddenSender = '0x5555555555555555555555555555555555555555';
|
|
775
|
-
const result = await builder.
|
|
806
|
+
const result = await builder.setAccount(overriddenSender).execute();
|
|
776
807
|
|
|
777
808
|
expect(Array.isArray(result)).toBe(true);
|
|
778
809
|
expect(result).toHaveLength(2);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
2
|
import { tnDecryptV2 } from '../decrypt/tnDecryptV2.js';
|
|
3
3
|
import { tnSealOutputV2 } from '../decrypt/tnSealOutputV2.js';
|
|
4
|
+
import { CofheErrorCode } from '../error.js';
|
|
4
5
|
|
|
5
6
|
const makeMockResponse = (opts: { ok: boolean; status?: number; statusText?: string; json: () => Promise<any> }) => {
|
|
6
7
|
return {
|
|
@@ -70,7 +71,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
70
71
|
const promise = tnDecryptV2({
|
|
71
72
|
ctHash: 1n,
|
|
72
73
|
chainId: 1,
|
|
73
|
-
|
|
74
|
+
acp: null,
|
|
74
75
|
thresholdNetworkUrl,
|
|
75
76
|
onPoll,
|
|
76
77
|
});
|
|
@@ -153,7 +154,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
153
154
|
const promise = tnDecryptV2({
|
|
154
155
|
ctHash: 1n,
|
|
155
156
|
chainId: 1,
|
|
156
|
-
|
|
157
|
+
acp: null,
|
|
157
158
|
thresholdNetworkUrl,
|
|
158
159
|
onPoll,
|
|
159
160
|
});
|
|
@@ -201,7 +202,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
201
202
|
ok: false,
|
|
202
203
|
status: 404,
|
|
203
204
|
statusText: 'Not Found',
|
|
204
|
-
json: async () => ({
|
|
205
|
+
json: async () => ({ error: 'ct_not_found', error_message: 'ciphertext not indexed yet' }),
|
|
205
206
|
});
|
|
206
207
|
}
|
|
207
208
|
|
|
@@ -233,7 +234,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
233
234
|
const promise = tnDecryptV2({
|
|
234
235
|
ctHash: 1n,
|
|
235
236
|
chainId: 1,
|
|
236
|
-
|
|
237
|
+
acp: null,
|
|
237
238
|
thresholdNetworkUrl,
|
|
238
239
|
onPoll,
|
|
239
240
|
});
|
|
@@ -275,7 +276,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
275
276
|
ok: false,
|
|
276
277
|
status: 404,
|
|
277
278
|
statusText: 'Not Found',
|
|
278
|
-
json: async () => ({
|
|
279
|
+
json: async () => ({ error: 'ct_not_found', error_message: 'ciphertext not indexed yet' }),
|
|
279
280
|
});
|
|
280
281
|
}
|
|
281
282
|
|
|
@@ -287,12 +288,47 @@ describe('decrypt polling callbacks', () => {
|
|
|
287
288
|
const promise = tnDecryptV2({
|
|
288
289
|
ctHash: 1n,
|
|
289
290
|
chainId: 1,
|
|
290
|
-
|
|
291
|
+
acp: null,
|
|
291
292
|
thresholdNetworkUrl,
|
|
292
293
|
});
|
|
293
294
|
|
|
294
295
|
const rejection = expect(promise).rejects.toMatchObject({
|
|
295
|
-
|
|
296
|
+
code: CofheErrorCode.CtNotFound,
|
|
297
|
+
apiErrorCode: 'ct_not_found',
|
|
298
|
+
message: 'decrypt ciphertext not found after retrying for 10000ms: ciphertext not indexed yet',
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
await vi.advanceTimersByTimeAsync(11_000);
|
|
302
|
+
await rejection;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('tnDecryptV2 retries any 404 and times out with the last error message', async () => {
|
|
306
|
+
const fetchMock = vi.fn(async (url: string, options?: any) => {
|
|
307
|
+
if (url === `${thresholdNetworkUrl}/v2/decrypt` && options?.method === 'POST') {
|
|
308
|
+
return makeMockResponse({
|
|
309
|
+
ok: false,
|
|
310
|
+
status: 404,
|
|
311
|
+
statusText: 'Not Found',
|
|
312
|
+
json: async () => ({ error: 'acp_denied', error_message: 'acp was rejected' }),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
throw new Error(`Unexpected fetch: ${url}`);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
global.fetch = fetchMock as any;
|
|
320
|
+
|
|
321
|
+
const promise = tnDecryptV2({
|
|
322
|
+
ctHash: 1n,
|
|
323
|
+
chainId: 1,
|
|
324
|
+
acp: null,
|
|
325
|
+
thresholdNetworkUrl,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const rejection = expect(promise).rejects.toMatchObject({
|
|
329
|
+
code: CofheErrorCode.CtNotFound,
|
|
330
|
+
apiErrorCode: 'ct_not_found',
|
|
331
|
+
message: 'decrypt ciphertext not found after retrying for 10000ms: acp was rejected',
|
|
296
332
|
});
|
|
297
333
|
|
|
298
334
|
await vi.advanceTimersByTimeAsync(11_000);
|
|
@@ -324,7 +360,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
324
360
|
const result = await tnDecryptV2({
|
|
325
361
|
ctHash: 1n,
|
|
326
362
|
chainId: 1,
|
|
327
|
-
|
|
363
|
+
acp: null,
|
|
328
364
|
thresholdNetworkUrl,
|
|
329
365
|
onPoll,
|
|
330
366
|
});
|
|
@@ -379,7 +415,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
379
415
|
const promise = tnDecryptV2({
|
|
380
416
|
ctHash: 1n,
|
|
381
417
|
chainId: 1,
|
|
382
|
-
|
|
418
|
+
acp: null,
|
|
383
419
|
thresholdNetworkUrl,
|
|
384
420
|
onPoll,
|
|
385
421
|
});
|
|
@@ -450,7 +486,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
450
486
|
const promise = tnSealOutputV2({
|
|
451
487
|
ctHash: 1n,
|
|
452
488
|
chainId: 1,
|
|
453
|
-
|
|
489
|
+
acp: {} as any,
|
|
454
490
|
thresholdNetworkUrl,
|
|
455
491
|
onPoll,
|
|
456
492
|
});
|
|
@@ -534,7 +570,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
534
570
|
const promise = tnSealOutputV2({
|
|
535
571
|
ctHash: 1n,
|
|
536
572
|
chainId: 1,
|
|
537
|
-
|
|
573
|
+
acp: {} as any,
|
|
538
574
|
thresholdNetworkUrl,
|
|
539
575
|
onPoll,
|
|
540
576
|
});
|
|
@@ -582,7 +618,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
582
618
|
ok: false,
|
|
583
619
|
status: 404,
|
|
584
620
|
statusText: 'Not Found',
|
|
585
|
-
json: async () => ({
|
|
621
|
+
json: async () => ({ error: 'ct_not_found', error_message: 'ciphertext not indexed yet' }),
|
|
586
622
|
});
|
|
587
623
|
}
|
|
588
624
|
|
|
@@ -617,7 +653,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
617
653
|
const promise = tnSealOutputV2({
|
|
618
654
|
ctHash: 1n,
|
|
619
655
|
chainId: 1,
|
|
620
|
-
|
|
656
|
+
acp: {} as any,
|
|
621
657
|
thresholdNetworkUrl,
|
|
622
658
|
onPoll,
|
|
623
659
|
});
|
|
@@ -659,7 +695,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
659
695
|
ok: false,
|
|
660
696
|
status: 404,
|
|
661
697
|
statusText: 'Not Found',
|
|
662
|
-
json: async () => ({
|
|
698
|
+
json: async () => ({ error: 'ct_not_found', error_message: 'ciphertext not indexed yet' }),
|
|
663
699
|
});
|
|
664
700
|
}
|
|
665
701
|
|
|
@@ -671,19 +707,54 @@ describe('decrypt polling callbacks', () => {
|
|
|
671
707
|
const promise = tnSealOutputV2({
|
|
672
708
|
ctHash: 1n,
|
|
673
709
|
chainId: 1,
|
|
674
|
-
|
|
710
|
+
acp: {} as any,
|
|
675
711
|
thresholdNetworkUrl,
|
|
676
712
|
retry404TimeoutMs: 2000,
|
|
677
713
|
});
|
|
678
714
|
|
|
679
715
|
const rejection = expect(promise).rejects.toMatchObject({
|
|
680
|
-
|
|
716
|
+
code: CofheErrorCode.CtNotFound,
|
|
717
|
+
apiErrorCode: 'ct_not_found',
|
|
718
|
+
message: 'sealOutput ciphertext not found after retrying for 2000ms: ciphertext not indexed yet',
|
|
681
719
|
});
|
|
682
720
|
|
|
683
721
|
await vi.advanceTimersByTimeAsync(3000);
|
|
684
722
|
await rejection;
|
|
685
723
|
});
|
|
686
724
|
|
|
725
|
+
it('tnSealOutputV2 retries any 404 and times out with the last error message', async () => {
|
|
726
|
+
const fetchMock = vi.fn(async (url: string, options?: any) => {
|
|
727
|
+
if (url === `${thresholdNetworkUrl}/v2/sealoutput` && options?.method === 'POST') {
|
|
728
|
+
return makeMockResponse({
|
|
729
|
+
ok: false,
|
|
730
|
+
status: 404,
|
|
731
|
+
statusText: 'Not Found',
|
|
732
|
+
json: async () => ({ error: 'acp_denied', error_message: 'acp was rejected' }),
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
throw new Error(`Unexpected fetch: ${url}`);
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
global.fetch = fetchMock as any;
|
|
740
|
+
|
|
741
|
+
const promise = tnSealOutputV2({
|
|
742
|
+
ctHash: 1n,
|
|
743
|
+
chainId: 1,
|
|
744
|
+
acp: {} as any,
|
|
745
|
+
thresholdNetworkUrl,
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
const rejection = expect(promise).rejects.toMatchObject({
|
|
749
|
+
code: CofheErrorCode.CtNotFound,
|
|
750
|
+
apiErrorCode: 'ct_not_found',
|
|
751
|
+
message: 'sealOutput ciphertext not found after retrying for 10000ms: acp was rejected',
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
await vi.advanceTimersByTimeAsync(11_000);
|
|
755
|
+
await rejection;
|
|
756
|
+
});
|
|
757
|
+
|
|
687
758
|
it('tnSealOutputV2 returns immediately when submit responds with cached completed payload', async () => {
|
|
688
759
|
const onPoll = vi.fn();
|
|
689
760
|
|
|
@@ -710,7 +781,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
710
781
|
const sealed = await tnSealOutputV2({
|
|
711
782
|
ctHash: 1n,
|
|
712
783
|
chainId: 1,
|
|
713
|
-
|
|
784
|
+
acp: {} as any,
|
|
714
785
|
thresholdNetworkUrl,
|
|
715
786
|
onPoll,
|
|
716
787
|
});
|
|
@@ -766,7 +837,7 @@ describe('decrypt polling callbacks', () => {
|
|
|
766
837
|
const promise = tnSealOutputV2({
|
|
767
838
|
ctHash: 1n,
|
|
768
839
|
chainId: 1,
|
|
769
|
-
|
|
840
|
+
acp: {} as any,
|
|
770
841
|
thresholdNetworkUrl,
|
|
771
842
|
onPoll,
|
|
772
843
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineChain } from 'viem';
|
|
2
|
+
import { STAGING_RPC_URL } from '@cofhe/test-setup';
|
|
3
|
+
|
|
4
|
+
declare const __STAGING_TESTS__: boolean | undefined;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* When TEST_STAGING_ENABLED=true, the sdk tests that exercise live CoFHE
|
|
8
|
+
* backends run against the staging environment instead of their default
|
|
9
|
+
* chain (the primary test chain / hardcoded testnets). Off: unchanged.
|
|
10
|
+
*/
|
|
11
|
+
export const STAGING_TESTS = typeof __STAGING_TESTS__ !== 'undefined' ? __STAGING_TESTS__ : false;
|
|
12
|
+
|
|
13
|
+
export const stagingViemChain = defineChain({
|
|
14
|
+
id: 420105,
|
|
15
|
+
name: 'CoFHE Staging',
|
|
16
|
+
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
|
17
|
+
rpcUrls: { default: { http: [STAGING_RPC_URL] } },
|
|
18
|
+
});
|