@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.
Files changed (121) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/adapters/ethers5.test.ts +174 -0
  3. package/adapters/ethers5.ts +36 -0
  4. package/adapters/ethers6.test.ts +169 -0
  5. package/adapters/ethers6.ts +36 -0
  6. package/adapters/hardhat-node.ts +167 -0
  7. package/adapters/hardhat.hh2.test.ts +159 -0
  8. package/adapters/hardhat.ts +36 -0
  9. package/adapters/index.test.ts +20 -0
  10. package/adapters/index.ts +5 -0
  11. package/adapters/smartWallet.ts +99 -0
  12. package/adapters/test-utils.ts +53 -0
  13. package/adapters/types.ts +6 -0
  14. package/adapters/wagmi.test.ts +156 -0
  15. package/adapters/wagmi.ts +17 -0
  16. package/chains/chains/arbSepolia.ts +14 -0
  17. package/chains/chains/baseSepolia.ts +14 -0
  18. package/chains/chains/hardhat.ts +15 -0
  19. package/chains/chains/localcofhe.ts +14 -0
  20. package/chains/chains/sepolia.ts +14 -0
  21. package/chains/chains.test.ts +50 -0
  22. package/chains/defineChain.ts +18 -0
  23. package/chains/index.ts +35 -0
  24. package/chains/types.ts +32 -0
  25. package/core/baseBuilder.ts +119 -0
  26. package/core/client.test.ts +315 -0
  27. package/core/client.ts +292 -0
  28. package/core/clientTypes.ts +108 -0
  29. package/core/config.test.ts +235 -0
  30. package/core/config.ts +220 -0
  31. package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
  32. package/core/decrypt/cofheMocksSealOutput.ts +57 -0
  33. package/core/decrypt/decryptHandleBuilder.ts +287 -0
  34. package/core/decrypt/decryptUtils.ts +28 -0
  35. package/core/decrypt/tnSealOutputV1.ts +59 -0
  36. package/core/decrypt/tnSealOutputV2.ts +298 -0
  37. package/core/encrypt/MockZkVerifierAbi.ts +106 -0
  38. package/core/encrypt/cofheMocksZkVerifySign.ts +284 -0
  39. package/core/encrypt/encryptInputsBuilder.test.ts +751 -0
  40. package/core/encrypt/encryptInputsBuilder.ts +560 -0
  41. package/core/encrypt/encryptUtils.ts +67 -0
  42. package/core/encrypt/zkPackProveVerify.ts +335 -0
  43. package/core/error.ts +168 -0
  44. package/core/fetchKeys.test.ts +195 -0
  45. package/core/fetchKeys.ts +144 -0
  46. package/core/index.ts +89 -0
  47. package/core/keyStore.test.ts +226 -0
  48. package/core/keyStore.ts +154 -0
  49. package/core/permits.test.ts +494 -0
  50. package/core/permits.ts +200 -0
  51. package/core/types.ts +398 -0
  52. package/core/utils.ts +130 -0
  53. package/dist/adapters.cjs +88 -0
  54. package/dist/adapters.d.cts +14576 -0
  55. package/dist/adapters.d.ts +14576 -0
  56. package/dist/adapters.js +83 -0
  57. package/dist/chains.cjs +114 -0
  58. package/dist/chains.d.cts +121 -0
  59. package/dist/chains.d.ts +121 -0
  60. package/dist/chains.js +1 -0
  61. package/dist/chunk-UGBVZNRT.js +818 -0
  62. package/dist/chunk-WEAZ25JO.js +105 -0
  63. package/dist/chunk-WGCRJCBR.js +2523 -0
  64. package/dist/clientTypes-5_1nwtUe.d.cts +914 -0
  65. package/dist/clientTypes-Es7fyi65.d.ts +914 -0
  66. package/dist/core.cjs +3414 -0
  67. package/dist/core.d.cts +111 -0
  68. package/dist/core.d.ts +111 -0
  69. package/dist/core.js +3 -0
  70. package/dist/node.cjs +3286 -0
  71. package/dist/node.d.cts +22 -0
  72. package/dist/node.d.ts +22 -0
  73. package/dist/node.js +91 -0
  74. package/dist/permit-fUSe6KKq.d.cts +349 -0
  75. package/dist/permit-fUSe6KKq.d.ts +349 -0
  76. package/dist/permits.cjs +871 -0
  77. package/dist/permits.d.cts +1045 -0
  78. package/dist/permits.d.ts +1045 -0
  79. package/dist/permits.js +1 -0
  80. package/dist/types-KImPrEIe.d.cts +48 -0
  81. package/dist/types-KImPrEIe.d.ts +48 -0
  82. package/dist/web.cjs +3478 -0
  83. package/dist/web.d.cts +38 -0
  84. package/dist/web.d.ts +38 -0
  85. package/dist/web.js +240 -0
  86. package/dist/zkProve.worker.cjs +93 -0
  87. package/dist/zkProve.worker.d.cts +2 -0
  88. package/dist/zkProve.worker.d.ts +2 -0
  89. package/dist/zkProve.worker.js +91 -0
  90. package/node/client.test.ts +147 -0
  91. package/node/config.test.ts +68 -0
  92. package/node/encryptInputs.test.ts +155 -0
  93. package/node/index.ts +97 -0
  94. package/node/storage.ts +51 -0
  95. package/package.json +27 -15
  96. package/permits/index.ts +68 -0
  97. package/permits/localstorage.test.ts +117 -0
  98. package/permits/permit.test.ts +477 -0
  99. package/permits/permit.ts +405 -0
  100. package/permits/sealing.test.ts +84 -0
  101. package/permits/sealing.ts +131 -0
  102. package/permits/signature.ts +79 -0
  103. package/permits/store.test.ts +128 -0
  104. package/permits/store.ts +166 -0
  105. package/permits/test-utils.ts +20 -0
  106. package/permits/types.ts +191 -0
  107. package/permits/utils.ts +62 -0
  108. package/permits/validation.test.ts +288 -0
  109. package/permits/validation.ts +369 -0
  110. package/web/client.web.test.ts +147 -0
  111. package/web/config.web.test.ts +69 -0
  112. package/web/encryptInputs.web.test.ts +172 -0
  113. package/web/index.ts +161 -0
  114. package/web/storage.ts +34 -0
  115. package/web/worker.builder.web.test.ts +148 -0
  116. package/web/worker.config.web.test.ts +329 -0
  117. package/web/worker.output.web.test.ts +84 -0
  118. package/web/workerManager.test.ts +80 -0
  119. package/web/workerManager.ts +214 -0
  120. package/web/workerManager.web.test.ts +114 -0
  121. package/web/zkProve.worker.ts +133 -0
@@ -0,0 +1,159 @@
1
+ import { describe, it, expect, beforeEach, beforeAll, afterAll } from 'vitest';
2
+ import { parseEther } from 'viem';
3
+ import { hardhat } from 'viem/chains';
4
+ import { HardhatSignerAdapter } from './hardhat.js';
5
+ import hre from 'hardhat';
6
+ import '@nomicfoundation/hardhat-ethers';
7
+ import type { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers.js';
8
+ import { hardhatNode } from './hardhat-node.js';
9
+
10
+ describe('HardhatSignerAdapter', () => {
11
+ const HARDHAT_CHAIN_ID = 31337; // Hardhat local network
12
+ let signer: HardhatEthersSigner;
13
+
14
+ beforeAll(async () => {
15
+ // Start Hardhat node before running tests
16
+ // await hardhatNode.start()
17
+ }, 60000); // 60 second timeout for node startup
18
+
19
+ afterAll(async () => {
20
+ // Immediate cleanup - no waiting
21
+ console.log('Starting cleanup...');
22
+ if ((hardhatNode as any).process) {
23
+ try {
24
+ (hardhatNode as any).process.kill('SIGKILL');
25
+ (hardhatNode as any).process = null;
26
+ (hardhatNode as any).isReady = false;
27
+ } catch (e) {
28
+ console.log('Kill error:', e);
29
+ }
30
+ }
31
+
32
+ // Force port cleanup
33
+ try {
34
+ const { spawn } = await import('child_process');
35
+ const killCmd = spawn('sh', ['-c', 'lsof -ti :8545 | xargs -r kill -9'], { stdio: 'ignore' });
36
+ setTimeout(() => killCmd.kill('SIGKILL'), 1000); // Kill the kill command after 1s
37
+ } catch (e) {
38
+ console.log('Port cleanup error:', e);
39
+ }
40
+
41
+ console.log('Cleanup done');
42
+ }, 3000); // 3 second timeout
43
+
44
+ beforeEach(async () => {
45
+ // Use real Hardhat runtime environment
46
+ const [firstSigner] = await hre.ethers.getSigners();
47
+ signer = firstSigner;
48
+ });
49
+
50
+ it('should work with Hardhat signer', async () => {
51
+ const result = await HardhatSignerAdapter(signer);
52
+
53
+ expect(result).toHaveProperty('publicClient');
54
+ expect(result).toHaveProperty('walletClient');
55
+ expect(result.publicClient).toBeDefined();
56
+ expect(result.walletClient).toBeDefined();
57
+ });
58
+
59
+ it('should work without configuration', async () => {
60
+ const result = await HardhatSignerAdapter(signer);
61
+
62
+ expect(result).toHaveProperty('publicClient');
63
+ expect(result).toHaveProperty('walletClient');
64
+ expect(result.publicClient).toBeDefined();
65
+ expect(result.walletClient).toBeDefined();
66
+ });
67
+
68
+ it('should throw error when signer has no provider', async () => {
69
+ const signerWithoutProvider = { provider: null };
70
+
71
+ await expect(async () => {
72
+ await HardhatSignerAdapter(signerWithoutProvider as any);
73
+ }).rejects.toThrow('Signer must have a provider');
74
+ });
75
+
76
+ describe('Provider Functions', () => {
77
+ it('should support getChainId', async () => {
78
+ const { publicClient } = await HardhatSignerAdapter(signer);
79
+
80
+ const chainId = await publicClient.getChainId();
81
+ expect(typeof chainId).toBe('number');
82
+ expect(chainId).toBe(HARDHAT_CHAIN_ID); // Hardhat local network
83
+ });
84
+
85
+ it('should support call (contract read)', async () => {
86
+ const { publicClient } = await HardhatSignerAdapter(signer);
87
+
88
+ // Test eth_call via getBalance
89
+ const balance = await publicClient.getBalance({
90
+ address: '0x0000000000000000000000000000000000000000',
91
+ });
92
+ expect(typeof balance).toBe('bigint');
93
+ });
94
+
95
+ it('should support request (raw RPC)', async () => {
96
+ const { publicClient } = await HardhatSignerAdapter(signer);
97
+
98
+ // Test raw RPC request
99
+ const blockNumber = (await publicClient.request({
100
+ method: 'eth_blockNumber',
101
+ })) as string;
102
+ expect(typeof blockNumber).toBe('string');
103
+ expect(blockNumber.startsWith('0x')).toBe(true);
104
+ });
105
+ });
106
+
107
+ describe('Signer Functions', () => {
108
+ it('should support getAddress', async () => {
109
+ const { walletClient } = await HardhatSignerAdapter(signer);
110
+
111
+ const addresses = await walletClient.getAddresses();
112
+ expect(Array.isArray(addresses)).toBe(true);
113
+ });
114
+
115
+ it('should support signTypedData', async () => {
116
+ const { walletClient } = await HardhatSignerAdapter(signer);
117
+
118
+ const domain = {
119
+ name: 'Test',
120
+ version: '1',
121
+ chainId: HARDHAT_CHAIN_ID,
122
+ verifyingContract: '0x0000000000000000000000000000000000000000' as const,
123
+ };
124
+
125
+ const types = {
126
+ Message: [{ name: 'content', type: 'string' }],
127
+ };
128
+
129
+ const message = { content: 'Hello World' };
130
+
131
+ const signature = await walletClient.signTypedData({
132
+ account: (await signer.getAddress()) as `0x${string}`,
133
+ domain,
134
+ types,
135
+ primaryType: 'Message',
136
+ message,
137
+ });
138
+
139
+ expect(typeof signature).toBe('string');
140
+ expect(signature.startsWith('0x')).toBe(true);
141
+ });
142
+
143
+ it('should support sendTransaction', async () => {
144
+ const { walletClient } = await HardhatSignerAdapter(signer);
145
+
146
+ const hash = await walletClient.sendTransaction({
147
+ account: (await signer.getAddress()) as `0x${string}`,
148
+ to: '0x0000000000000000000000000000000000000000' as `0x${string}`,
149
+ value: parseEther('0'),
150
+ chain: hardhat, // Provide chain directly in the call
151
+ });
152
+
153
+ // Should succeed with Hardhat local network (has funds)
154
+ expect(typeof hash).toBe('string');
155
+ expect(hash.startsWith('0x')).toBe(true);
156
+ expect(hash.length).toBe(66);
157
+ });
158
+ });
159
+ });
@@ -0,0 +1,36 @@
1
+ import { createPublicClient, createWalletClient, custom } from 'viem';
2
+ import { type AdapterResult } from './types.js';
3
+ import type { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers.js';
4
+
5
+ export async function HardhatSignerAdapter(signer: HardhatEthersSigner): Promise<AdapterResult> {
6
+ // Get provider from signer
7
+ const provider = signer.provider;
8
+ if (!provider) {
9
+ throw new Error('Signer must have a provider');
10
+ }
11
+
12
+ // Create transport from provider (Hardhat providers are EIP-1193 compatible)
13
+ const transport = custom({
14
+ request: async ({ method, params }: { method: string; params?: unknown[] }) => {
15
+ if ('request' in provider && typeof provider.request === 'function') {
16
+ return await provider.request({ method, params });
17
+ } else if ('send' in provider && typeof provider.send === 'function') {
18
+ return await (provider as { send: (method: string, params?: unknown[]) => Promise<unknown> }).send(
19
+ method,
20
+ params || []
21
+ );
22
+ } else {
23
+ throw new Error('Provider does not support EIP-1193 request method');
24
+ }
25
+ },
26
+ });
27
+
28
+ // Get account from signer for local signing
29
+ const address = await signer.getAddress();
30
+ const account = address as `0x${string}`;
31
+
32
+ const publicClient = createPublicClient({ transport });
33
+ const walletClient = createWalletClient({ transport, account });
34
+
35
+ return { publicClient, walletClient };
36
+ }
@@ -0,0 +1,20 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import * as adapters from './index.js';
3
+
4
+ describe('Index Exports', () => {
5
+ it('should export main adapter functions', () => {
6
+ expect(typeof adapters.Ethers5Adapter).toBe('function');
7
+ expect(typeof adapters.Ethers6Adapter).toBe('function');
8
+ expect(typeof adapters.WagmiAdapter).toBe('function');
9
+ expect(typeof adapters.HardhatSignerAdapter).toBe('function');
10
+ });
11
+
12
+ it('should have the expected simple adapters', () => {
13
+ const expectedAdapters = ['Ethers5Adapter', 'Ethers6Adapter', 'WagmiAdapter', 'HardhatSignerAdapter'];
14
+
15
+ expectedAdapters.forEach((adapterName) => {
16
+ expect(adapters).toHaveProperty(adapterName);
17
+ expect(typeof (adapters as any)[adapterName]).toBe('function');
18
+ });
19
+ });
20
+ });
@@ -0,0 +1,5 @@
1
+ export { Ethers5Adapter } from './ethers5.js';
2
+ export { Ethers6Adapter } from './ethers6.js';
3
+ export { WagmiAdapter } from './wagmi.js';
4
+ export { HardhatSignerAdapter } from './hardhat.js';
5
+ export type { AdapterResult } from './types.js';
@@ -0,0 +1,99 @@
1
+ import type { PublicClient, WalletClient, Chain, Hex } from 'viem';
2
+ import { createWalletClient, custom } from 'viem';
3
+
4
+ type SmartAccountClient = {
5
+ account: { address: `0x${string}` };
6
+ // Sends a UserOperation, returns a hash (usually userOpHash)
7
+ sendTransaction: (tx: any) => Promise<`0x${string}`>;
8
+ // EIP-712 via smart account (e.g., Safe EIP-1271)
9
+ signTypedData: (_args: {
10
+ domain: any;
11
+ types: Record<string, any>;
12
+ primaryType: string;
13
+ message: Record<string, any>;
14
+ }) => Promise<`0x${string}`>;
15
+ // Optional:
16
+ signMessage?: (_args: { message: string | Hex }) => Promise<`0x${string}`>;
17
+ };
18
+
19
+ /**
20
+ * Adapter: (publicClient, smartAccountClient) -> { publicClient, walletClient }
21
+ * - publicClient: passthrough of the given viem PublicClient
22
+ * - walletClient: viem WalletClient-shaped object whose sendTransaction/sign* delegate to the smart account
23
+ */
24
+ export function smartWalletViemAdapter(
25
+ publicClient: PublicClient,
26
+ smartAccountClient: SmartAccountClient,
27
+ opts: { chain?: Chain } = {}
28
+ ): { publicClient: PublicClient; walletClient: WalletClient } {
29
+ const chain = opts.chain ?? (publicClient as any).chain;
30
+
31
+ // Use the existing publicClient for all JSON-RPC calls
32
+ const transport = custom({
33
+ request: ({ method, params }: { method: string; params?: any[] }) =>
34
+ publicClient.request({ method: method as any, params: (params ?? []) as any }),
35
+ });
36
+
37
+ // Create a base viem WalletClient (JSON-RPC account placeholder)
38
+ // We’ll override methods to route through the smart account.
39
+ const base = createWalletClient({
40
+ chain,
41
+ transport,
42
+ account: smartAccountClient.account.address, // not used for signing; just keeps API shape
43
+ });
44
+
45
+ // Override methods that must go through the smart account
46
+ const walletClient: WalletClient = {
47
+ ...base,
48
+
49
+ /**
50
+ * For AA, this sends a UserOperation via your smartAccountClient.
51
+ * Return value is typically a userOp hash (not a raw tx hash).
52
+ */
53
+ async sendTransaction(tx: any) {
54
+ return smartAccountClient.sendTransaction(tx);
55
+ },
56
+
57
+ /**
58
+ * Sign typed data via the smart account (EIP-1271 flow).
59
+ * Supports both single-object and (domain, types, message) forms.
60
+ */
61
+ async signTypedData(arg1: any, types?: any, message?: any) {
62
+ let domain, typesObj, messageObj, primaryType: string;
63
+ if (types === undefined && message === undefined) {
64
+ // Single object: { domain, types, message, primaryType }
65
+ domain = arg1.domain;
66
+ typesObj = arg1.types;
67
+ messageObj = arg1.message;
68
+ primaryType = arg1.primaryType;
69
+ } else {
70
+ // Separate params
71
+ domain = arg1;
72
+ typesObj = types;
73
+ messageObj = message;
74
+ primaryType = Object.keys(typesObj).find((k) => k !== 'EIP712Domain') ?? Object.keys(typesObj)[0];
75
+ }
76
+ return smartAccountClient.signTypedData({ domain, types: typesObj, primaryType, message: messageObj });
77
+ },
78
+
79
+ /**
80
+ * Optional message signing if your smart account client supports it.
81
+ * Otherwise, fall back to base (may throw for smart accounts).
82
+ */
83
+ async signMessage(args: { message: string | Hex }) {
84
+ if (typeof smartAccountClient.signMessage === 'function') {
85
+ return smartAccountClient.signMessage(args);
86
+ }
87
+ // Fallback to base signMessage if smart account doesn't support it
88
+ return base.signMessage({ ...args, account: base.account });
89
+ },
90
+
91
+ /**
92
+ * Smart accounts generally cannot produce a raw signed EOA tx.
93
+ * Keep viem’s default, but expect it to throw if invoked.
94
+ */
95
+ // signTransaction: base.signTransaction,
96
+ } as WalletClient;
97
+
98
+ return { publicClient, walletClient };
99
+ }
@@ -0,0 +1,53 @@
1
+ import { vi } from 'vitest';
2
+ import type { EIP1193Provider } from 'viem';
3
+
4
+ /**
5
+ * Mock EIP-1193 provider for testing
6
+ */
7
+ export function createMockEIP1193Provider(): EIP1193Provider {
8
+ const mockProvider = {
9
+ request: vi.fn().mockImplementation(async ({ method, params }) => {
10
+ switch (method) {
11
+ case 'eth_chainId':
12
+ return '0x2aa36a7'; // Sepolia chainId
13
+ case 'eth_accounts':
14
+ return ['0x742d35Cc6634C0532925a3b8D0Ea4E686C9b8A'];
15
+ case 'eth_getBalance':
16
+ return '0x1bc16d674ec80000'; // 2 ETH
17
+ case 'eth_blockNumber':
18
+ return '0x12345';
19
+ case 'eth_gasPrice':
20
+ return '0x9184e72a000'; // 10 gwei
21
+ case 'personal_sign':
22
+ case 'eth_sign':
23
+ return '0x' + 'a'.repeat(130); // Mock signature
24
+ case 'eth_signTypedData_v4':
25
+ return '0x' + 'a'.repeat(130); // Mock typed data signature
26
+ case 'eth_sendTransaction':
27
+ return '0x' + 'b'.repeat(64); // Mock transaction hash
28
+ default:
29
+ throw new Error(`Unsupported method: ${method}`);
30
+ }
31
+ }),
32
+ on: vi.fn(),
33
+ removeListener: vi.fn(),
34
+ // Add additional EIP-1193 properties
35
+ send: vi.fn(),
36
+ sendAsync: vi.fn(),
37
+ isMetaMask: false,
38
+ isConnected: vi.fn().mockReturnValue(true),
39
+ };
40
+
41
+ // Add bind method that viem expects and bind all methods
42
+ const boundProvider = {
43
+ ...mockProvider,
44
+ request: mockProvider.request.bind(mockProvider),
45
+ on: mockProvider.on.bind(mockProvider),
46
+ removeListener: mockProvider.removeListener.bind(mockProvider),
47
+ bind: function () {
48
+ return this;
49
+ },
50
+ };
51
+
52
+ return boundProvider as any;
53
+ }
@@ -0,0 +1,6 @@
1
+ import type { PublicClient, WalletClient } from 'viem';
2
+
3
+ export interface AdapterResult {
4
+ publicClient: PublicClient;
5
+ walletClient: WalletClient;
6
+ }
@@ -0,0 +1,156 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { parseEther, createPublicClient, createWalletClient, http, type PublicClient, type WalletClient } from 'viem';
3
+ import { privateKeyToAccount } from 'viem/accounts';
4
+ import { WagmiAdapter } from './wagmi.js';
5
+
6
+ describe('WagmiAdapter', () => {
7
+ const testRpcUrl = 'https://ethereum-sepolia.rpc.subquery.network/public';
8
+ const SEPOLIA_CHAIN_ID = 11155111;
9
+ let account: ReturnType<typeof privateKeyToAccount>;
10
+ let publicClient: PublicClient;
11
+ let walletClient: WalletClient;
12
+
13
+ beforeEach(() => {
14
+ // Create common setup for all tests - no chain needed
15
+ account = privateKeyToAccount(('0x' + '1'.repeat(64)) as `0x${string}`);
16
+
17
+ publicClient = createPublicClient({
18
+ transport: http(testRpcUrl),
19
+ });
20
+
21
+ walletClient = createWalletClient({
22
+ transport: http(testRpcUrl),
23
+ account,
24
+ });
25
+ });
26
+
27
+ it('should work with real Wagmi clients', async () => {
28
+ const result = await WagmiAdapter(walletClient, publicClient);
29
+
30
+ expect(result).toHaveProperty('publicClient');
31
+ expect(result).toHaveProperty('walletClient');
32
+ expect(result.publicClient).toBe(publicClient);
33
+ expect(result.walletClient).toBe(walletClient);
34
+ });
35
+
36
+ it('should throw error when wallet client is missing', async () => {
37
+ const mockPublicClient = {} as any;
38
+
39
+ await expect(async () => {
40
+ await WagmiAdapter(null as any, mockPublicClient);
41
+ }).rejects.toThrow('WalletClient is required');
42
+ });
43
+
44
+ it('should throw error when public client is missing', async () => {
45
+ const mockWalletClient = {} as any;
46
+
47
+ await expect(async () => {
48
+ await WagmiAdapter(mockWalletClient, null as any);
49
+ }).rejects.toThrow('PublicClient is required');
50
+ });
51
+
52
+ describe('Provider Functions', () => {
53
+ it('should support getChainId', async () => {
54
+ const { publicClient: resultPublic } = await WagmiAdapter(walletClient, publicClient);
55
+
56
+ const chainId = await resultPublic.getChainId();
57
+ expect(typeof chainId).toBe('number');
58
+ expect(chainId).toBe(SEPOLIA_CHAIN_ID);
59
+ }, 10000);
60
+
61
+ it('should support call (contract read)', async () => {
62
+ const { publicClient: resultPublic } = await WagmiAdapter(walletClient, publicClient);
63
+
64
+ // Test eth_call - get ETH balance of zero address
65
+ const balance = await resultPublic.getBalance({
66
+ address: '0x0000000000000000000000000000000000000000',
67
+ });
68
+ expect(typeof balance).toBe('bigint');
69
+ }, 10000);
70
+
71
+ it('should support request (raw RPC)', async () => {
72
+ const { publicClient: resultPublic } = await WagmiAdapter(walletClient, publicClient);
73
+
74
+ // Test raw RPC request
75
+ const blockNumber = (await resultPublic.request({
76
+ method: 'eth_blockNumber',
77
+ })) as string;
78
+ expect(typeof blockNumber).toBe('string');
79
+ expect(blockNumber.startsWith('0x')).toBe(true);
80
+ }, 10000);
81
+ });
82
+
83
+ describe('Signer Functions', () => {
84
+ it('should support getAddress', async () => {
85
+ const { walletClient: resultWallet } = await WagmiAdapter(walletClient, publicClient);
86
+
87
+ const addresses = await resultWallet.getAddresses();
88
+ expect(Array.isArray(addresses)).toBe(true);
89
+ // Should contain the account address
90
+ expect(addresses).toContain(account.address);
91
+ }, 10000);
92
+
93
+ it('should support signTypedData', async () => {
94
+ const { walletClient: resultWallet } = await WagmiAdapter(walletClient, publicClient);
95
+
96
+ const domain = {
97
+ name: 'Test',
98
+ version: '1',
99
+ chainId: SEPOLIA_CHAIN_ID, // Sepolia
100
+ verifyingContract: '0x0000000000000000000000000000000000000000' as const,
101
+ };
102
+
103
+ const types = {
104
+ Message: [{ name: 'content', type: 'string' }],
105
+ };
106
+
107
+ const message = { content: 'Hello World' };
108
+
109
+ const signature = await resultWallet.signTypedData({
110
+ domain,
111
+ types,
112
+ primaryType: 'Message',
113
+ message,
114
+ account: resultWallet.account!,
115
+ });
116
+
117
+ expect(typeof signature).toBe('string');
118
+ expect(signature.startsWith('0x')).toBe(true);
119
+ }, 10000);
120
+
121
+ it('should support sendTransaction', async () => {
122
+ const { publicClient: resultPublic, walletClient: resultWallet } = await WagmiAdapter(walletClient, publicClient);
123
+
124
+ // Try to send a transaction - this will fail due to insufficient funds
125
+ try {
126
+ console.log('estimating gas');
127
+ const gas = await resultPublic.estimateGas({
128
+ account: account.address,
129
+ to: '0x0000000000000000000000000000000000000000',
130
+ value: parseEther('0'),
131
+ });
132
+
133
+ console.log('sending transaction', account.address);
134
+ const hash = await resultWallet.sendTransaction({
135
+ to: '0x0000000000000000000000000000000000000000' as `0x${string}`,
136
+ value: parseEther('0'),
137
+ gas,
138
+ account: resultWallet.account!,
139
+ chain: resultWallet.chain,
140
+ });
141
+ console.log('transaction sent', hash);
142
+
143
+ // If it succeeds (shouldn't due to no funds), verify the format
144
+ expect(typeof hash).toBe('string');
145
+ expect(hash.startsWith('0x')).toBe(true);
146
+ expect(hash.length).toBe(66);
147
+ } catch (error: any) {
148
+ // Expected error: insufficient funds (good!)
149
+ const isInsufficientFunds = error.message.includes('insufficient funds') || error.message.includes('balance');
150
+
151
+ expect(isInsufficientFunds).toBe(true);
152
+ console.log('Expected error (insufficient funds):', error.message);
153
+ }
154
+ }, 10000);
155
+ });
156
+ });
@@ -0,0 +1,17 @@
1
+ import { type PublicClient, type WalletClient } from 'viem';
2
+
3
+ export async function WagmiAdapter(walletClient: WalletClient, publicClient: PublicClient) {
4
+ if (!walletClient) {
5
+ throw new Error('WalletClient is required');
6
+ }
7
+
8
+ if (!publicClient) {
9
+ throw new Error('PublicClient is required');
10
+ }
11
+
12
+ // Wagmi provides real viem clients, so we just pass them through
13
+ return {
14
+ publicClient,
15
+ walletClient,
16
+ };
17
+ }
@@ -0,0 +1,14 @@
1
+ import { defineChain } from '../defineChain.js';
2
+
3
+ /**
4
+ * Arbitrum Sepolia testnet chain configuration
5
+ */
6
+ export const arbSepolia = defineChain({
7
+ id: 421614,
8
+ name: 'Arbitrum Sepolia',
9
+ network: 'arb-sepolia',
10
+ coFheUrl: 'https://testnet-cofhe.fhenix.zone',
11
+ verifierUrl: 'https://testnet-cofhe-vrf.fhenix.zone',
12
+ thresholdNetworkUrl: 'https://testnet-cofhe-tn.fhenix.zone',
13
+ environment: 'TESTNET',
14
+ });
@@ -0,0 +1,14 @@
1
+ import { defineChain } from '../defineChain.js';
2
+
3
+ /**
4
+ * Base Sepolia testnet chain configuration
5
+ */
6
+ export const baseSepolia = defineChain({
7
+ id: 84532,
8
+ name: 'Base Sepolia',
9
+ network: 'base-sepolia',
10
+ coFheUrl: 'https://testnet-cofhe.fhenix.zone',
11
+ verifierUrl: 'https://testnet-cofhe-vrf.fhenix.zone',
12
+ thresholdNetworkUrl: 'https://testnet-cofhe-tn.fhenix.zone',
13
+ environment: 'TESTNET',
14
+ });
@@ -0,0 +1,15 @@
1
+ import { defineChain } from '../defineChain.js';
2
+
3
+ /**
4
+ * Hardhat local development chain configuration
5
+ */
6
+ export const hardhat = defineChain({
7
+ id: 31337,
8
+ name: 'Hardhat',
9
+ network: 'localhost',
10
+ // These are unused in the mock environment
11
+ coFheUrl: 'http://127.0.0.1:8448',
12
+ verifierUrl: 'http://127.0.0.1:3001',
13
+ thresholdNetworkUrl: 'http://127.0.0.1:3000',
14
+ environment: 'MOCK',
15
+ });
@@ -0,0 +1,14 @@
1
+ import { defineChain } from '../defineChain.js';
2
+
3
+ /**
4
+ * Localcofhe chain configuration
5
+ */
6
+ export const localcofhe = defineChain({
7
+ id: 420105,
8
+ name: 'Local Cofhe',
9
+ network: 'localhost',
10
+ coFheUrl: 'http://127.0.0.1:9448',
11
+ verifierUrl: 'http://127.0.0.1:3001',
12
+ thresholdNetworkUrl: 'http://127.0.0.1:3000',
13
+ environment: 'TESTNET',
14
+ });
@@ -0,0 +1,14 @@
1
+ import { defineChain } from '../defineChain.js';
2
+
3
+ /**
4
+ * Sepolia testnet chain configuration
5
+ */
6
+ export const sepolia = defineChain({
7
+ id: 11155111,
8
+ name: 'Sepolia',
9
+ network: 'sepolia',
10
+ coFheUrl: 'https://testnet-cofhe.fhenix.zone',
11
+ verifierUrl: 'https://testnet-cofhe-vrf.fhenix.zone',
12
+ thresholdNetworkUrl: 'https://testnet-cofhe-tn.fhenix.zone',
13
+ environment: 'TESTNET',
14
+ });