chunktech 0.2.0 → 0.3.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/README.md CHANGED
@@ -2,15 +2,17 @@
2
2
 
3
3
  On-chain file storage via chunked transactions for EVM chains.
4
4
 
5
- Store and retrieve files on Ethereum, Base, and Arbitrum using transaction calldata.
5
+ Store and retrieve files on Ethereum, Base, and Arbitrum using transaction calldata. Includes specialized support for censorship-resistant browser extension distribution.
6
6
 
7
7
  ## Features
8
8
 
9
9
  - **Chunk** - Split files into 33.3KB pieces for on-chain storage
10
- - **Send** - Broadcast chunks as transactions
10
+ - **Send** - Broadcast chunks as self-transfer transactions
11
11
  - **Track** - Monitor transaction confirmations
12
12
  - **Reassemble** - Reconstruct files from on-chain data
13
13
  - **Encrypt** - Optional X3DH encryption for private data
14
+ - **Cross-Chain** - Store data on L2, pointer on mainnet
15
+ - **Extensions** - Distribute Chrome/Firefox extensions via inscriptions
14
16
 
15
17
  ## Installation
16
18
 
@@ -23,27 +25,6 @@ For encryption support:
23
25
  npm install @noble/curves @noble/hashes
24
26
  ```
25
27
 
26
- ## Configuration
27
-
28
- Copy `.env.example` to `.env` and configure:
29
-
30
- ```bash
31
- cp .env.example .env
32
- ```
33
-
34
- ```env
35
- # Private key for signing transactions (without 0x prefix)
36
- PRIVATE_KEY=your_private_key_here
37
-
38
- # RPC URLs (optional - uses public RPCs if not set)
39
- RPC_BASE=https://mainnet.base.org
40
- RPC_ARBITRUM=https://arb1.arbitrum.io/rpc
41
- RPC_ETHEREUM=https://eth.llamarpc.com
42
-
43
- # Default chain
44
- DEFAULT_CHAIN=base
45
- ```
46
-
47
28
  ## Quick Start
48
29
 
49
30
  ```typescript
@@ -52,157 +33,220 @@ import { createWalletClient, http } from 'viem';
52
33
  import { base } from 'viem/chains';
53
34
  import { privateKeyToAccount } from 'viem/accounts';
54
35
 
55
- // Load from environment
56
36
  const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`);
57
37
  const walletClient = createWalletClient({
58
38
  account,
59
39
  chain: base,
60
- transport: http(process.env.RPC_BASE),
40
+ transport: http(),
61
41
  });
62
42
 
63
- // Initialize ChunkTech
64
43
  const ct = new ChunkTech({ walletClient });
65
44
 
66
- // Upload a file
67
- const file = new Uint8Array([...]); // Your file data
68
- const result = await ct.upload(file, {
69
- onProgress: (sent, total) => console.log(`${sent}/${total} chunks sent`),
45
+ // Upload
46
+ const result = await ct.upload(fileData, {
47
+ onProgress: (sent, total) => console.log(`${sent}/${total}`),
70
48
  });
71
49
 
72
- console.log('Chunk ID:', result.chunkId);
73
- console.log('TX Hashes:', result.txHashes);
74
-
75
- // Download the file
50
+ // Download
76
51
  const downloaded = await ct.download(result.txHashes);
77
- console.log('Retrieved:', downloaded.data);
78
52
  ```
79
53
 
80
- ## API
54
+ ## Browser Extension Distribution
81
55
 
82
- ### `new ChunkTech(config)`
56
+ Distribute Chrome and Firefox extensions as on-chain inscriptions. The inscription itself is the installer - a self-contained HTML page that fetches extension data from L2 and offers downloads.
83
57
 
84
- Create a new ChunkTech instance.
58
+ ```
59
+ ┌─────────────────────────────────────────────────────────┐
60
+ │ Inscription (Ethereum) │
61
+ │ │
62
+ │ Self-contained HTML that: │
63
+ │ ├── Shows extension info + download buttons │
64
+ │ ├── Fetches chunks from Base via RPC │
65
+ │ ├── Reassembles + verifies SHA256 │
66
+ │ └── Downloads as .zip (Chrome) or .xpi (Firefox) │
67
+ │ │
68
+ └─────────────────────────────────────────────────────────┘
69
+ ```
70
+
71
+ ### Upload Extension
85
72
 
86
73
  ```typescript
87
- interface ChunkTechConfig {
88
- walletClient: WalletClient; // viem WalletClient for signing
89
- publicClient?: PublicClient; // Optional, created from walletClient if not provided
90
- chain?: Chain; // Optional, detected from walletClient
91
- rpcUrl?: string; // Optional custom RPC URL
92
- }
93
- ```
74
+ import { ExtensionUploader } from 'chunktech';
75
+ import { createWalletClient, http } from 'viem';
76
+ import { base, mainnet } from 'viem/chains';
77
+ import { privateKeyToAccount } from 'viem/accounts';
78
+ import { readFileSync } from 'fs';
94
79
 
95
- ### `upload(data, options)`
80
+ const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`);
96
81
 
97
- Upload data to the blockchain.
82
+ const uploader = new ExtensionUploader({
83
+ keyChain: 'ethereum', // Inscription lives here (1 tx)
84
+ dataChain: 'base', // Extension data lives here (cheap)
85
+ keyWalletClient: createWalletClient({
86
+ account,
87
+ chain: mainnet,
88
+ transport: http(),
89
+ }),
90
+ dataWalletClient: createWalletClient({
91
+ account,
92
+ chain: base,
93
+ transport: http(),
94
+ }),
95
+ });
98
96
 
99
- ```typescript
100
- const result = await ct.upload(data, {
101
- encrypt: false, // Enable encryption
102
- keys: encryptionKeys, // Required if encrypt: true
103
- recipients: [...], // Recipients for encrypted data
104
- onProgress: (sent, total) => {}, // Progress callback
105
- confirmations: 1, // Wait for confirmations
97
+ const result = await uploader.upload({
98
+ name: 'My Extension',
99
+ version: '1.0.0',
100
+ developer: 'vitalik.eth',
101
+ description: 'A censorship-resistant browser extension',
102
+ homepage: 'https://myextension.xyz',
103
+ chrome: readFileSync('dist/chrome.zip'),
104
+ firefox: readFileSync('dist/firefox.xpi'),
105
+ }, {
106
+ onProgress: (phase, sent, total) => {
107
+ console.log(`${phase}: ${sent}/${total}`);
108
+ },
106
109
  });
107
110
 
108
- // Returns:
109
- {
110
- chunkId: string; // Unique ID for this upload
111
- txHashes: Hash[]; // Transaction hashes
112
- totalChunks: number; // Number of chunks sent
113
- totalBytes: number; // Original data size
114
- }
111
+ console.log('Inscription TX:', result.inscriptionTxHash);
112
+ // View at: https://ethscriptions.com/ethscriptions/0x...
115
113
  ```
116
114
 
117
- ### `download(txHashes, options)`
115
+ ### What Users See
116
+
117
+ The inscription renders as a download page:
118
+
119
+ ```
120
+ ╔═══════════════════════════════════════════════════╗
121
+ ║ My Extension v1.0.0 ║
122
+ ║ vitalik.eth ║
123
+ ╚═══════════════════════════════════════════════════╝
124
+
125
+ A censorship-resistant browser extension
126
+
127
+ ┌─────────────────┐ ┌─────────────────┐
128
+ │ Chrome/Brave │ │ Firefox │
129
+ │ [Detected] │ │ │
130
+ │ [Download] │ │ [Download] │
131
+ │ 142 KB │ │ 138 KB │
132
+ └─────────────────┘ └─────────────────┘
133
+
134
+ Installation Instructions:
135
+ 1. Download the extension
136
+ 2. Unzip (Chrome) or keep as .xpi (Firefox)
137
+ 3. Load in developer mode / Install from file
138
+ ```
118
139
 
119
- Download and reassemble data from the blockchain.
140
+ ### Why This Matters
141
+
142
+ - **Censorship-resistant** - No app store can remove it
143
+ - **Immutable** - Code is permanently on-chain
144
+ - **Verifiable** - SHA256 verified on download
145
+ - **Self-contained** - The inscription IS the installer
146
+ - **Multi-browser** - Chrome, Brave, Edge, Firefox from one inscription
147
+
148
+ ## Cross-Chain Upload
149
+
150
+ Store bulk data on L2 (cheap), pointer on mainnet (durable):
120
151
 
121
152
  ```typescript
122
- const result = await ct.download(txHashes, {
123
- keys: encryptionKeys, // Required if data was encrypted
124
- recipientId: 'myId', // Required if data was encrypted
153
+ import { CrossChainUploader } from 'chunktech';
154
+
155
+ const uploader = new CrossChainUploader({
156
+ keyChain: 'ethereum',
157
+ dataChain: 'base',
158
+ keyWalletClient,
159
+ dataWalletClient,
125
160
  });
126
161
 
127
- // Returns:
128
- {
129
- data: Uint8Array; // The reassembled file
130
- chunkId: string; // Chunk set ID
131
- totalChunks: number; // Number of chunks retrieved
132
- }
133
- ```
162
+ const result = await uploader.upload(fileData, {
163
+ format: 'html',
164
+ title: 'My File',
165
+ });
134
166
 
135
- ## Encryption
167
+ // result.keyTxHash = mainnet inscription (self-loading HTML)
168
+ // result.dataTxHashes = Base data chunks
169
+ ```
136
170
 
137
- ChunkTech supports optional X3DH encryption for private data.
171
+ ## API Reference
138
172
 
139
- ```typescript
140
- import { generateEncryptionKeys, deriveKeysFromSignature } from 'chunktech';
173
+ ### ChunkTech
141
174
 
142
- // Generate new keys
143
- const myKeys = await generateEncryptionKeys();
175
+ Main class for single-chain uploads.
144
176
 
145
- // Or derive from wallet signature (deterministic)
146
- const signature = await wallet.signMessage('chunktech-keys');
147
- const myKeys = await deriveKeysFromSignature(signature);
177
+ ```typescript
178
+ const ct = new ChunkTech({
179
+ walletClient: WalletClient, // viem wallet
180
+ publicClient?: PublicClient, // Optional
181
+ chain?: Chain, // Auto-detected
182
+ rpcUrl?: string, // Custom RPC
183
+ });
148
184
 
149
- // Upload encrypted data
150
- await ct.upload(data, {
151
- encrypt: true,
152
- keys: myKeys,
153
- recipients: [
154
- { id: 'alice', bundle: aliceBundle },
155
- { id: 'bob', bundle: bobBundle },
156
- ],
185
+ // Upload
186
+ const result = await ct.upload(data, {
187
+ encrypt?: boolean,
188
+ keys?: EncryptionKeys,
189
+ recipients?: Recipient[],
190
+ onProgress?: (sent, total) => void,
191
+ confirmations?: number,
157
192
  });
158
193
 
159
- // Download encrypted data
194
+ // Download
160
195
  const result = await ct.download(txHashes, {
161
- keys: myKeys,
162
- recipientId: 'sender', // Use 'sender' if you're the uploader
196
+ keys?: EncryptionKeys,
197
+ recipientId?: string,
163
198
  });
164
199
  ```
165
200
 
166
- ## Cross-Chain Upload
201
+ ### ExtensionUploader
167
202
 
168
- Store key transaction on mainnet, bulk data on L2 for cost savings:
203
+ Specialized uploader for browser extensions.
169
204
 
170
205
  ```typescript
171
- import { CrossChainUploader } from 'chunktech';
172
-
173
- const uploader = new CrossChainUploader({
174
- keyChain: 'ethereum', // Key/manifest goes here
175
- dataChain: 'base', // Bulk chunks go here
176
- keyWalletClient, // Wallet for mainnet
177
- dataWalletClient, // Wallet for Base
206
+ const uploader = new ExtensionUploader({
207
+ keyChain: 'ethereum' | 'sepolia',
208
+ dataChain: 'base' | 'baseSepolia',
209
+ keyWalletClient: WalletClient,
210
+ dataWalletClient: WalletClient,
211
+ keyRpcUrl?: string,
212
+ dataRpcUrl?: string,
178
213
  });
179
214
 
180
- const result = await uploader.upload(fileData, {
181
- format: 'html', // Self-loading HTML inscription
182
- title: 'My File',
183
- onProgress: (phase, sent, total) => {
184
- console.log(`${phase}: ${sent}/${total}`);
185
- },
215
+ const result = await uploader.upload({
216
+ name: string,
217
+ version: string,
218
+ developer: string,
219
+ description?: string,
220
+ homepage?: string,
221
+ chrome?: Uint8Array,
222
+ firefox?: Uint8Array,
223
+ }, {
224
+ onProgress?: (phase, sent, total) => void,
225
+ confirmations?: number,
186
226
  });
187
-
188
- console.log('Mainnet TX:', result.keyTxHash);
189
- console.log('Base TXs:', result.dataTxHashes);
190
227
  ```
191
228
 
192
- **Architecture:**
193
- - **Mainnet TX** = The "unchunker" (HTML loader with manifest)
194
- - **Base TXs** = ALL data chunks (100% of file data on L2)
229
+ ### CrossChainUploader
195
230
 
196
- The mainnet inscription is self-contained and:
197
- - Fetches ALL chunks from Base L2 via RPC
198
- - Reassembles and verifies SHA256
199
- - Provides download button
231
+ General-purpose cross-chain uploader with HTML loader.
200
232
 
201
- No data on mainnet - just the key that knows how to unchunk from L2.
233
+ ```typescript
234
+ const uploader = new CrossChainUploader({
235
+ keyChain: ChainName,
236
+ dataChain: ChainName,
237
+ keyWalletClient: WalletClient,
238
+ dataWalletClient: WalletClient,
239
+ });
202
240
 
203
- ## Low-Level API
241
+ const result = await uploader.upload(data, {
242
+ format?: 'html' | 'json',
243
+ title?: string,
244
+ description?: string,
245
+ mimeType?: string,
246
+ });
247
+ ```
204
248
 
205
- For more control, use the individual modules:
249
+ ### Low-Level Utilities
206
250
 
207
251
  ```typescript
208
252
  import {
@@ -212,76 +256,152 @@ import {
212
256
  decodeChunk,
213
257
  reassembleChunks,
214
258
  ChunkTracker,
259
+ estimateChunks,
215
260
 
216
261
  // Sending
217
262
  sendChunk,
218
263
  sendChunks,
264
+ sendChunksParallel,
219
265
 
220
266
  // Tracking
267
+ waitForTransaction,
221
268
  waitForTransactions,
222
269
  TransactionMonitor,
223
270
 
224
271
  // Fetching
225
272
  fetchChunk,
273
+ fetchChunks,
226
274
  assembleFromHashes,
227
275
  StreamingAssembler,
276
+
277
+ // Encryption
278
+ generateEncryptionKeys,
279
+ deriveKeysFromSignature,
280
+ encryptForRecipients,
281
+ decryptForRecipient,
228
282
  } from 'chunktech';
229
283
  ```
230
284
 
231
- ### Chunking
285
+ ## Encryption
286
+
287
+ Optional X3DH + AES-256-GCM encryption for private data.
232
288
 
233
289
  ```typescript
234
- // Split data into chunks
235
- const chunked = chunkData(myData);
236
- console.log(`${chunked.total} chunks, ID: ${chunked.id}`);
290
+ import { generateEncryptionKeys } from 'chunktech';
237
291
 
238
- // Encode for on-chain storage
239
- const calldata = encodeChunk(chunked.chunks[0]);
292
+ const myKeys = await generateEncryptionKeys();
240
293
 
241
- // Decode from calldata
242
- const chunk = decodeChunk(calldata);
294
+ // Upload encrypted
295
+ await ct.upload(data, {
296
+ encrypt: true,
297
+ keys: myKeys,
298
+ recipients: [
299
+ { id: 'alice', bundle: aliceKeys.bundle },
300
+ ],
301
+ });
302
+
303
+ // Download encrypted
304
+ const result = await ct.download(txHashes, {
305
+ keys: myKeys,
306
+ recipientId: 'sender',
307
+ });
243
308
  ```
244
309
 
245
- ### Streaming Reassembly
310
+ ## Supported Chains
311
+
312
+ | Chain | ID | Use Case |
313
+ |-------|-----|----------|
314
+ | Ethereum | 1 | Inscriptions, durability |
315
+ | Base | 8453 | Cheap data storage |
316
+ | Arbitrum | 42161 | Cheap data storage |
317
+ | Sepolia | 11155111 | Testing |
318
+ | Base Sepolia | 84532 | Testing |
319
+ | Arbitrum Sepolia | 421614 | Testing |
320
+
321
+ ## Cost Estimates
322
+
323
+ For a 500KB extension on Base:
246
324
 
247
- ```typescript
248
- const tracker = new ChunkTracker();
249
-
250
- for (const txHash of incomingHashes) {
251
- const result = await fetchChunk(publicClient, txHash);
252
- if (result.chunk) {
253
- const assembled = tracker.add(result.chunk);
254
- if (assembled) {
255
- console.log('Complete!', assembled);
256
- }
257
- }
258
- }
259
-
260
- // Check progress
261
- console.log(tracker.getIncomplete());
262
- // [{ id: '...', have: 2, need: 5 }]
263
325
  ```
326
+ Chunks: ~15 (at 33KB each)
327
+ Cost per chunk: ~$0.002
328
+ Total: ~$0.03
264
329
 
265
- ## Supported Chains
330
+ + 1 Ethereum inscription: ~$2-5 (varies with gas)
331
+ ```
266
332
 
267
- | Chain | Chain ID |
268
- |-------|----------|
269
- | Ethereum | 1 |
270
- | Base | 8453 |
271
- | Arbitrum | 42161 |
272
- | Sepolia | 11155111 |
273
- | Base Sepolia | 84532 |
274
- | Arbitrum Sepolia | 421614 |
333
+ ## How It Works
275
334
 
276
- ## Constants
335
+ 1. **Chunking** - Files split into 33.3KB pieces with metadata (ID, part, total)
336
+ 2. **Encoding** - Each chunk → JSON → base64 → prefixed calldata
337
+ 3. **Sending** - Self-transfer transactions (to == from, value = 0)
338
+ 4. **Storage** - Calldata stored permanently in transaction history
339
+ 5. **Retrieval** - Fetch via `eth_getTransactionByHash`, decode, reassemble
340
+ 6. **Verification** - SHA256 hash checked after reassembly
277
341
 
278
- ```typescript
279
- import { MAX_CHUNK_SIZE } from 'chunktech';
342
+ ## On-Chain Viewer Pages
343
+
344
+ Create standalone HTML pages that fetch, verify, and display on-chain content. Perfect for:
345
+ - NPM packages with auditable source
346
+ - Browser extensions with install instructions
347
+ - Any file needing public verification
348
+
349
+ ### Quick Inscribe
350
+
351
+ ```javascript
352
+ import { readFileSync } from 'fs';
353
+ import { createWalletClient, http, toHex } from 'viem';
354
+ import { base } from 'viem/chains';
355
+ import { createHash } from 'crypto';
280
356
 
281
- // MAX_CHUNK_SIZE = 33333 (33.3KB)
282
- // This ensures wrapped chunks stay under 128KB tx limit
357
+ const zipData = readFileSync('package.zip');
358
+ const base64 = zipData.toString('base64');
359
+ const sha256 = createHash('sha256').update(zipData).digest('hex');
360
+
361
+ const dataUri = `data:application/zip;base64,${base64}`;
362
+ const calldata = toHex(new TextEncoder().encode(dataUri));
363
+
364
+ const hash = await walletClient.sendTransaction({
365
+ to: account.address,
366
+ data: calldata,
367
+ });
368
+
369
+ console.log(`TX: ${hash}`);
370
+ console.log(`SHA256: ${sha256}`);
283
371
  ```
284
372
 
373
+ ### Viewer HTML
374
+
375
+ The viewer fetches from any RPC, verifies SHA256, and displays source:
376
+
377
+ ```
378
+ ┌─────────────────────────────────────────┐
379
+ │ MyPackage v1.0.0 │
380
+ │ │
381
+ │ [Download] [Verify On-Chain] │
382
+ │ │
383
+ │ ┌─────────────────────────────────┐ │
384
+ │ │ README │ index.ts │ package.json│ │
385
+ │ ├─────────────────────────────────┤ │
386
+ │ │ │ │
387
+ │ │ // Source code displayed here │ │
388
+ │ │ │ │
389
+ │ └─────────────────────────────────┘ │
390
+ └─────────────────────────────────────────┘
391
+ ```
392
+
393
+ Key features:
394
+ - Fetches tx via public RPC (no backend)
395
+ - SHA256 verification on download
396
+ - Source code tabs for auditing
397
+ - Works offline once loaded
398
+
399
+ See `skill.md` for full implementation details.
400
+
401
+ ## Acknowledgments
402
+
403
+ - [calldata-rpc](https://github.com/chopperdaddy/calldata-rpc) by [@chopperdaddy](https://github.com/chopperdaddy) - Decentralized RPC endpoint discovery via IPFS and ENS, used in the HTML loaders for reliable chain access.
404
+
285
405
  ## License
286
406
 
287
407
  MIT
@@ -1 +1 @@
1
- {"version":3,"file":"crosschain.d.ts","sourceRoot":"","sources":["../src/crosschain.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAEV,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAuBpB,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,gBAAgB,CAAe;IAEvC,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,SAAS,CAAY;gBAEjB,MAAM,EAAE,gBAAgB;IAiBpC;;OAEG;IACG,MAAM,CACV,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,MAAM,EACvC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC;CAwFnC;AAMD,iBAAS,kBAAkB,CACzB,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9C,MAAM,CAwHR;AA0ED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"crosschain.d.ts","sourceRoot":"","sources":["../src/crosschain.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAEV,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAuBpB,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,gBAAgB,CAAe;IAEvC,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,SAAS,CAAY;gBAEjB,MAAM,EAAE,gBAAgB;IAiBpC;;OAEG;IACG,MAAM,CACV,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,MAAM,EACvC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC;CAwFnC;AAMD,iBAAS,kBAAkB,CACzB,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9C,MAAM,CA+IR;AA0ED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -172,9 +172,23 @@ h1{font-size:1.5rem;margin-bottom:8px;background:linear-gradient(135deg,#667eea,
172
172
  </div>
173
173
  <script>
174
174
  const M=${JSON.stringify(manifest)};
175
- const RPC={8453:"https://mainnet.base.org",42161:"https://arb1.arbitrum.io/rpc",84532:"https://sepolia.base.org",421614:"https://sepolia-rollup.arbitrum.io/rpc"};
175
+ // RPC discovery via calldata-rpc (https://github.com/chopperdaddy/calldata-rpc)
176
+ // Decentralized RPC endpoints hosted on IPFS via ENS
177
+ const TESTNET_RPC={84532:"https://sepolia.base.org",421614:"https://sepolia-rollup.arbitrum.io/rpc"};
176
178
 
177
- async function fetchChunk(rpc,hash){
179
+ async function getRpcUrls(chainId){
180
+ if(TESTNET_RPC[chainId])return[TESTNET_RPC[chainId]];
181
+ const endpoints=["https://rpcs.calldata.eth.limo","https://rpcs.calldata.eth.link"];
182
+ for(const base of endpoints){
183
+ try{
184
+ const r=await fetch(base);
185
+ if(r.ok){const d=await r.json();if(d[chainId]&&Array.isArray(d[chainId]))return d[chainId];}
186
+ }catch(e){}
187
+ }
188
+ return[];
189
+ }
190
+
191
+ async function fetchChunkFromRpc(rpc,hash){
178
192
  const r=await fetch(rpc,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",method:"eth_getTransactionByHash",params:[hash],id:1})});
179
193
  const j=await r.json();
180
194
  if(!j.result||!j.result.input)throw new Error("TX not found: "+hash);
@@ -191,19 +205,28 @@ async function fetchChunk(rpc,hash){
191
205
  return{part:payload.part,data};
192
206
  }
193
207
 
208
+ async function fetchChunk(rpcs,hash){
209
+ let lastErr;
210
+ for(const rpc of rpcs){
211
+ try{return await fetchChunkFromRpc(rpc,hash);}catch(e){lastErr=e;}
212
+ }
213
+ throw lastErr||new Error("No RPCs available");
214
+ }
215
+
194
216
  async function load(){
195
217
  const status=document.getElementById("status");
196
218
  const progress=document.getElementById("progress");
197
219
  const error=document.getElementById("error");
198
220
  const download=document.getElementById("download");
199
- const rpc=RPC[M.dataChainId];
200
- if(!rpc){error.textContent="Unsupported chain: "+M.dataChainId;error.style.display="block";return;}
221
+ status.textContent="Discovering RPC endpoints...";
222
+ const rpcs=await getRpcUrls(M.dataChainId);
223
+ if(!rpcs.length){error.textContent="No RPC endpoints for chain: "+M.dataChainId;error.style.display="block";return;}
201
224
  const chunks=[];
202
225
  try{
203
226
  // Fetch ALL chunks from L2
204
227
  for(let i=0;i<M.dataTxHashes.length;i++){
205
228
  status.textContent="Loading chunk "+(i+1)+"/"+M.totalChunks+" from "+M.dataChain+"...";
206
- const chunk=await fetchChunk(rpc,M.dataTxHashes[i]);
229
+ const chunk=await fetchChunk(rpcs,M.dataTxHashes[i]);
207
230
  chunks.push(chunk);
208
231
  progress.style.width=((i+1)/M.totalChunks*100)+"%";
209
232
  }
@@ -1 +1 @@
1
- {"version":3,"file":"crosschain.js","sourceRoot":"","sources":["../src/crosschain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crosschain.js","sourceRoot":"","sources":["../src/crosschain.ts"],"names":[],"mappings":"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"}