@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,68 @@
1
+ import { arbSepolia } from '@/chains';
2
+
3
+ import { describe, it, expect } from 'vitest';
4
+ import { createCofhesdkConfig, createCofhesdkClient } from './index.js';
5
+
6
+ describe('@cofhe/node - Config', () => {
7
+ describe('createCofhesdkConfig', () => {
8
+ it('should automatically inject filesystem storage as default', () => {
9
+ const config = createCofhesdkConfig({
10
+ supportedChains: [arbSepolia],
11
+ });
12
+
13
+ expect(config.fheKeyStorage).toBeDefined();
14
+ expect(config.fheKeyStorage).not.toBeNull();
15
+ expect(config.supportedChains).toEqual([arbSepolia]);
16
+ });
17
+
18
+ it('should allow overriding storage', async () => {
19
+ const customStorage = {
20
+ getItem: () => Promise.resolve(10),
21
+ setItem: () => Promise.resolve(),
22
+ removeItem: () => Promise.resolve(),
23
+ };
24
+ const config = createCofhesdkConfig({
25
+ supportedChains: [arbSepolia],
26
+ fheKeyStorage: customStorage,
27
+ });
28
+
29
+ expect(await config.fheKeyStorage!.getItem('test')).toBe(10);
30
+ });
31
+
32
+ it('should allow null storage', () => {
33
+ const config = createCofhesdkConfig({
34
+ supportedChains: [arbSepolia],
35
+ fheKeyStorage: null,
36
+ });
37
+
38
+ expect(config.fheKeyStorage).toBeNull();
39
+ });
40
+
41
+ it('should preserve all other config options', () => {
42
+ const config = createCofhesdkConfig({
43
+ supportedChains: [arbSepolia],
44
+ mocks: {
45
+ sealOutputDelay: 0,
46
+ },
47
+ });
48
+
49
+ expect(config.supportedChains).toEqual([arbSepolia]);
50
+ expect(config.mocks.sealOutputDelay).toBe(0);
51
+ expect(config.fheKeyStorage).toBeDefined();
52
+ });
53
+ });
54
+
55
+ describe('createCofhesdkClient with config', () => {
56
+ it('should create client with validated config', () => {
57
+ const config = createCofhesdkConfig({
58
+ supportedChains: [arbSepolia],
59
+ });
60
+
61
+ const client = createCofhesdkClient(config);
62
+
63
+ expect(client).toBeDefined();
64
+ expect(client.config).toBe(config);
65
+ expect(client.config.fheKeyStorage).toBeDefined();
66
+ });
67
+ });
68
+ });
@@ -0,0 +1,155 @@
1
+ import { Encryptable, FheTypes, type CofhesdkClient, CofhesdkErrorCode, CofhesdkError } from '@/core';
2
+ import { arbSepolia as cofhesdkArbSepolia } from '@/chains';
3
+
4
+ import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
5
+ import type { PublicClient, WalletClient } from 'viem';
6
+ import { createPublicClient, createWalletClient, http } from 'viem';
7
+ import { privateKeyToAccount } from 'viem/accounts';
8
+ import { arbitrumSepolia as viemArbitrumSepolia } from 'viem/chains';
9
+ import { createCofhesdkClient, createCofhesdkConfig } from './index.js';
10
+
11
+ // Real test setup - using actual node-tfhe
12
+ const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
13
+
14
+ describe('@cofhe/node - Encrypt Inputs', () => {
15
+ let cofhesdkClient: CofhesdkClient;
16
+ let publicClient: PublicClient;
17
+ let walletClient: WalletClient;
18
+
19
+ beforeAll(() => {
20
+ // Create real viem clients
21
+ publicClient = createPublicClient({
22
+ chain: viemArbitrumSepolia,
23
+ transport: http(),
24
+ });
25
+
26
+ const account = privateKeyToAccount(TEST_PRIVATE_KEY);
27
+ walletClient = createWalletClient({
28
+ chain: viemArbitrumSepolia,
29
+ transport: http(),
30
+ account,
31
+ });
32
+ });
33
+
34
+ beforeEach(() => {
35
+ const config = createCofhesdkConfig({
36
+ supportedChains: [cofhesdkArbSepolia],
37
+ });
38
+ cofhesdkClient = createCofhesdkClient(config);
39
+ });
40
+
41
+ describe('Real TFHE Initialization', () => {
42
+ it('should initialize node-tfhe on first encryption', async () => {
43
+ await cofhesdkClient.connect(publicClient, walletClient);
44
+
45
+ // This will trigger real TFHE initialization
46
+ const encrypted = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
47
+
48
+ // If we get here, TFHE was initialized successfully
49
+ expect(encrypted).toBeDefined();
50
+ }, 60000); // Longer timeout for real operations
51
+
52
+ it('should handle multiple encryptions without re-initializing', async () => {
53
+ await cofhesdkClient.connect(publicClient, walletClient);
54
+
55
+ // First encryption
56
+ await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
57
+
58
+ // Second encryption should reuse initialization
59
+ await cofhesdkClient.encryptInputs([Encryptable.uint64(50n)]).encrypt();
60
+ }, 120000);
61
+ });
62
+
63
+ describe('Real Encryption', () => {
64
+ it('should encrypt a bool with real TFHE', async () => {
65
+ await cofhesdkClient.connect(publicClient, walletClient);
66
+
67
+ const encrypted = await cofhesdkClient.encryptInputs([Encryptable.bool(true)]).encrypt();
68
+
69
+ expect(encrypted.length).toBe(1);
70
+ expect(encrypted[0].utype).toBe(FheTypes.Bool);
71
+ expect(encrypted[0].ctHash).toBeDefined();
72
+ expect(typeof encrypted[0].ctHash).toBe('bigint');
73
+ expect(encrypted[0].signature).toBeDefined();
74
+ expect(typeof encrypted[0].signature).toBe('string');
75
+ expect(encrypted[0].securityZone).toBe(0);
76
+ }, 60000);
77
+
78
+ it('should encrypt all supported types together', async () => {
79
+ await cofhesdkClient.connect(publicClient, walletClient);
80
+
81
+ const inputs = [
82
+ Encryptable.bool(false),
83
+ Encryptable.uint8(1n),
84
+ Encryptable.uint16(2n),
85
+ Encryptable.uint32(3n),
86
+ Encryptable.uint64(4n),
87
+ Encryptable.uint128(5n),
88
+ Encryptable.address('0x742d35Cc6634C0532925a3b844D16faC4c175E99'),
89
+ ];
90
+
91
+ const encrypted = await cofhesdkClient.encryptInputs(inputs).encrypt();
92
+
93
+ expect(encrypted.length).toBe(7);
94
+ // Verify each type
95
+ expect(encrypted[0].utype).toBe(FheTypes.Bool);
96
+ expect(encrypted[1].utype).toBe(FheTypes.Uint8);
97
+ expect(encrypted[2].utype).toBe(FheTypes.Uint16);
98
+ expect(encrypted[3].utype).toBe(FheTypes.Uint32);
99
+ expect(encrypted[4].utype).toBe(FheTypes.Uint64);
100
+ expect(encrypted[5].utype).toBe(FheTypes.Uint128);
101
+ expect(encrypted[6].utype).toBe(FheTypes.Uint160);
102
+ }, 90000); // Longer timeout for multiple encryptions
103
+ });
104
+
105
+ describe('Real Builder Pattern', () => {
106
+ it('should support chaining builder methods with real encryption', async () => {
107
+ await cofhesdkClient.connect(publicClient, walletClient);
108
+
109
+ const snapshot = cofhesdkClient.getSnapshot();
110
+ const encrypted = await cofhesdkClient
111
+ .encryptInputs([Encryptable.uint128(100n)])
112
+ .setChainId(snapshot.chainId!)
113
+ .setAccount(snapshot.account!)
114
+ .setSecurityZone(0)
115
+ .encrypt();
116
+
117
+ expect(encrypted.length).toBe(1);
118
+ expect(encrypted[0].utype).toBe(FheTypes.Uint128);
119
+ }, 60000);
120
+ });
121
+
122
+ describe('Real Error Handling', () => {
123
+ it('should fail gracefully when not connected', async () => {
124
+ // Don't connect the client
125
+ try {
126
+ await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
127
+ } catch (error) {
128
+ expect(error).toBeInstanceOf(CofhesdkError);
129
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.NotConnected);
130
+ }
131
+ }, 30000);
132
+
133
+ it('should handle invalid CoFHE URL', async () => {
134
+ const badConfig = createCofhesdkConfig({
135
+ supportedChains: [
136
+ {
137
+ ...cofhesdkArbSepolia,
138
+ coFheUrl: 'http://invalid-cofhe-url.local',
139
+ verifierUrl: 'http://invalid-verifier-url.local',
140
+ },
141
+ ],
142
+ });
143
+
144
+ const badClient = createCofhesdkClient(badConfig);
145
+ await badClient.connect(publicClient, walletClient);
146
+
147
+ try {
148
+ await badClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
149
+ } catch (error) {
150
+ expect(error).toBeInstanceOf(CofhesdkError);
151
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.ZkVerifyFailed);
152
+ }
153
+ }, 60000);
154
+ });
155
+ });
package/node/index.ts ADDED
@@ -0,0 +1,97 @@
1
+ // Node.js specific functionality only
2
+
3
+ import {
4
+ createCofhesdkClientBase,
5
+ createCofhesdkConfigBase,
6
+ type CofhesdkClient,
7
+ type CofhesdkConfig,
8
+ type CofhesdkInputConfig,
9
+ type ZkBuilderAndCrsGenerator,
10
+ type FheKeyDeserializer,
11
+ } from '@/core';
12
+
13
+ // Import node-specific storage (internal use only)
14
+ import { createNodeStorage } from './storage.js';
15
+
16
+ // Import node-tfhe for Node.js
17
+ import { TfheCompactPublicKey, ProvenCompactCiphertextList, CompactPkeCrs, init_panic_hook } from 'node-tfhe';
18
+
19
+ /**
20
+ * Internal function to initialize TFHE for Node.js
21
+ * Called automatically on first encryption - users don't need to call this manually
22
+ * @returns true if TFHE was initialized, false if already initialized
23
+ */
24
+ let tfheInitialized = false;
25
+ async function initTfhe(): Promise<boolean> {
26
+ if (tfheInitialized) return false;
27
+ await init_panic_hook();
28
+ tfheInitialized = true;
29
+ return true;
30
+ }
31
+
32
+ /**
33
+ * Utility to convert the hex string key to a Uint8Array for use with tfhe
34
+ */
35
+ const fromHexString = (hexString: string): Uint8Array => {
36
+ const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
37
+ const arr = cleanString.replace(/^0x/, '').match(/.{1,2}/g);
38
+ if (!arr) return new Uint8Array();
39
+ return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
40
+ };
41
+
42
+ /**
43
+ * Serializer for TFHE public keys
44
+ * Validates that the buffer can be deserialized into a TfheCompactPublicKey
45
+ */
46
+ const tfhePublicKeyDeserializer: FheKeyDeserializer = (buff: string): void => {
47
+ TfheCompactPublicKey.deserialize(fromHexString(buff));
48
+ };
49
+
50
+ /**
51
+ * Serializer for Compact PKE CRS
52
+ * Validates that the buffer can be deserialized into ZkCompactPkePublicParams
53
+ */
54
+ const compactPkeCrsDeserializer: FheKeyDeserializer = (buff: string): void => {
55
+ CompactPkeCrs.deserialize(fromHexString(buff));
56
+ };
57
+
58
+ /**
59
+ * Creates a ZK builder and CRS from FHE public key and CRS buffers
60
+ * This is used internally by the SDK to create encrypted inputs
61
+ */
62
+ const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: string) => {
63
+ const fhePublicKey = TfheCompactPublicKey.deserialize(fromHexString(fhe));
64
+ const zkBuilder = ProvenCompactCiphertextList.builder(fhePublicKey);
65
+ const zkCrs = CompactPkeCrs.deserialize(fromHexString(crs));
66
+
67
+ return { zkBuilder, zkCrs };
68
+ };
69
+
70
+ /**
71
+ * Creates a CoFHE SDK configuration for Node.js with filesystem storage as default
72
+ * @param config - The CoFHE SDK input configuration (fheKeyStorage will default to filesystem if not provided)
73
+ * @returns The CoFHE SDK configuration with Node.js defaults applied
74
+ */
75
+ export function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfig {
76
+ return createCofhesdkConfigBase({
77
+ environment: 'node',
78
+ ...config,
79
+ fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createNodeStorage(),
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Creates a CoFHE SDK client instance for Node.js with node-tfhe automatically configured
85
+ * TFHE will be initialized automatically on first encryption - no manual setup required
86
+ * @param config - The CoFHE SDK configuration (use createCofhesdkConfig to create with Node.js defaults)
87
+ * @returns The CoFHE SDK client instance
88
+ */
89
+ export function createCofhesdkClient(config: CofhesdkConfig): CofhesdkClient {
90
+ return createCofhesdkClientBase({
91
+ config,
92
+ zkBuilderAndCrsGenerator,
93
+ tfhePublicKeyDeserializer,
94
+ compactPkeCrsDeserializer,
95
+ initTfhe,
96
+ });
97
+ }
@@ -0,0 +1,51 @@
1
+ /* eslint-disable turbo/no-undeclared-env-vars */
2
+
3
+ import type { IStorage } from '@/core';
4
+
5
+ import { promises as fs } from 'fs';
6
+ import { join } from 'path';
7
+
8
+ // Memory storage fallback
9
+ const memoryStorage: Record<string, string> = {};
10
+
11
+ /**
12
+ * Creates a node storage implementation using the filesystem
13
+ * @returns IStorage implementation for Node.js environments
14
+ */
15
+ export const createNodeStorage = (): IStorage => {
16
+ return {
17
+ getItem: async (name: string) => {
18
+ try {
19
+ const storageDir = join(process.env.HOME || process.env.USERPROFILE || '.', '.cofhesdk');
20
+ await fs.mkdir(storageDir, { recursive: true });
21
+ const filePath = join(storageDir, `${name}.json`);
22
+ const data = await fs.readFile(filePath, 'utf8').catch(() => null);
23
+ return data ? JSON.parse(data) : null;
24
+ } catch (e) {
25
+ console.warn('Node.js filesystem modules not available, falling back to memory storage' + e);
26
+ return memoryStorage[name] || null;
27
+ }
28
+ },
29
+ setItem: async (name: string, value: any) => {
30
+ try {
31
+ const storageDir = join(process.env.HOME || process.env.USERPROFILE || '.', '.cofhesdk');
32
+ await fs.mkdir(storageDir, { recursive: true });
33
+ const filePath = join(storageDir, `${name}.json`);
34
+ await fs.writeFile(filePath, JSON.stringify(value));
35
+ } catch (e) {
36
+ console.warn('Node.js filesystem modules not available, falling back to memory storage' + e);
37
+ memoryStorage[name] = JSON.stringify(value);
38
+ }
39
+ },
40
+ removeItem: async (name: string) => {
41
+ try {
42
+ const storageDir = join(process.env.HOME || process.env.USERPROFILE || '.', '.cofhesdk');
43
+ const filePath = join(storageDir, `${name}.json`);
44
+ await fs.unlink(filePath).catch(() => {});
45
+ } catch (e) {
46
+ console.warn('Node.js filesystem modules not available, falling back to memory storage' + e);
47
+ delete memoryStorage[name];
48
+ }
49
+ },
50
+ };
51
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cofhe/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "description": "SDK for Fhenix COFHE coprocessor interaction",
6
6
  "main": "./dist/core.cjs",
@@ -41,25 +41,37 @@
41
41
  },
42
42
  "sideEffects": false,
43
43
  "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/FhenixProtocol/cofhesdk.git",
47
+ "directory": "packages/sdk"
48
+ },
44
49
  "files": [
45
- "dist/**"
50
+ "dist/**",
51
+ "core/**",
52
+ "adapters/**",
53
+ "chains/**",
54
+ "permits/**",
55
+ "node/**",
56
+ "web/**",
57
+ "CHANGELOG.md"
46
58
  ],
47
59
  "dependencies": {
60
+ "iframe-shared-storage": "^1.0.34",
48
61
  "immer": "^10.1.1",
49
- "zustand": "^5.0.1",
50
- "zod": "^3.22.0",
51
- "viem": "^2.0.0",
52
62
  "node-tfhe": "0.11.1",
53
- "idb-keyval": "^6.2.1",
54
63
  "tfhe": "0.11.1",
55
- "tweetnacl": "^1.0.3"
64
+ "tweetnacl": "^1.0.3",
65
+ "viem": "^2.38.6",
66
+ "zod": "^3.22.0",
67
+ "zustand": "^5.0.1"
56
68
  },
57
69
  "peerDependencies": {
58
- "viem": "^2.0.0",
70
+ "@nomicfoundation/hardhat-ethers": "^3.0.0",
59
71
  "@wagmi/core": "^2.0.0",
60
72
  "ethers": "^5.0.0 || ^6.0.0",
61
73
  "hardhat": "^2.0.0",
62
- "@nomicfoundation/hardhat-ethers": "^3.0.0"
74
+ "viem": "^2.38.6"
63
75
  },
64
76
  "peerDependenciesMeta": {
65
77
  "@wagmi/core": {
@@ -76,21 +88,21 @@
76
88
  }
77
89
  },
78
90
  "devDependencies": {
91
+ "@nomicfoundation/hardhat-ethers": "^3.0.0",
79
92
  "@types/node": "^20.0.0",
80
93
  "@vitest/browser": "^3.0.0",
81
94
  "@vitest/coverage-v8": "^3.0.0",
82
95
  "eslint": "^8.57.0",
96
+ "ethers5": "npm:ethers@^5.7.2",
97
+ "ethers6": "npm:ethers@^6.13.0",
83
98
  "happy-dom": "^15.0.0",
99
+ "hardhat": "^2.19.0",
84
100
  "playwright": "^1.55.0",
85
101
  "tsup": "^8.0.2",
86
102
  "typescript": "5.5.4",
87
103
  "vitest": "^3.0.0",
88
- "ethers5": "npm:ethers@^5.7.2",
89
- "ethers6": "npm:ethers@^6.13.0",
90
- "hardhat": "^2.19.0",
91
- "@nomicfoundation/hardhat-ethers": "^3.0.0",
92
- "@cofhe/eslint-config": "0.1.0",
93
- "@cofhe/tsconfig": "0.1.0"
104
+ "@cofhe/eslint-config": "0.2.0",
105
+ "@cofhe/tsconfig": "0.1.1"
94
106
  },
95
107
  "publishConfig": {
96
108
  "access": "public"
@@ -0,0 +1,68 @@
1
+ // Core types
2
+ export type {
3
+ Permit,
4
+ CreateSelfPermitOptions as SelfPermitOptions,
5
+ CreateSharingPermitOptions as SharingPermitOptions,
6
+ ImportSharedPermitOptions as ImportPermitOptions,
7
+ SerializedPermit,
8
+ PermitMetadata,
9
+ Permission,
10
+ EIP712Domain,
11
+ EIP712Types,
12
+ EIP712Message,
13
+ ValidationResult,
14
+ PermitSignaturePrimaryType,
15
+ } from './types.js';
16
+
17
+ // Main utilities
18
+ export { PermitUtils } from './permit.js';
19
+
20
+ // Validation utilities
21
+ export {
22
+ // Self permit validators
23
+ SelfPermitOptionsValidator,
24
+ SelfPermitValidator,
25
+ validateSelfPermitOptions,
26
+ validateSelfPermit,
27
+ // Sharing permit validators
28
+ SharingPermitOptionsValidator,
29
+ SharingPermitValidator,
30
+ validateSharingPermitOptions,
31
+ validateSharingPermit,
32
+ // Import permit validators
33
+ ImportPermitOptionsValidator,
34
+ ImportPermitValidator,
35
+ validateImportPermitOptions,
36
+ validateImportPermit,
37
+ // Common utilities
38
+ ValidationUtils,
39
+ } from './validation.js';
40
+
41
+ // Signature utilities
42
+ export { SignatureUtils, getSignatureTypesAndMessage, SignatureTypes } from './signature.js';
43
+
44
+ // Storage utilities
45
+ export {
46
+ permitStore,
47
+ getPermit,
48
+ getActivePermit,
49
+ getPermits,
50
+ setPermit,
51
+ removePermit,
52
+ getActivePermitHash,
53
+ setActivePermitHash,
54
+ removeActivePermitHash,
55
+ clearStaleStore,
56
+ PERMIT_STORE_DEFAULTS,
57
+ } from './store.js';
58
+
59
+ // Sealing utilities
60
+ export { SealingKey, GenerateSealingKey } from './sealing.js';
61
+ export type { EthEncryptedData } from './sealing.js';
62
+
63
+ // Re-export everything for convenience
64
+ export * from './types.js';
65
+ export * from './permit.js';
66
+ export * from './validation.js';
67
+ export * from './signature.js';
68
+ export * from './store.js';
@@ -0,0 +1,117 @@
1
+ /**
2
+ * @vitest-environment happy-dom
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import {
7
+ getPermit,
8
+ setPermit,
9
+ removePermit,
10
+ getActivePermitHash,
11
+ setActivePermitHash,
12
+ PermitUtils,
13
+ permitStore,
14
+ } from './index.js';
15
+ import { createMockPermit } from './test-utils.js';
16
+
17
+ // Type declarations for happy-dom environment
18
+ declare const localStorage: {
19
+ clear: () => void;
20
+ getItem: (name: string) => string | null;
21
+ setItem: (name: string, value: string) => void;
22
+ };
23
+
24
+ describe('Permits localStorage Tests', () => {
25
+ const chainId = 1;
26
+ const account = '0x1234567890123456789012345678901234567890';
27
+
28
+ beforeEach(() => {
29
+ // Clear localStorage and reset store state
30
+ localStorage.clear();
31
+ permitStore.resetStore();
32
+ });
33
+
34
+ afterEach(() => {
35
+ // Clean up after each test
36
+ localStorage.clear();
37
+ permitStore.resetStore();
38
+ });
39
+
40
+ it('should persist permits to localStorage', async () => {
41
+ const permit = await createMockPermit();
42
+ const hash = PermitUtils.getHash(permit);
43
+
44
+ setPermit(chainId, account, permit);
45
+
46
+ // Verify data is stored in localStorage
47
+ const storedData = localStorage.getItem('cofhesdk-permits');
48
+ expect(storedData).toBeDefined();
49
+
50
+ const parsedData = JSON.parse(storedData!);
51
+ expect(parsedData.state.permits[chainId][account][hash]).toBeDefined();
52
+ });
53
+
54
+ it('should persist active permit hash to localStorage', async () => {
55
+ const permit = await createMockPermit();
56
+ const hash = PermitUtils.getHash(permit);
57
+
58
+ setPermit(chainId, account, permit);
59
+ setActivePermitHash(chainId, account, hash);
60
+
61
+ // Verify active permit hash is stored
62
+ const storedData = localStorage.getItem('cofhesdk-permits');
63
+ expect(storedData).toBeDefined();
64
+
65
+ const parsedData = JSON.parse(storedData!);
66
+ expect(parsedData.state.activePermitHash[chainId][account]).toBe(hash);
67
+ });
68
+
69
+ it('should restore permits from localStorage', async () => {
70
+ const permit = await createMockPermit();
71
+ const hash = PermitUtils.getHash(permit);
72
+
73
+ // Add permit to localStorage
74
+ setPermit(chainId, account, permit);
75
+ setActivePermitHash(chainId, account, hash);
76
+ const serializedPermit = PermitUtils.serialize(permit);
77
+
78
+ // Verify data is restored
79
+ const retrievedPermit = getPermit(chainId, account, hash);
80
+ expect(retrievedPermit).toBeDefined();
81
+ expect(PermitUtils.serialize(retrievedPermit!)).toEqual(serializedPermit);
82
+
83
+ const activeHash = getActivePermitHash(chainId, account);
84
+ expect(activeHash).toBe(hash);
85
+ });
86
+
87
+ it('should handle corrupted localStorage data gracefully', () => {
88
+ // Set invalid JSON in localStorage
89
+ localStorage.setItem('cofhesdk-permits', 'invalid json');
90
+
91
+ // Store should handle this gracefully
92
+ expect(() => {
93
+ permitStore.store.getState();
94
+ }).not.toThrow();
95
+ });
96
+
97
+ it('should clean up localStorage when permits are removed', async () => {
98
+ const permit = await createMockPermit();
99
+ const hash = PermitUtils.getHash(permit);
100
+
101
+ setPermit(chainId, account, permit);
102
+ setActivePermitHash(chainId, account, hash);
103
+
104
+ // Verify data exists
105
+ let storedData = localStorage.getItem('cofhesdk-permits');
106
+ expect(storedData).toBeDefined();
107
+
108
+ // Remove permit
109
+ removePermit(chainId, account, hash, true);
110
+
111
+ // Verify data is cleaned up
112
+ storedData = localStorage.getItem('cofhesdk-permits');
113
+ const parsedData = JSON.parse(storedData!);
114
+ expect(parsedData.state.permits[chainId][account][hash]).toBeUndefined();
115
+ expect(parsedData.state.activePermitHash[chainId][account]).toBeUndefined();
116
+ });
117
+ });