@cofhe/sdk 0.1.1 → 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 (96) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/adapters/ethers6.ts +28 -28
  3. package/adapters/hardhat.ts +0 -1
  4. package/adapters/index.test.ts +14 -19
  5. package/adapters/smartWallet.ts +81 -73
  6. package/adapters/test-utils.ts +45 -45
  7. package/adapters/types.ts +3 -3
  8. package/chains/chains/localcofhe.ts +14 -0
  9. package/chains/chains.test.ts +2 -1
  10. package/chains/index.ts +3 -1
  11. package/core/baseBuilder.ts +30 -49
  12. package/core/client.test.ts +94 -77
  13. package/core/client.ts +133 -149
  14. package/core/clientTypes.ts +108 -0
  15. package/core/config.test.ts +22 -11
  16. package/core/config.ts +16 -9
  17. package/core/decrypt/decryptHandleBuilder.ts +51 -45
  18. package/core/decrypt/{tnSealOutput.ts → tnSealOutputV1.ts} +1 -1
  19. package/core/decrypt/tnSealOutputV2.ts +298 -0
  20. package/core/encrypt/cofheMocksZkVerifySign.ts +16 -10
  21. package/core/encrypt/encryptInputsBuilder.test.ts +132 -116
  22. package/core/encrypt/encryptInputsBuilder.ts +159 -111
  23. package/core/encrypt/encryptUtils.ts +6 -3
  24. package/core/encrypt/zkPackProveVerify.ts +70 -8
  25. package/core/error.ts +0 -2
  26. package/core/fetchKeys.test.ts +1 -18
  27. package/core/fetchKeys.ts +0 -26
  28. package/core/index.ts +29 -17
  29. package/core/keyStore.ts +65 -38
  30. package/core/permits.test.ts +253 -1
  31. package/core/permits.ts +80 -16
  32. package/core/types.ts +198 -152
  33. package/core/utils.ts +43 -1
  34. package/dist/adapters.d.cts +38 -20
  35. package/dist/adapters.d.ts +38 -20
  36. package/dist/chains.cjs +14 -1
  37. package/dist/chains.d.cts +23 -1
  38. package/dist/chains.d.ts +23 -1
  39. package/dist/chains.js +1 -1
  40. package/dist/{chunk-LU7BMUUT.js → chunk-UGBVZNRT.js} +39 -25
  41. package/dist/{chunk-GZCQQYVI.js → chunk-WEAZ25JO.js} +14 -2
  42. package/dist/{chunk-KFGPTJ6X.js → chunk-WGCRJCBR.js} +1920 -1692
  43. package/dist/{types-bB7wLj0q.d.cts → clientTypes-5_1nwtUe.d.cts} +308 -347
  44. package/dist/{types-PhwGgQvs.d.ts → clientTypes-Es7fyi65.d.ts} +308 -347
  45. package/dist/core.cjs +2872 -2632
  46. package/dist/core.d.cts +101 -6
  47. package/dist/core.d.ts +101 -6
  48. package/dist/core.js +3 -3
  49. package/dist/node.cjs +2716 -2520
  50. package/dist/node.d.cts +3 -3
  51. package/dist/node.d.ts +3 -3
  52. package/dist/node.js +4 -3
  53. package/dist/{permit-S9CnI6MF.d.cts → permit-fUSe6KKq.d.cts} +31 -15
  54. package/dist/{permit-S9CnI6MF.d.ts → permit-fUSe6KKq.d.ts} +31 -15
  55. package/dist/permits.cjs +39 -24
  56. package/dist/permits.d.cts +137 -148
  57. package/dist/permits.d.ts +137 -148
  58. package/dist/permits.js +1 -1
  59. package/dist/web.cjs +2929 -2518
  60. package/dist/web.d.cts +21 -5
  61. package/dist/web.d.ts +21 -5
  62. package/dist/web.js +185 -9
  63. package/dist/zkProve.worker.cjs +93 -0
  64. package/dist/zkProve.worker.d.cts +2 -0
  65. package/dist/zkProve.worker.d.ts +2 -0
  66. package/dist/zkProve.worker.js +91 -0
  67. package/node/client.test.ts +20 -25
  68. package/node/encryptInputs.test.ts +18 -38
  69. package/node/index.ts +1 -0
  70. package/package.json +14 -14
  71. package/permits/index.ts +1 -0
  72. package/permits/localstorage.test.ts +0 -1
  73. package/permits/permit.test.ts +25 -22
  74. package/permits/permit.ts +30 -21
  75. package/permits/sealing.test.ts +3 -3
  76. package/permits/sealing.ts +2 -2
  77. package/permits/store.ts +5 -7
  78. package/permits/test-utils.ts +1 -1
  79. package/permits/types.ts +17 -0
  80. package/permits/utils.ts +0 -1
  81. package/permits/validation.ts +24 -4
  82. package/web/client.web.test.ts +20 -25
  83. package/web/config.web.test.ts +0 -2
  84. package/web/encryptInputs.web.test.ts +31 -54
  85. package/web/index.ts +65 -1
  86. package/web/storage.ts +19 -5
  87. package/web/worker.builder.web.test.ts +148 -0
  88. package/web/worker.config.web.test.ts +329 -0
  89. package/web/worker.output.web.test.ts +84 -0
  90. package/web/workerManager.test.ts +80 -0
  91. package/web/workerManager.ts +214 -0
  92. package/web/workerManager.web.test.ts +114 -0
  93. package/web/zkProve.worker.ts +133 -0
  94. package/core/result.test.ts +0 -180
  95. package/core/result.ts +0 -67
  96. package/core/test-utils.ts +0 -45
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @cofhe/sdk Changelog
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8fda09a: Removes `Promise<boolean>` return type from `client.connect(...)`, instead throws an error if the connection fails.
8
+ - e0caeca: Adds `environment: 'node' | 'web' | 'hardhat' | 'react'` option to config. Exposed via `client.config.enviroment`. Automatically populated appropriately within the various `createCofhesdkConfig` functions.
9
+ - 2a9d6c5: Updated to new CoFHE /sealoutputV2 endpoint - uses polling to fetch decryption results instead of long running open HTTP connections.
10
+
11
+ ### Patch Changes
12
+
13
+ - 4057a76: Add WebWorker for zkProve
14
+ - dba2759: Add getOrCreate permit functions
15
+ - 7c861af: Remove `initializationResults` from cofhesdk client.
16
+
3
17
  ## 0.1.1
4
18
 
5
19
  ### Patch Changes
@@ -1,36 +1,36 @@
1
- import { createPublicClient, createWalletClient, custom } from 'viem'
2
- import { privateKeyToAccount, toAccount } from 'viem/accounts'
3
- import type { Wallet, AbstractSigner, Provider } from 'ethers6'
4
- import { type AdapterResult } from './types.js'
1
+ import { createPublicClient, createWalletClient, custom } from 'viem';
2
+ import { privateKeyToAccount, toAccount } from 'viem/accounts';
3
+ import type { Wallet, AbstractSigner, Provider } from 'ethers6';
4
+ import { type AdapterResult } from './types.js';
5
5
 
6
- type Ethers6Signer = AbstractSigner | Wallet
6
+ type Ethers6Signer = AbstractSigner | Wallet;
7
7
 
8
8
  export async function Ethers6Adapter(provider: Provider, signer: Ethers6Signer): Promise<AdapterResult> {
9
- // Create transport from provider
10
- const transport =
11
- provider && 'send' in provider && typeof provider.send === 'function'
12
- ? // @ts-ignore - ethers6 provider.send is not typed
13
- custom({ request: ({ method, params }: any) => provider.send(method, params ?? []) })
14
- : (() => {
15
- throw new Error('Provider does not support EIP-1193 interface')
16
- })()
9
+ // Create transport from provider
10
+ const transport =
11
+ provider && 'send' in provider && typeof provider.send === 'function'
12
+ ? // @ts-ignore - ethers6 provider.send is not typed
13
+ custom({ request: ({ method, params }: any) => provider.send(method, params ?? []) })
14
+ : (() => {
15
+ throw new Error('Provider does not support EIP-1193 interface');
16
+ })();
17
17
 
18
- // build a viem Account
19
- const address = (await signer.getAddress()) as `0x${string}`
20
- let account: ReturnType<typeof privateKeyToAccount> | ReturnType<typeof toAccount> | `0x${string}`
18
+ // build a viem Account
19
+ const address = (await signer.getAddress()) as `0x${string}`;
20
+ let account: ReturnType<typeof privateKeyToAccount> | ReturnType<typeof toAccount> | `0x${string}`;
21
21
 
22
- if ('privateKey' in signer && typeof (signer as Wallet).privateKey === 'string') {
23
- // Local (true offline) signing → works with Infura via sendRawTransaction
24
- account = privateKeyToAccount((signer as Wallet).privateKey as `0x${string}`) // local account
25
- } else if (provider && typeof provider.send === 'function') {
26
- // Injected wallet (MetaMask/Coinbase) → wallet signs via eth_sendTransaction
27
- account = address // JSON-RPC account (not local signing)
28
- } else {
29
- throw new Error('Signer does not expose a private key and no injected wallet is available.')
30
- }
22
+ if ('privateKey' in signer && typeof (signer as Wallet).privateKey === 'string') {
23
+ // Local (true offline) signing → works with Infura via sendRawTransaction
24
+ account = privateKeyToAccount((signer as Wallet).privateKey as `0x${string}`); // local account
25
+ } else if (provider && typeof provider.send === 'function') {
26
+ // Injected wallet (MetaMask/Coinbase) → wallet signs via eth_sendTransaction
27
+ account = address; // JSON-RPC account (not local signing)
28
+ } else {
29
+ throw new Error('Signer does not expose a private key and no injected wallet is available.');
30
+ }
31
31
 
32
- const publicClient = createPublicClient({ transport })
33
- const walletClient = createWalletClient({ transport, account })
32
+ const publicClient = createPublicClient({ transport });
33
+ const walletClient = createWalletClient({ transport, account });
34
34
 
35
- return { publicClient, walletClient }
35
+ return { publicClient, walletClient };
36
36
  }
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-unused-vars */
2
1
  import { createPublicClient, createWalletClient, custom } from 'viem';
3
2
  import { type AdapterResult } from './types.js';
4
3
  import type { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers.js';
@@ -1,25 +1,20 @@
1
- import { describe, it, expect } from 'vitest'
2
- import * as adapters from './index.js'
1
+ import { describe, it, expect } from 'vitest';
2
+ import * as adapters from './index.js';
3
3
 
4
4
  describe('Index Exports', () => {
5
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
- })
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
11
 
12
12
  it('should have the expected simple adapters', () => {
13
- const expectedAdapters = [
14
- 'Ethers5Adapter',
15
- 'Ethers6Adapter',
16
- 'WagmiAdapter',
17
- 'HardhatSignerAdapter'
18
- ]
13
+ const expectedAdapters = ['Ethers5Adapter', 'Ethers6Adapter', 'WagmiAdapter', 'HardhatSignerAdapter'];
19
14
 
20
- expectedAdapters.forEach(adapterName => {
21
- expect(adapters).toHaveProperty(adapterName)
22
- expect(typeof (adapters as any)[adapterName]).toBe('function')
23
- })
24
- })
25
- })
15
+ expectedAdapters.forEach((adapterName) => {
16
+ expect(adapters).toHaveProperty(adapterName);
17
+ expect(typeof (adapters as any)[adapterName]).toBe('function');
18
+ });
19
+ });
20
+ });
@@ -1,16 +1,19 @@
1
- import type { PublicClient, WalletClient, Chain, Hex } from "viem";
2
- import { createWalletClient, custom } from "viem";
3
-
1
+ import type { PublicClient, WalletClient, Chain, Hex } from 'viem';
2
+ import { createWalletClient, custom } from 'viem';
4
3
 
5
4
  type SmartAccountClient = {
6
- account: { address: `0x${string}` };
7
- // Sends a UserOperation, returns a hash (usually userOpHash)
8
- // eslint-disable-next-line no-unused-vars
9
- sendTransaction: (tx: any) => Promise<`0x${string}`>;
10
- // EIP-712 via smart account (e.g., Safe EIP-1271)
11
- signTypedData: (_args: { domain: any; types: Record<string, any>; primaryType: string; message: Record<string, any> }) => Promise<`0x${string}`>;
12
- // Optional:
13
- signMessage?: (_args: { message: string | Hex }) => Promise<`0x${string}`>;
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}`>;
14
17
  };
15
18
 
16
19
  /**
@@ -18,74 +21,79 @@ type SmartAccountClient = {
18
21
  * - publicClient: passthrough of the given viem PublicClient
19
22
  * - walletClient: viem WalletClient-shaped object whose sendTransaction/sign* delegate to the smart account
20
23
  */
21
- export function smartWalletViemAdapter(publicClient: PublicClient, smartAccountClient: SmartAccountClient, opts: { chain?: Chain } = {}): { publicClient: PublicClient; walletClient: WalletClient } {
22
- const chain = opts.chain ?? (publicClient as any).chain;
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;
23
30
 
24
- // Use the existing publicClient for all JSON-RPC calls
25
- const transport = custom({
26
- request: ({ method, params }: { method: string; params?: any[] }) => publicClient.request({ method: method as any, params: (params ?? []) as any }),
27
- });
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
+ });
28
36
 
29
- // Create a base viem WalletClient (JSON-RPC account placeholder)
30
- // We’ll override methods to route through the smart account.
31
- const base = createWalletClient({
32
- chain,
33
- transport,
34
- account: smartAccountClient.account.address, // not used for signing; just keeps API shape
35
- });
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
+ });
36
44
 
37
- // Override methods that must go through the smart account
38
- const walletClient: WalletClient = {
39
- ...base,
45
+ // Override methods that must go through the smart account
46
+ const walletClient: WalletClient = {
47
+ ...base,
40
48
 
41
- /**
42
- * For AA, this sends a UserOperation via your smartAccountClient.
43
- * Return value is typically a userOp hash (not a raw tx hash).
44
- */
45
- async sendTransaction(tx: any) {
46
- return smartAccountClient.sendTransaction(tx);
47
- },
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
+ },
48
56
 
49
- /**
50
- * Sign typed data via the smart account (EIP-1271 flow).
51
- * Supports both single-object and (domain, types, message) forms.
52
- */
53
- async signTypedData(arg1: any, types?: any, message?: any) {
54
- let domain, typesObj, messageObj, primaryType: string;
55
- if (types === undefined && message === undefined) {
56
- // Single object: { domain, types, message, primaryType }
57
- domain = arg1.domain;
58
- typesObj = arg1.types;
59
- messageObj = arg1.message;
60
- primaryType = arg1.primaryType;
61
- } else {
62
- // Separate params
63
- domain = arg1;
64
- typesObj = types;
65
- messageObj = message;
66
- primaryType = Object.keys(typesObj).find((k) => k !== "EIP712Domain") ?? Object.keys(typesObj)[0];
67
- }
68
- return smartAccountClient.signTypedData({ domain, types: typesObj, primaryType, message: messageObj });
69
- },
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
+ },
70
78
 
71
- /**
72
- * Optional message signing if your smart account client supports it.
73
- * Otherwise, fall back to base (may throw for smart accounts).
74
- */
75
- async signMessage(args: { message: string | Hex }) {
76
- if (typeof smartAccountClient.signMessage === "function") {
77
- return smartAccountClient.signMessage(args);
78
- }
79
- // Fallback to base signMessage if smart account doesn't support it
80
- return base.signMessage({...args, account: base.account });
81
- },
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
+ },
82
90
 
83
- /**
84
- * Smart accounts generally cannot produce a raw signed EOA tx.
85
- * Keep viem’s default, but expect it to throw if invoked.
86
- */
87
- // signTransaction: base.signTransaction,
88
- } as WalletClient;
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;
89
97
 
90
- return { publicClient, walletClient };
98
+ return { publicClient, walletClient };
91
99
  }
@@ -1,53 +1,53 @@
1
- import { vi } from 'vitest'
2
- import type { EIP1193Provider } from 'viem'
1
+ import { vi } from 'vitest';
2
+ import type { EIP1193Provider } from 'viem';
3
3
 
4
4
  /**
5
5
  * Mock EIP-1193 provider for testing
6
6
  */
7
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
- }
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
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
- }
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
51
 
52
- return boundProvider as any
52
+ return boundProvider as any;
53
53
  }
package/adapters/types.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { PublicClient, WalletClient } from 'viem'
1
+ import type { PublicClient, WalletClient } from 'viem';
2
2
 
3
3
  export interface AdapterResult {
4
- publicClient: PublicClient
5
- walletClient: WalletClient
4
+ publicClient: PublicClient;
5
+ walletClient: WalletClient;
6
6
  }
@@ -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
+ });
@@ -3,11 +3,12 @@ import { sepolia, arbSepolia, baseSepolia, hardhat, chains, getChainById, getCha
3
3
 
4
4
  describe('Chains', () => {
5
5
  it('should export all chains', () => {
6
- expect(Object.keys(chains)).toHaveLength(4);
6
+ expect(Object.keys(chains)).toHaveLength(5);
7
7
  expect(chains).toHaveProperty('sepolia');
8
8
  expect(chains).toHaveProperty('arbSepolia');
9
9
  expect(chains).toHaveProperty('baseSepolia');
10
10
  expect(chains).toHaveProperty('hardhat');
11
+ expect(chains).toHaveProperty('localcofhe');
11
12
  });
12
13
 
13
14
  it('should have correct chain configurations', () => {
package/chains/index.ts CHANGED
@@ -6,8 +6,9 @@ import { sepolia } from './chains/sepolia.js';
6
6
  import { arbSepolia } from './chains/arbSepolia.js';
7
7
  import { baseSepolia } from './chains/baseSepolia.js';
8
8
  import { hardhat } from './chains/hardhat.js';
9
+ import { localcofhe } from './chains/localcofhe.js';
9
10
 
10
- export { sepolia, arbSepolia, baseSepolia, hardhat };
11
+ export { sepolia, arbSepolia, baseSepolia, hardhat, localcofhe };
11
12
 
12
13
  // Export all chains as a collection
13
14
  export const chains = {
@@ -15,6 +16,7 @@ export const chains = {
15
16
  arbSepolia,
16
17
  baseSepolia,
17
18
  hardhat,
19
+ localcofhe,
18
20
  } as const;
19
21
 
20
22
  // Import CofheChain type for helper functions
@@ -21,34 +21,44 @@ export type BaseBuilderParams = {
21
21
  * for working with clients, config, and chain IDs
22
22
  */
23
23
  export abstract class BaseBuilder {
24
- protected config: CofhesdkConfig | undefined;
24
+ protected config: CofhesdkConfig;
25
+
25
26
  protected publicClient: PublicClient | undefined;
26
27
  protected walletClient: WalletClient | undefined;
27
28
 
28
29
  protected chainId: number | undefined;
29
30
  protected account: string | undefined;
30
31
 
31
- protected requireConnected: (() => void) | undefined;
32
-
33
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
+ }
34
44
  this.config = params.config;
45
+
35
46
  this.publicClient = params.publicClient;
36
47
  this.walletClient = params.walletClient;
37
48
 
38
49
  this.chainId = params.chainId;
39
50
  this.account = params.account;
40
51
 
41
- this.requireConnected = params.requireConnected;
52
+ // Require the client to be connected if passed as param
53
+ params.requireConnected?.();
42
54
  }
43
55
 
44
56
  /**
45
- * Gets the chain ID from the instance or fetches it from the public client
46
- * @returns The chain ID
47
- * @throws {CofhesdkError} If chainId is not set and publicClient is not available
57
+ * Asserts that this.chainId is populated
58
+ * @throws {CofhesdkError} If chainId is not set
48
59
  */
49
- protected async getChainIdOrThrow(): Promise<number> {
50
- if (this.chainId) return this.chainId;
51
-
60
+ protected assertChainId(): asserts this is this & { chainId: number } {
61
+ if (this.chainId) return;
52
62
  throw new CofhesdkError({
53
63
  code: CofhesdkErrorCode.ChainIdUninitialized,
54
64
  message: 'Chain ID is not set',
@@ -60,13 +70,11 @@ export abstract class BaseBuilder {
60
70
  }
61
71
 
62
72
  /**
63
- * Gets the account address from the instance or fetches it from the wallet client
64
- * @returns The account address
65
- * @throws {CofhesdkError} If account is not set and walletClient is not available
73
+ * Asserts that this.account is populated
74
+ * @throws {CofhesdkError} If account is not set
66
75
  */
67
- protected async getAccountOrThrow(): Promise<string> {
68
- if (this.account) return this.account;
69
-
76
+ protected assertAccount(): asserts this is this & { account: string } {
77
+ if (this.account) return;
70
78
  throw new CofhesdkError({
71
79
  code: CofhesdkErrorCode.AccountUninitialized,
72
80
  message: 'Account is not set',
@@ -78,29 +86,11 @@ export abstract class BaseBuilder {
78
86
  }
79
87
 
80
88
  /**
81
- * Gets the config or throws an error if not available
82
- * @returns The config
83
- * @throws {CofhesdkError} If config is not set
84
- */
85
- protected getConfigOrThrow(): CofhesdkConfig {
86
- if (this.config) return this.config;
87
- throw new CofhesdkError({
88
- code: CofhesdkErrorCode.MissingConfig,
89
- message: 'Builder config is undefined',
90
- hint: 'Ensure client has been created with a config.',
91
- context: {
92
- config: this.config,
93
- },
94
- });
95
- }
96
-
97
- /**
98
- * Gets the public client or throws an error if not available
99
- * @returns The public client
89
+ * Asserts that this.publicClient is populated
100
90
  * @throws {CofhesdkError} If publicClient is not set
101
91
  */
102
- protected getPublicClientOrThrow(): PublicClient {
103
- if (this.publicClient) return this.publicClient;
92
+ protected assertPublicClient(): asserts this is this & { publicClient: PublicClient } {
93
+ if (this.publicClient) return;
104
94
  throw new CofhesdkError({
105
95
  code: CofhesdkErrorCode.MissingPublicClient,
106
96
  message: 'Public client not found',
@@ -112,12 +102,11 @@ export abstract class BaseBuilder {
112
102
  }
113
103
 
114
104
  /**
115
- * Gets the wallet client or throws an error if not available
116
- * @returns The wallet client
105
+ * Asserts that this.walletClient is populated
117
106
  * @throws {CofhesdkError} If walletClient is not set
118
107
  */
119
- protected getWalletClientOrThrow(): WalletClient {
120
- if (this.walletClient) return this.walletClient;
108
+ protected assertWalletClient(): asserts this is this & { walletClient: WalletClient } {
109
+ if (this.walletClient) return;
121
110
  throw new CofhesdkError({
122
111
  code: CofhesdkErrorCode.MissingWalletClient,
123
112
  message: 'Wallet client not found',
@@ -127,12 +116,4 @@ export abstract class BaseBuilder {
127
116
  },
128
117
  });
129
118
  }
130
-
131
- /**
132
- * Requires the client to be connected
133
- * @throws {CofhesdkError} If client is not connected
134
- */
135
- protected requireConnectedOrThrow(): void {
136
- if (this.requireConnected) this.requireConnected();
137
- }
138
119
  }