New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

chunktech

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

chunktech

On-chain file storage via chunked transactions for EVM chains

latest
npmnpm
Version
0.3.0
Version published
Maintainers
1
Created
Source

ChunkTech

On-chain file storage via chunked transactions for EVM chains.

Store and retrieve files on Ethereum, Base, and Arbitrum using transaction calldata. Includes specialized support for censorship-resistant browser extension distribution.

Features

  • Chunk - Split files into 33.3KB pieces for on-chain storage
  • Send - Broadcast chunks as self-transfer transactions
  • Track - Monitor transaction confirmations
  • Reassemble - Reconstruct files from on-chain data
  • Encrypt - Optional X3DH encryption for private data
  • Cross-Chain - Store data on L2, pointer on mainnet
  • Extensions - Distribute Chrome/Firefox extensions via inscriptions

Installation

npm install chunktech viem

For encryption support:

npm install @noble/curves @noble/hashes

Quick Start

import { ChunkTech } from 'chunktech';
import { createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`);
const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(),
});

const ct = new ChunkTech({ walletClient });

// Upload
const result = await ct.upload(fileData, {
  onProgress: (sent, total) => console.log(`${sent}/${total}`),
});

// Download
const downloaded = await ct.download(result.txHashes);

Browser Extension Distribution

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.

┌─────────────────────────────────────────────────────────┐
│  Inscription (Ethereum)                                 │
│                                                         │
│  Self-contained HTML that:                              │
│  ├── Shows extension info + download buttons            │
│  ├── Fetches chunks from Base via RPC                   │
│  ├── Reassembles + verifies SHA256                      │
│  └── Downloads as .zip (Chrome) or .xpi (Firefox)       │
│                                                         │
└─────────────────────────────────────────────────────────┘

Upload Extension

import { ExtensionUploader } from 'chunktech';
import { createWalletClient, http } from 'viem';
import { base, mainnet } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';
import { readFileSync } from 'fs';

const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`);

const uploader = new ExtensionUploader({
  keyChain: 'ethereum',     // Inscription lives here (1 tx)
  dataChain: 'base',        // Extension data lives here (cheap)
  keyWalletClient: createWalletClient({
    account,
    chain: mainnet,
    transport: http(),
  }),
  dataWalletClient: createWalletClient({
    account,
    chain: base,
    transport: http(),
  }),
});

const result = await uploader.upload({
  name: 'My Extension',
  version: '1.0.0',
  developer: 'vitalik.eth',
  description: 'A censorship-resistant browser extension',
  homepage: 'https://myextension.xyz',
  chrome: readFileSync('dist/chrome.zip'),
  firefox: readFileSync('dist/firefox.xpi'),
}, {
  onProgress: (phase, sent, total) => {
    console.log(`${phase}: ${sent}/${total}`);
  },
});

console.log('Inscription TX:', result.inscriptionTxHash);
// View at: https://ethscriptions.com/ethscriptions/0x...

What Users See

The inscription renders as a download page:

╔═══════════════════════════════════════════════════╗
║         My Extension v1.0.0                       ║
║         vitalik.eth                               ║
╚═══════════════════════════════════════════════════╝

A censorship-resistant browser extension

┌─────────────────┐    ┌─────────────────┐
│  Chrome/Brave   │    │    Firefox      │
│   [Detected]    │    │                 │
│  [Download]     │    │  [Download]     │
│   142 KB        │    │   138 KB        │
└─────────────────┘    └─────────────────┘

Installation Instructions:
1. Download the extension
2. Unzip (Chrome) or keep as .xpi (Firefox)
3. Load in developer mode / Install from file

Why This Matters

  • Censorship-resistant - No app store can remove it
  • Immutable - Code is permanently on-chain
  • Verifiable - SHA256 verified on download
  • Self-contained - The inscription IS the installer
  • Multi-browser - Chrome, Brave, Edge, Firefox from one inscription

Cross-Chain Upload

Store bulk data on L2 (cheap), pointer on mainnet (durable):

import { CrossChainUploader } from 'chunktech';

const uploader = new CrossChainUploader({
  keyChain: 'ethereum',
  dataChain: 'base',
  keyWalletClient,
  dataWalletClient,
});

const result = await uploader.upload(fileData, {
  format: 'html',
  title: 'My File',
});

// result.keyTxHash = mainnet inscription (self-loading HTML)
// result.dataTxHashes = Base data chunks

API Reference

ChunkTech

Main class for single-chain uploads.

const ct = new ChunkTech({
  walletClient: WalletClient,  // viem wallet
  publicClient?: PublicClient, // Optional
  chain?: Chain,               // Auto-detected
  rpcUrl?: string,             // Custom RPC
});

// Upload
const result = await ct.upload(data, {
  encrypt?: boolean,
  keys?: EncryptionKeys,
  recipients?: Recipient[],
  onProgress?: (sent, total) => void,
  confirmations?: number,
});

// Download
const result = await ct.download(txHashes, {
  keys?: EncryptionKeys,
  recipientId?: string,
});

ExtensionUploader

Specialized uploader for browser extensions.

const uploader = new ExtensionUploader({
  keyChain: 'ethereum' | 'sepolia',
  dataChain: 'base' | 'baseSepolia',
  keyWalletClient: WalletClient,
  dataWalletClient: WalletClient,
  keyRpcUrl?: string,
  dataRpcUrl?: string,
});

const result = await uploader.upload({
  name: string,
  version: string,
  developer: string,
  description?: string,
  homepage?: string,
  chrome?: Uint8Array,
  firefox?: Uint8Array,
}, {
  onProgress?: (phase, sent, total) => void,
  confirmations?: number,
});

CrossChainUploader

General-purpose cross-chain uploader with HTML loader.

const uploader = new CrossChainUploader({
  keyChain: ChainName,
  dataChain: ChainName,
  keyWalletClient: WalletClient,
  dataWalletClient: WalletClient,
});

const result = await uploader.upload(data, {
  format?: 'html' | 'json',
  title?: string,
  description?: string,
  mimeType?: string,
});

Low-Level Utilities

import {
  // Chunking
  chunkData,
  encodeChunk,
  decodeChunk,
  reassembleChunks,
  ChunkTracker,
  estimateChunks,

  // Sending
  sendChunk,
  sendChunks,
  sendChunksParallel,

  // Tracking
  waitForTransaction,
  waitForTransactions,
  TransactionMonitor,

  // Fetching
  fetchChunk,
  fetchChunks,
  assembleFromHashes,
  StreamingAssembler,

  // Encryption
  generateEncryptionKeys,
  deriveKeysFromSignature,
  encryptForRecipients,
  decryptForRecipient,
} from 'chunktech';

Encryption

Optional X3DH + AES-256-GCM encryption for private data.

import { generateEncryptionKeys } from 'chunktech';

const myKeys = await generateEncryptionKeys();

// Upload encrypted
await ct.upload(data, {
  encrypt: true,
  keys: myKeys,
  recipients: [
    { id: 'alice', bundle: aliceKeys.bundle },
  ],
});

// Download encrypted
const result = await ct.download(txHashes, {
  keys: myKeys,
  recipientId: 'sender',
});

Supported Chains

ChainIDUse Case
Ethereum1Inscriptions, durability
Base8453Cheap data storage
Arbitrum42161Cheap data storage
Sepolia11155111Testing
Base Sepolia84532Testing
Arbitrum Sepolia421614Testing

Cost Estimates

For a 500KB extension on Base:

Chunks: ~15 (at 33KB each)
Cost per chunk: ~$0.002
Total: ~$0.03

+ 1 Ethereum inscription: ~$2-5 (varies with gas)

How It Works

  • Chunking - Files split into 33.3KB pieces with metadata (ID, part, total)
  • Encoding - Each chunk → JSON → base64 → prefixed calldata
  • Sending - Self-transfer transactions (to == from, value = 0)
  • Storage - Calldata stored permanently in transaction history
  • Retrieval - Fetch via eth_getTransactionByHash, decode, reassemble
  • Verification - SHA256 hash checked after reassembly

On-Chain Viewer Pages

Create standalone HTML pages that fetch, verify, and display on-chain content. Perfect for:

  • NPM packages with auditable source
  • Browser extensions with install instructions
  • Any file needing public verification

Quick Inscribe

import { readFileSync } from 'fs';
import { createWalletClient, http, toHex } from 'viem';
import { base } from 'viem/chains';
import { createHash } from 'crypto';

const zipData = readFileSync('package.zip');
const base64 = zipData.toString('base64');
const sha256 = createHash('sha256').update(zipData).digest('hex');

const dataUri = `data:application/zip;base64,${base64}`;
const calldata = toHex(new TextEncoder().encode(dataUri));

const hash = await walletClient.sendTransaction({
  to: account.address,
  data: calldata,
});

console.log(`TX: ${hash}`);
console.log(`SHA256: ${sha256}`);

Viewer HTML

The viewer fetches from any RPC, verifies SHA256, and displays source:

┌─────────────────────────────────────────┐
│  MyPackage v1.0.0                       │
│                                         │
│  [Download]  [Verify On-Chain]          │
│                                         │
│  ┌─────────────────────────────────┐    │
│  │ README │ index.ts │ package.json│    │
│  ├─────────────────────────────────┤    │
│  │                                 │    │
│  │  // Source code displayed here  │    │
│  │                                 │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

Key features:

  • Fetches tx via public RPC (no backend)
  • SHA256 verification on download
  • Source code tabs for auditing
  • Works offline once loaded

See skill.md for full implementation details.

Acknowledgments

  • calldata-rpc by @chopperdaddy - Decentralized RPC endpoint discovery via IPFS and ENS, used in the HTML loaders for reliable chain access.

License

MIT

Keywords

ethereum

FAQs

Package last updated on 11 Jan 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts