@cofhe/sdk 0.1.0 → 0.2.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 +62 -0
- package/adapters/ethers5.test.ts +174 -0
- package/adapters/ethers5.ts +36 -0
- package/adapters/ethers6.test.ts +169 -0
- package/adapters/ethers6.ts +36 -0
- package/adapters/hardhat-node.ts +167 -0
- package/adapters/hardhat.hh2.test.ts +159 -0
- package/adapters/hardhat.ts +36 -0
- package/adapters/index.test.ts +20 -0
- package/adapters/index.ts +5 -0
- package/adapters/smartWallet.ts +99 -0
- package/adapters/test-utils.ts +53 -0
- package/adapters/types.ts +6 -0
- package/adapters/wagmi.test.ts +156 -0
- package/adapters/wagmi.ts +17 -0
- package/chains/chains/arbSepolia.ts +14 -0
- package/chains/chains/baseSepolia.ts +14 -0
- package/chains/chains/hardhat.ts +15 -0
- package/chains/chains/localcofhe.ts +14 -0
- package/chains/chains/sepolia.ts +14 -0
- package/chains/chains.test.ts +50 -0
- package/chains/defineChain.ts +18 -0
- package/chains/index.ts +35 -0
- package/chains/types.ts +32 -0
- package/core/baseBuilder.ts +119 -0
- package/core/client.test.ts +315 -0
- package/core/client.ts +292 -0
- package/core/clientTypes.ts +108 -0
- package/core/config.test.ts +235 -0
- package/core/config.ts +220 -0
- package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
- package/core/decrypt/cofheMocksSealOutput.ts +57 -0
- package/core/decrypt/decryptHandleBuilder.ts +287 -0
- package/core/decrypt/decryptUtils.ts +28 -0
- package/core/decrypt/tnSealOutputV1.ts +59 -0
- package/core/decrypt/tnSealOutputV2.ts +298 -0
- package/core/encrypt/MockZkVerifierAbi.ts +106 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +284 -0
- package/core/encrypt/encryptInputsBuilder.test.ts +751 -0
- package/core/encrypt/encryptInputsBuilder.ts +560 -0
- package/core/encrypt/encryptUtils.ts +67 -0
- package/core/encrypt/zkPackProveVerify.ts +335 -0
- package/core/error.ts +168 -0
- package/core/fetchKeys.test.ts +195 -0
- package/core/fetchKeys.ts +144 -0
- package/core/index.ts +89 -0
- package/core/keyStore.test.ts +226 -0
- package/core/keyStore.ts +154 -0
- package/core/permits.test.ts +494 -0
- package/core/permits.ts +200 -0
- package/core/types.ts +398 -0
- package/core/utils.ts +130 -0
- package/dist/adapters.cjs +88 -0
- package/dist/adapters.d.cts +14576 -0
- package/dist/adapters.d.ts +14576 -0
- package/dist/adapters.js +83 -0
- package/dist/chains.cjs +114 -0
- package/dist/chains.d.cts +121 -0
- package/dist/chains.d.ts +121 -0
- package/dist/chains.js +1 -0
- package/dist/chunk-UGBVZNRT.js +818 -0
- package/dist/chunk-WEAZ25JO.js +105 -0
- package/dist/chunk-WGCRJCBR.js +2523 -0
- package/dist/clientTypes-5_1nwtUe.d.cts +914 -0
- package/dist/clientTypes-Es7fyi65.d.ts +914 -0
- package/dist/core.cjs +3414 -0
- package/dist/core.d.cts +111 -0
- package/dist/core.d.ts +111 -0
- package/dist/core.js +3 -0
- package/dist/node.cjs +3286 -0
- package/dist/node.d.cts +22 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +91 -0
- package/dist/permit-fUSe6KKq.d.cts +349 -0
- package/dist/permit-fUSe6KKq.d.ts +349 -0
- package/dist/permits.cjs +871 -0
- package/dist/permits.d.cts +1045 -0
- package/dist/permits.d.ts +1045 -0
- package/dist/permits.js +1 -0
- package/dist/types-KImPrEIe.d.cts +48 -0
- package/dist/types-KImPrEIe.d.ts +48 -0
- package/dist/web.cjs +3478 -0
- package/dist/web.d.cts +38 -0
- package/dist/web.d.ts +38 -0
- package/dist/web.js +240 -0
- package/dist/zkProve.worker.cjs +93 -0
- package/dist/zkProve.worker.d.cts +2 -0
- package/dist/zkProve.worker.d.ts +2 -0
- package/dist/zkProve.worker.js +91 -0
- package/node/client.test.ts +147 -0
- package/node/config.test.ts +68 -0
- package/node/encryptInputs.test.ts +155 -0
- package/node/index.ts +97 -0
- package/node/storage.ts +51 -0
- package/package.json +27 -15
- package/permits/index.ts +68 -0
- package/permits/localstorage.test.ts +117 -0
- package/permits/permit.test.ts +477 -0
- package/permits/permit.ts +405 -0
- package/permits/sealing.test.ts +84 -0
- package/permits/sealing.ts +131 -0
- package/permits/signature.ts +79 -0
- package/permits/store.test.ts +128 -0
- package/permits/store.ts +166 -0
- package/permits/test-utils.ts +20 -0
- package/permits/types.ts +191 -0
- package/permits/utils.ts +62 -0
- package/permits/validation.test.ts +288 -0
- package/permits/validation.ts +369 -0
- package/web/client.web.test.ts +147 -0
- package/web/config.web.test.ts +69 -0
- package/web/encryptInputs.web.test.ts +172 -0
- package/web/index.ts +161 -0
- package/web/storage.ts +34 -0
- package/web/worker.builder.web.test.ts +148 -0
- package/web/worker.config.web.test.ts +329 -0
- package/web/worker.output.web.test.ts +84 -0
- package/web/workerManager.test.ts +80 -0
- package/web/workerManager.ts +214 -0
- package/web/workerManager.web.test.ts +114 -0
- package/web/zkProve.worker.ts +133 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { sepolia, arbSepolia, baseSepolia, hardhat, chains, getChainById, getChainByName } from './index.js';
|
|
3
|
+
|
|
4
|
+
describe('Chains', () => {
|
|
5
|
+
it('should export all chains', () => {
|
|
6
|
+
expect(Object.keys(chains)).toHaveLength(5);
|
|
7
|
+
expect(chains).toHaveProperty('sepolia');
|
|
8
|
+
expect(chains).toHaveProperty('arbSepolia');
|
|
9
|
+
expect(chains).toHaveProperty('baseSepolia');
|
|
10
|
+
expect(chains).toHaveProperty('hardhat');
|
|
11
|
+
expect(chains).toHaveProperty('localcofhe');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should have correct chain configurations', () => {
|
|
15
|
+
expect(sepolia.id).toBe(11155111);
|
|
16
|
+
expect(sepolia.name).toBe('Sepolia');
|
|
17
|
+
expect(sepolia.environment).toBe('TESTNET');
|
|
18
|
+
|
|
19
|
+
expect(hardhat.id).toBe(31337);
|
|
20
|
+
expect(hardhat.name).toBe('Hardhat');
|
|
21
|
+
expect(hardhat.environment).toBe('MOCK');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should find chains by ID', () => {
|
|
25
|
+
expect(getChainById(11155111)).toBe(sepolia);
|
|
26
|
+
expect(getChainById(31337)).toBe(hardhat);
|
|
27
|
+
expect(getChainById(999999)).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should find chains by name', () => {
|
|
31
|
+
expect(getChainByName('sepolia')).toBe(sepolia);
|
|
32
|
+
expect(getChainByName('Sepolia')).toBe(sepolia);
|
|
33
|
+
expect(getChainByName('hardhat')).toBe(hardhat);
|
|
34
|
+
expect(getChainByName('nonexistent')).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should validate chain properties', () => {
|
|
38
|
+
const allChains = [sepolia, arbSepolia, baseSepolia, hardhat];
|
|
39
|
+
|
|
40
|
+
allChains.forEach((chain) => {
|
|
41
|
+
expect(typeof chain.id).toBe('number');
|
|
42
|
+
expect(typeof chain.name).toBe('string');
|
|
43
|
+
expect(typeof chain.network).toBe('string');
|
|
44
|
+
expect(typeof chain.coFheUrl).toBe('string');
|
|
45
|
+
expect(typeof chain.verifierUrl).toBe('string');
|
|
46
|
+
expect(typeof chain.thresholdNetworkUrl).toBe('string');
|
|
47
|
+
expect(['MOCK', 'TESTNET', 'MAINNET']).toContain(chain.environment);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CofheChainSchema, type CofheChain } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Defines and validates a CofheChain configuration
|
|
5
|
+
* @param chainConfig - The chain configuration object to validate
|
|
6
|
+
* @returns The validated chain configuration unchanged
|
|
7
|
+
* @throws {Error} If the chain configuration is invalid
|
|
8
|
+
*/
|
|
9
|
+
export function defineChain(chainConfig: CofheChain): CofheChain {
|
|
10
|
+
const result = CofheChainSchema.safeParse(chainConfig);
|
|
11
|
+
|
|
12
|
+
if (!result.success) {
|
|
13
|
+
const errorMessages = result.error.errors.map((err) => `${err.path.join('.')}: ${err.message}`);
|
|
14
|
+
throw new Error(`Invalid chain configuration: ${errorMessages.join(', ')}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return result.data;
|
|
18
|
+
}
|
package/chains/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Export types
|
|
2
|
+
export type { CofheChain, Environment } from './types.js';
|
|
3
|
+
|
|
4
|
+
// Import and export individual chains
|
|
5
|
+
import { sepolia } from './chains/sepolia.js';
|
|
6
|
+
import { arbSepolia } from './chains/arbSepolia.js';
|
|
7
|
+
import { baseSepolia } from './chains/baseSepolia.js';
|
|
8
|
+
import { hardhat } from './chains/hardhat.js';
|
|
9
|
+
import { localcofhe } from './chains/localcofhe.js';
|
|
10
|
+
|
|
11
|
+
export { sepolia, arbSepolia, baseSepolia, hardhat, localcofhe };
|
|
12
|
+
|
|
13
|
+
// Export all chains as a collection
|
|
14
|
+
export const chains = {
|
|
15
|
+
sepolia,
|
|
16
|
+
arbSepolia,
|
|
17
|
+
baseSepolia,
|
|
18
|
+
hardhat,
|
|
19
|
+
localcofhe,
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
// Import CofheChain type for helper functions
|
|
23
|
+
import type { CofheChain } from './types.js';
|
|
24
|
+
|
|
25
|
+
// Export chain by ID helper
|
|
26
|
+
export const getChainById = (chainId: number): CofheChain | undefined => {
|
|
27
|
+
return Object.values(chains).find((chain) => chain.id === chainId);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Export chain by name helper
|
|
31
|
+
export const getChainByName = (name: string): CofheChain | undefined => {
|
|
32
|
+
return Object.values(chains).find(
|
|
33
|
+
(chain) => chain.name.toLowerCase() === name.toLowerCase() || chain.network.toLowerCase() === name.toLowerCase()
|
|
34
|
+
);
|
|
35
|
+
};
|
package/chains/types.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Environment schema for @cofhe/sdk chains
|
|
5
|
+
*/
|
|
6
|
+
export const EnvironmentSchema = z.enum(['MOCK', 'TESTNET', 'MAINNET']);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Zod schema for CofheChain validation
|
|
10
|
+
*/
|
|
11
|
+
export const CofheChainSchema = z.object({
|
|
12
|
+
/** Chain ID */
|
|
13
|
+
id: z.number().int().positive(),
|
|
14
|
+
/** Human-readable chain name */
|
|
15
|
+
name: z.string().min(1),
|
|
16
|
+
/** Network identifier */
|
|
17
|
+
network: z.string().min(1),
|
|
18
|
+
/** coFhe service URL */
|
|
19
|
+
coFheUrl: z.string().url(),
|
|
20
|
+
/** Verifier service URL */
|
|
21
|
+
verifierUrl: z.string().url(),
|
|
22
|
+
/** Threshold network service URL */
|
|
23
|
+
thresholdNetworkUrl: z.string().url(),
|
|
24
|
+
/** Environment type */
|
|
25
|
+
environment: EnvironmentSchema,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Type inference from the schema
|
|
30
|
+
*/
|
|
31
|
+
export type CofheChain = z.infer<typeof CofheChainSchema>;
|
|
32
|
+
export type Environment = z.infer<typeof EnvironmentSchema>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { type PublicClient, type WalletClient } from 'viem';
|
|
2
|
+
import { type CofhesdkConfig } from './config.js';
|
|
3
|
+
import { CofhesdkError, CofhesdkErrorCode } from './error.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base parameters that all builders need
|
|
7
|
+
*/
|
|
8
|
+
export type BaseBuilderParams = {
|
|
9
|
+
config: CofhesdkConfig | undefined;
|
|
10
|
+
publicClient: PublicClient | undefined;
|
|
11
|
+
walletClient: WalletClient | undefined;
|
|
12
|
+
|
|
13
|
+
chainId: number | undefined;
|
|
14
|
+
account: string | undefined;
|
|
15
|
+
|
|
16
|
+
requireConnected: (() => void) | undefined;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Abstract base class for builders that provides common functionality
|
|
21
|
+
* for working with clients, config, and chain IDs
|
|
22
|
+
*/
|
|
23
|
+
export abstract class BaseBuilder {
|
|
24
|
+
protected config: CofhesdkConfig;
|
|
25
|
+
|
|
26
|
+
protected publicClient: PublicClient | undefined;
|
|
27
|
+
protected walletClient: WalletClient | undefined;
|
|
28
|
+
|
|
29
|
+
protected chainId: number | undefined;
|
|
30
|
+
protected account: string | undefined;
|
|
31
|
+
|
|
32
|
+
constructor(params: BaseBuilderParams) {
|
|
33
|
+
// Check that config is provided
|
|
34
|
+
if (!params.config) {
|
|
35
|
+
throw new CofhesdkError({
|
|
36
|
+
code: CofhesdkErrorCode.MissingConfig,
|
|
37
|
+
message: 'Builder config is undefined',
|
|
38
|
+
hint: 'Ensure client has been created with a config.',
|
|
39
|
+
context: {
|
|
40
|
+
config: params.config,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
this.config = params.config;
|
|
45
|
+
|
|
46
|
+
this.publicClient = params.publicClient;
|
|
47
|
+
this.walletClient = params.walletClient;
|
|
48
|
+
|
|
49
|
+
this.chainId = params.chainId;
|
|
50
|
+
this.account = params.account;
|
|
51
|
+
|
|
52
|
+
// Require the client to be connected if passed as param
|
|
53
|
+
params.requireConnected?.();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Asserts that this.chainId is populated
|
|
58
|
+
* @throws {CofhesdkError} If chainId is not set
|
|
59
|
+
*/
|
|
60
|
+
protected assertChainId(): asserts this is this & { chainId: number } {
|
|
61
|
+
if (this.chainId) return;
|
|
62
|
+
throw new CofhesdkError({
|
|
63
|
+
code: CofhesdkErrorCode.ChainIdUninitialized,
|
|
64
|
+
message: 'Chain ID is not set',
|
|
65
|
+
hint: 'Ensure client.connect() has been called and awaited, or use setChainId(...) to set the chainId explicitly.',
|
|
66
|
+
context: {
|
|
67
|
+
chainId: this.chainId,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Asserts that this.account is populated
|
|
74
|
+
* @throws {CofhesdkError} If account is not set
|
|
75
|
+
*/
|
|
76
|
+
protected assertAccount(): asserts this is this & { account: string } {
|
|
77
|
+
if (this.account) return;
|
|
78
|
+
throw new CofhesdkError({
|
|
79
|
+
code: CofhesdkErrorCode.AccountUninitialized,
|
|
80
|
+
message: 'Account is not set',
|
|
81
|
+
hint: 'Ensure client.connect() has been called and awaited, or use setAccount(...) to set the account explicitly.',
|
|
82
|
+
context: {
|
|
83
|
+
account: this.account,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Asserts that this.publicClient is populated
|
|
90
|
+
* @throws {CofhesdkError} If publicClient is not set
|
|
91
|
+
*/
|
|
92
|
+
protected assertPublicClient(): asserts this is this & { publicClient: PublicClient } {
|
|
93
|
+
if (this.publicClient) return;
|
|
94
|
+
throw new CofhesdkError({
|
|
95
|
+
code: CofhesdkErrorCode.MissingPublicClient,
|
|
96
|
+
message: 'Public client not found',
|
|
97
|
+
hint: 'Ensure client.connect() has been called with a publicClient.',
|
|
98
|
+
context: {
|
|
99
|
+
publicClient: this.publicClient,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Asserts that this.walletClient is populated
|
|
106
|
+
* @throws {CofhesdkError} If walletClient is not set
|
|
107
|
+
*/
|
|
108
|
+
protected assertWalletClient(): asserts this is this & { walletClient: WalletClient } {
|
|
109
|
+
if (this.walletClient) return;
|
|
110
|
+
throw new CofhesdkError({
|
|
111
|
+
code: CofhesdkErrorCode.MissingWalletClient,
|
|
112
|
+
message: 'Wallet client not found',
|
|
113
|
+
hint: 'Ensure client.connect() has been called with a walletClient.',
|
|
114
|
+
context: {
|
|
115
|
+
walletClient: this.walletClient,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { createCofhesdkClientBase } from './client.js';
|
|
3
|
+
import { type CofhesdkClient, type CofhesdkClientConnectionState } from './clientTypes.js';
|
|
4
|
+
import { createCofhesdkConfigBase, type CofhesdkEnvironment } from './config.js';
|
|
5
|
+
import { CofhesdkError, CofhesdkErrorCode } from './error.js';
|
|
6
|
+
import { type PublicClient, type WalletClient } from 'viem';
|
|
7
|
+
import { EncryptInputsBuilder } from './encrypt/encryptInputsBuilder.js';
|
|
8
|
+
import { Encryptable } from './types.js';
|
|
9
|
+
|
|
10
|
+
// Mock dependencies
|
|
11
|
+
vi.mock('./keyStore', () => ({
|
|
12
|
+
createKeysStore: vi.fn(() => ({
|
|
13
|
+
rehydrateKeysStore: vi.fn().mockResolvedValue(undefined),
|
|
14
|
+
getFheKey: vi.fn(),
|
|
15
|
+
getCrs: vi.fn(),
|
|
16
|
+
setFheKey: vi.fn(),
|
|
17
|
+
setCrs: vi.fn(),
|
|
18
|
+
clearKeysStorage: vi.fn(),
|
|
19
|
+
store: {} as any,
|
|
20
|
+
})),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
// Test helpers
|
|
24
|
+
const createMockPublicClient = (chainId = 11155111): PublicClient =>
|
|
25
|
+
({
|
|
26
|
+
getChainId: vi.fn().mockResolvedValue(chainId),
|
|
27
|
+
}) as any;
|
|
28
|
+
|
|
29
|
+
const createMockWalletClient = (addresses = ['0x1234567890123456789012345678901234567890']): WalletClient =>
|
|
30
|
+
({
|
|
31
|
+
getAddresses: vi.fn().mockResolvedValue(addresses),
|
|
32
|
+
}) as any;
|
|
33
|
+
|
|
34
|
+
const createTestClient = (): CofhesdkClient => {
|
|
35
|
+
const config = createCofhesdkConfigBase({ supportedChains: [] });
|
|
36
|
+
return createCofhesdkClientBase({
|
|
37
|
+
config,
|
|
38
|
+
zkBuilderAndCrsGenerator: {} as any,
|
|
39
|
+
tfhePublicKeyDeserializer: {} as any,
|
|
40
|
+
compactPkeCrsDeserializer: {} as any,
|
|
41
|
+
initTfhe: () => Promise.resolve(false),
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
describe('createCofhesdkClientBase', () => {
|
|
46
|
+
let client: CofhesdkClient;
|
|
47
|
+
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
client = createTestClient();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('initial state', () => {
|
|
53
|
+
it('should start disconnected', () => {
|
|
54
|
+
const snapshot = client.getSnapshot();
|
|
55
|
+
expect(snapshot.connected).toBe(false);
|
|
56
|
+
expect(snapshot.connecting).toBe(false);
|
|
57
|
+
expect(snapshot.connectError).toBe(undefined);
|
|
58
|
+
expect(snapshot.chainId).toBe(undefined);
|
|
59
|
+
expect(snapshot.account).toBe(undefined);
|
|
60
|
+
expect(snapshot.publicClient).toBe(undefined);
|
|
61
|
+
expect(snapshot.walletClient).toBe(undefined);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should expose convenience flags', () => {
|
|
65
|
+
expect(client.connected).toBe(false);
|
|
66
|
+
expect(client.connecting).toBe(false);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should expose config', () => {
|
|
70
|
+
expect(client.config).toBeDefined();
|
|
71
|
+
expect(client.config.supportedChains).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('environment', () => {
|
|
76
|
+
it('should create a client with the correct environment', async () => {
|
|
77
|
+
const environments: CofhesdkEnvironment[] = ['node', 'hardhat', 'web', 'react'];
|
|
78
|
+
for (const environment of environments) {
|
|
79
|
+
const config = createCofhesdkConfigBase({ environment, supportedChains: [] });
|
|
80
|
+
const client = createCofhesdkClientBase({
|
|
81
|
+
config,
|
|
82
|
+
zkBuilderAndCrsGenerator: {} as any,
|
|
83
|
+
tfhePublicKeyDeserializer: {} as any,
|
|
84
|
+
compactPkeCrsDeserializer: {} as any,
|
|
85
|
+
initTfhe: () => Promise.resolve(false),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(client.config.environment).toBe(environment);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('reactive state', () => {
|
|
94
|
+
it('should notify subscribers of state changes', async () => {
|
|
95
|
+
const states: CofhesdkClientConnectionState[] = [];
|
|
96
|
+
client.subscribe((snapshot) => states.push(snapshot));
|
|
97
|
+
|
|
98
|
+
const publicClient = createMockPublicClient();
|
|
99
|
+
const walletClient = createMockWalletClient();
|
|
100
|
+
await client.connect(publicClient, walletClient);
|
|
101
|
+
|
|
102
|
+
// Expect states[0] to be the connecting state
|
|
103
|
+
expect(states[0].connecting).toBe(true);
|
|
104
|
+
expect(states[0].connected).toBe(false);
|
|
105
|
+
expect(states[0].chainId).toBe(undefined);
|
|
106
|
+
expect(states[0].account).toBe(undefined);
|
|
107
|
+
expect(states[0].publicClient).toBe(undefined);
|
|
108
|
+
expect(states[0].walletClient).toBe(undefined);
|
|
109
|
+
|
|
110
|
+
// Expect states[1] to be the connected state
|
|
111
|
+
expect(states[1].connected).toBe(true);
|
|
112
|
+
expect(states[1].connecting).toBe(false);
|
|
113
|
+
expect(states[1].chainId).toBe(11155111);
|
|
114
|
+
expect(states[1].account).toBe('0x1234567890123456789012345678901234567890');
|
|
115
|
+
expect(states[1].publicClient).toBe(publicClient);
|
|
116
|
+
expect(states[1].walletClient).toBe(walletClient);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should stop notifications after unsubscribe', async () => {
|
|
120
|
+
const states: CofhesdkClientConnectionState[] = [];
|
|
121
|
+
const unsubscribe = client.subscribe((snapshot) => states.push(snapshot));
|
|
122
|
+
|
|
123
|
+
unsubscribe();
|
|
124
|
+
|
|
125
|
+
const publicClient = createMockPublicClient();
|
|
126
|
+
const walletClient = createMockWalletClient();
|
|
127
|
+
await client.connect(publicClient, walletClient);
|
|
128
|
+
|
|
129
|
+
// Should only have the initial notification
|
|
130
|
+
expect(states.length).toBe(0);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('connect', () => {
|
|
135
|
+
it('should successfully connect with valid clients', async () => {
|
|
136
|
+
const publicClient = createMockPublicClient(11155111);
|
|
137
|
+
const walletClient = createMockWalletClient(['0xabcd']);
|
|
138
|
+
|
|
139
|
+
await client.connect(publicClient, walletClient);
|
|
140
|
+
|
|
141
|
+
expect(client.connected).toBe(true);
|
|
142
|
+
expect(client.connecting).toBe(false);
|
|
143
|
+
|
|
144
|
+
const snapshot = client.getSnapshot();
|
|
145
|
+
expect(snapshot.chainId).toBe(11155111);
|
|
146
|
+
expect(snapshot.account).toBe('0xabcd');
|
|
147
|
+
expect(snapshot.publicClient).toBe(publicClient);
|
|
148
|
+
expect(snapshot.walletClient).toBe(walletClient);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should set connecting state during connection', async () => {
|
|
152
|
+
const publicClient = createMockPublicClient();
|
|
153
|
+
const walletClient = createMockWalletClient();
|
|
154
|
+
|
|
155
|
+
const connectPromise = client.connect(publicClient, walletClient);
|
|
156
|
+
|
|
157
|
+
// Check mid-connection state
|
|
158
|
+
expect(client.connecting).toBe(true);
|
|
159
|
+
expect(client.connected).toBe(false);
|
|
160
|
+
|
|
161
|
+
await connectPromise;
|
|
162
|
+
|
|
163
|
+
expect(client.connecting).toBe(false);
|
|
164
|
+
expect(client.connected).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should return existing promise if already connecting', async () => {
|
|
168
|
+
const publicClient = createMockPublicClient();
|
|
169
|
+
const walletClient = createMockWalletClient();
|
|
170
|
+
|
|
171
|
+
const promise1 = client.connect(publicClient, walletClient);
|
|
172
|
+
const promise2 = client.connect(publicClient, walletClient);
|
|
173
|
+
|
|
174
|
+
expect(promise1).toStrictEqual(promise2);
|
|
175
|
+
|
|
176
|
+
await promise1;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should handle publicClient.getChainId throwing an error', async () => {
|
|
180
|
+
const publicClient = createMockPublicClient();
|
|
181
|
+
const getChainIdError = new Error('Network error');
|
|
182
|
+
publicClient.getChainId = vi.fn().mockRejectedValue(getChainIdError);
|
|
183
|
+
const walletClient = createMockWalletClient();
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
await client.connect(publicClient, walletClient);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
189
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
|
|
190
|
+
expect((error as CofhesdkError).message).toBe(
|
|
191
|
+
'getting chain ID from public client failed | Caused by: Network error'
|
|
192
|
+
);
|
|
193
|
+
expect((error as CofhesdkError).cause).toBe(getChainIdError);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should handle publicClient.getChainId returning null', async () => {
|
|
198
|
+
const publicClient = createMockPublicClient();
|
|
199
|
+
publicClient.getChainId = vi.fn().mockResolvedValue(null);
|
|
200
|
+
const walletClient = createMockWalletClient();
|
|
201
|
+
|
|
202
|
+
const connectPromise = client.connect(publicClient, walletClient);
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
await connectPromise;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
208
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
|
|
209
|
+
expect((error as CofhesdkError).message).toBe('chain ID from public client is null');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should handle walletClient.getAddresses throwing an error', async () => {
|
|
214
|
+
const publicClient = createMockPublicClient();
|
|
215
|
+
const getAddressesError = new Error('Network error');
|
|
216
|
+
const walletClient = createMockWalletClient();
|
|
217
|
+
walletClient.getAddresses = vi.fn().mockRejectedValue(getAddressesError);
|
|
218
|
+
|
|
219
|
+
const connectPromise = client.connect(publicClient, walletClient);
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
await connectPromise;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
225
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetAddressesFailed);
|
|
226
|
+
expect((error as CofhesdkError).message).toBe(
|
|
227
|
+
'getting address from wallet client failed | Caused by: Network error'
|
|
228
|
+
);
|
|
229
|
+
expect((error as CofhesdkError).cause).toBe(getAddressesError);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should handle walletClient.getAddresses returning an empty array', async () => {
|
|
234
|
+
const publicClient = createMockPublicClient();
|
|
235
|
+
const walletClient = createMockWalletClient([]);
|
|
236
|
+
|
|
237
|
+
const connectPromise = client.connect(publicClient, walletClient);
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
await connectPromise;
|
|
241
|
+
} catch (error) {
|
|
242
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
243
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetAddressesFailed);
|
|
244
|
+
expect((error as CofhesdkError).message).toBe('address from wallet client is null');
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should store error in state on failure', async () => {
|
|
249
|
+
const publicClient = createMockPublicClient();
|
|
250
|
+
const getChainIdError = new Error('Network error');
|
|
251
|
+
publicClient.getChainId = vi.fn().mockRejectedValue(getChainIdError);
|
|
252
|
+
const walletClient = createMockWalletClient();
|
|
253
|
+
|
|
254
|
+
const connectPromise = client.connect(publicClient, walletClient);
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
await connectPromise;
|
|
258
|
+
} catch (error) {
|
|
259
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
260
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
|
|
261
|
+
expect((error as CofhesdkError).message).toBe(
|
|
262
|
+
'getting chain ID from public client failed | Caused by: Network error'
|
|
263
|
+
);
|
|
264
|
+
expect((error as CofhesdkError).cause).toBe(getChainIdError);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('encryptInputs', () => {
|
|
270
|
+
it('should throw if not connected', async () => {
|
|
271
|
+
try {
|
|
272
|
+
await client.encryptInputs([Encryptable.uint8(1n), Encryptable.uint8(2n), Encryptable.uint8(3n)]).encrypt();
|
|
273
|
+
} catch (error) {
|
|
274
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
275
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.NotConnected);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should create EncryptInputsBuilder when connected', async () => {
|
|
280
|
+
const publicClient = createMockPublicClient(123);
|
|
281
|
+
const walletClient = createMockWalletClient(['0xtest']);
|
|
282
|
+
|
|
283
|
+
await client.connect(publicClient, walletClient);
|
|
284
|
+
|
|
285
|
+
const builder = await client.encryptInputs([Encryptable.uint8(1n), Encryptable.uint8(2n), Encryptable.uint8(3n)]);
|
|
286
|
+
|
|
287
|
+
expect(builder).toBeDefined();
|
|
288
|
+
expect(builder).toBeInstanceOf(EncryptInputsBuilder);
|
|
289
|
+
expect(builder).toHaveProperty('encrypt');
|
|
290
|
+
expect(builder.getChainId()).toBe(123);
|
|
291
|
+
expect(builder.getAccount()).toBe('0xtest');
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
describe('permits', () => {
|
|
296
|
+
it('should expose permits', () => {
|
|
297
|
+
expect(client.permits).toBeDefined();
|
|
298
|
+
expect(client.permits).toHaveProperty('getSnapshot');
|
|
299
|
+
expect(client.permits).toHaveProperty('subscribe');
|
|
300
|
+
expect(client.permits).toHaveProperty('createSelf');
|
|
301
|
+
expect(client.permits).toHaveProperty('createSharing');
|
|
302
|
+
expect(client.permits).toHaveProperty('importShared');
|
|
303
|
+
expect(client.permits).toHaveProperty('getHash');
|
|
304
|
+
expect(client.permits).toHaveProperty('serialize');
|
|
305
|
+
expect(client.permits).toHaveProperty('deserialize');
|
|
306
|
+
expect(client.permits).toHaveProperty('getPermit');
|
|
307
|
+
expect(client.permits).toHaveProperty('getPermits');
|
|
308
|
+
expect(client.permits).toHaveProperty('getActivePermit');
|
|
309
|
+
expect(client.permits).toHaveProperty('getActivePermitHash');
|
|
310
|
+
expect(client.permits).toHaveProperty('removePermit');
|
|
311
|
+
expect(client.permits).toHaveProperty('selectActivePermit');
|
|
312
|
+
expect(client.permits).toHaveProperty('removeActivePermit');
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
});
|