Skip to content

Manage Files and Buckets

This guide explains how to manage your storage resources on DataHaven using the StorageHub SDK. You will learn how to request the removal of a file from the network and how to delete buckets. It's important to periodically review and clean up unused data to avoid unnecessary costs, as buckets and files incur ongoing storage fees.

Prerequisites

  • Node.js v22+ installed
  • A TypeScript project

    Need a starter project?

    If you don't have an existing project, follow these steps to create a TypeScript project you can use to follow the guides in this section:

    1. Create a new project folder by executing the following command in the terminal:

      mkdir datahaven-project && cd datahaven-project
      
    2. Initialize a package.json file using the correct command for your package manager:

      pnpm init
      
      yarn init
      
      npm init --y
      
    3. Add the TypeScript and Node type definitions to your projects using the correct command for your package manager:

      pnpm add -D typescript ts-node @types/node
      
      yarn add -D typescript ts-node @types/node
      
      npm install -D typescript ts-node @types/node
      
    4. Create a tsconfig.json file in the root of your project and paste the following configuration:

      tsconfig.json
      {
          "compilerOptions": {
              "target": "ES2022",
              "module": "nodenext",
              "moduleResolution": "NodeNext",
              "esModuleInterop": true,
              "strict": true,
              "skipLibCheck": true,
              "outDir": "dist",
              "declaration": true,
              "sourceMap": true
          },
          "include": ["src/**/*.ts"]
      }
      
    5. Initialize the src directory:

      mkdir src && touch src/index.ts
      
  • A file uploaded to DataHaven, along with the file key

Install Dependencies

pnpm add @storagehub-sdk/core @storagehub-sdk/msp-client @storagehub/types-bundle @polkadot/api @storagehub/api-augment viem
yarn add @storagehub-sdk/core @storagehub-sdk/msp-client @storagehub/types-bundle @polkadot/api @storagehub/api-augment viem
npm install @storagehub-sdk/core @storagehub-sdk/msp-client @storagehub/types-bundle @polkadot/api @storagehub/api-augment viem

Initialize Clients and Authenticate MSP Client

First, you'll need to set up the necessary clients to connect to the DataHaven network, which runs on a dual-protocol architecture (Substrate for core logic and EVM for compatibility).

If you've already followed the Upload a File guide, your clients may already be initialized and your MSP client authenticated. In that case, review the placeholders at the bottom of the following snippet to see where you'll add logic in this guide, then skip ahead to Request file deletion.

Create an index.ts and add the following code:

index.ts
import '@storagehub/api-augment';
import { ApiPromise, WsProvider } from '@polkadot/api';
import { types } from '@storagehub/types-bundle';
import {
  HttpClientConfig,
  StorageHubClient,
  initWasm,
} from '@storagehub-sdk/core';
import { HealthStatus, MspClient, FileInfo } from '@storagehub-sdk/msp-client';
import {
  Chain,
  PublicClient,
  WalletClient,
  createPublicClient,
  createWalletClient,
  defineChain,
  http,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';


async function run() {
  // For anything from @storagehub-sdk/core to work, initWasm() is required
  // on top of the file
  await initWasm();

  // --- viem setup ---
  // Define DataHaven chain, as expected by viem
  const chain: Chain = defineChain({
    id: 55931,
    name: 'DataHaven Testnet',
    nativeCurrency: { name: 'Mock', symbol: 'MOCK', decimals: 18 },
    rpcUrls: {
      default: { http: ['https://services.datahaven-testnet.network/testnet'] },
    },
  });

  // Define account from a private key
  const account = privateKeyToAccount('INSERT_PRIVATE_KEY' as `0x${string}`);
  const address = account.address;

  // Create a wallet client using the defined chain, account, and RPC URL
  const walletClient: WalletClient = createWalletClient({
    chain,
    account,
    transport: http('https://services.datahaven-testnet.network/testnet'),
  });

  // Create a public client using the defined chain and RPC URL
  const publicClient: PublicClient = createPublicClient({
    chain,
    transport: http('https://services.datahaven-testnet.network/testnet'),
  });

  // --- Polkadot.js API setup ---
  const provider = new WsProvider(
    'wss://services.datahaven-testnet.network/testnet'
  );
  const polkadotApi: ApiPromise = await ApiPromise.create({
    provider,
    typesBundle: types,
    noInitWarn: true,
  });

  // Initialize StorageHub Client
  const storageHubClient = new StorageHubClient({
    rpcUrl: 'https://services.datahaven-testnet.network/testnet',
    chain: chain,
    walletClient: walletClient,
    filesystemContractAddress:
      '0x0000000000000000000000000000000000000404' as `0x${string}`,
  });

  // --- Data deletion logic ---
  // **PLACEHOLDER FOR STEP 1: REQUEST FILE DELETION**
  // **PLACEHOLDER FOR STEP 2: DELETE A BUCKET**

  // Disconnect the Polkadot API at the very end
  await polkadotApi.disconnect();
}

await run();

Request File Deletion

Add the code below to remove a specific file from the DataHaven network. You’ll first fetch the file’s metadata from the MSP, format it for on-chain compatibility, and then submit a deletion request using the StorageHub SDK.

const bucketId = 'INSERT_BUCKET_ID'; // `0x${string}`
const fileKey = 'INSERT_FILE_KEY'; // `0x${string}`
// If not in hex already convert it with .toHex()

// Get file info before deletion
const fileInfo: FileInfo = await mspClient.files.getFileInfo(
  bucketId,
  fileKey
);
console.log('File info before deletion:', fileInfo);

let formattedFileInfo: any = fileInfo;
['fileKey', 'fingerprint', 'bucketId'].forEach(
  (k) => (formattedFileInfo[k] = '0x' + formattedFileInfo[k])
);

console.log('Formatted file info for deletion:', formattedFileInfo);

// Request file deletion
const txHashRequestDeleteFile: `0x${string}` =
  await storageHubClient.requestDeleteFile(formattedFileInfo);
console.log('requestDeleteFile() txHash:', txHashRequestDeleteFile);

// Wait for delete file transaction receipt
const receiptRequestDeleteFile = await publicClient.waitForTransactionReceipt(
  {
    hash: txHashRequestDeleteFile,
  }
);
console.log('File deletion receipt:', receiptRequestDeleteFile);
if (receiptRequestDeleteFile.status !== 'success') {
  throw new Error(`File deletion failed: ${txHashRequestDeleteFile}`);
}

console.log(
  `File with key ${fileKey} deleted successfully from bucket ${bucketId}`
);

If you run the script with the code above, the fileInfo and formattedFileInfo should look like this:

ts-node index.ts
File info before deletion: {
  fileKey: 'e0d46d3e57ab2aabd09aee9cf8425910de5028bc82a1a8c52774b7c71d6c8933',
  fingerprint: '1bc3a71173c16c1eee04f7e7cf2591678b0b6cdf08eb81c638ae60a38b706aad',
  bucketId: '5811b0cfc1529286c59988e55e3e7d701ba2d68bdebdafb9b891f0c887611108',
  location: 'helloworld.txt',
  size: 18,
  isPublic: true,
  uploadedAt: 2025-11-05T14:19:55.911Z,
  status: 'expired'
}
Formatted file info before deletion:{
 fileKey: '0xe0d46d3e57ab2aabd09aee9cf8425910de5028bc82a1a8c52774b7c71d6c8933',
  fingerprint: '0x1bc3a71173c16c1eee04f7e7cf2591678b0b6cdf08eb81c638ae60a38b706aad',
  bucketId: '0x5811b0cfc1529286c59988e55e3e7d701ba2d68bdebdafb9b891f0c887611108',
  location: 'helloworld.txt',
  size: 18,
  isPublic: true,
  uploadedAt: 2025-11-05T14:19:55.911Z,
  status: 'expired'
}

And the final response should include:

ts-node index.ts
requestDeleteFile() txHash: 0x5e33858fb2399ffbfaa90f9abb1bb6d06f978c5b25fe9d552a05ac6fd17f055c
File deletion receipt: {
  transactionHash: '0x5e33858fb2399ffbfaa90f9abb1bb6d06f978c5b25fe9d552a05ac6fd17f055c',
  transactionIndex: 0,
  blockHash: '0xd3ad1ede25a2abb1673c26cac35c55ca3aaf6976db181582525838ff4b5b9498',
  from: '0x00fa35d84a43db75467d2b2c1ed8974aca57223e',
  to: '0x0000000000000000000000000000000000000404',
  blockNumber: 115472n,
  cumulativeGasUsed: 32400n,
  gasUsed: 32400n,
  contractAddress: null,
  logs: [
    {
      address: '0x0000000000000000000000000000000000000404',
      topics: [Array],
      data: '0x',
      blockHash: '0xd3ad1ede25a2abb1673c26cac35c55ca3aaf6976db181582525838ff4b5b9498',
      blockNumber: 115472n,
      transactionHash: '0x5e33858fb2399ffbfaa90f9abb1bb6d06f978c5b25fe9d552a05ac6fd17f055c',
      transactionIndex: 0,
      logIndex: 0,
      transactionLogIndex: '0x0',
      removed: false
    }
  ],
  logsBloom: '0x00000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000004000000000200000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000800000004000000080000000000000000000000000000000000000010000000000000000000000000000080000',
  status: 'success',
  effectiveGasPrice: 1000000000n,
  type: 'legacy'
}
File with key 0xe0d46d3e57ab2aabd09aee9cf8425910de5028bc82a1a8c52774b7c71d6c8933 deleted successfully from bucket 0x5811b0cfc1529286c59988e55e3e7d701ba2d68bdebdafb9b891f0c887611108

Delete a Bucket

To delete your bucket, add the following code:

Note

A bucket can only be deleted if all its files have already been deleted. Use the mspClient.buckets.getFiles() method by passing a bucketId as a parameter to check all the files currently stored in that bucket.

// Delete bucket
const txHashDeleteBucket: `0x${string}` | undefined =
  await storageHubClient.deleteBucket(bucketId as `0x${string}`);
console.log('deleteBucket() txHash:', txHashDeleteBucket);
if (!txHashDeleteBucket) {
  throw new Error('deleteBucket() did not return a transaction hash');
}

// Wait for transaction
const receiptDeleteBucket = await publicClient.waitForTransactionReceipt({
  hash: txHashDeleteBucket,
});
console.log('Bucket deletion receipt:', receiptDeleteBucket);
if (receiptDeleteBucket.status !== 'success') {
  throw new Error(`Bucket deletion failed: ${txHashDeleteBucket}`);
}

If you run the script with the bucket deletion code, the response should include:

ts-node index.ts
deleteBucket() txHash: 0x30204c4e27430ad81067e3dcbb283e46dac3a8a2ca484c980277056658128f13
Bucket deletion receipt: {
  transactionHash: '0x30204c4e27430ad81067e3dcbb283e46dac3a8a2ca484c980277056658128f13',
  transactionIndex: 0,
  blockHash: '0x2784726df3ea7f5333749c54f9c62e1813404a5475e0d040a456194c2636d2d2',
  from: '0x00fa35d84a43db75467d2b2c1ed8974aca57223e',
  to: '0x0000000000000000000000000000000000000404',
  blockNumber: 117400n,
  cumulativeGasUsed: 228432n,
  gasUsed: 228432n,
  contractAddress: null,
  logs: [
    {
      address: '0x0000000000000000000000000000000000000404',
      topics: [Array],
      data: '0x',
      blockHash: '0x2784726df3ea7f5333749c54f9c62e1813404a5475e0d040a456194c2636d2d2',
      blockNumber: 117400n,
      transactionHash: '0x30204c4e27430ad81067e3dcbb283e46dac3a8a2ca484c980277056658128f13',
      transactionIndex: 0,
      logIndex: 0,
      transactionLogIndex: '0x0',
      removed: false
    }
  ],
  logsBloom: '0x00000000000000040000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000010000000000000000000000000040000000000020000000000000000000000000100000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000010000800000000000000000000000080000',
  status: 'success',
  effectiveGasPrice: 1000000000n,
  type: 'legacy'
}

Next Steps

Last update: November 7, 2025
| Created: November 7, 2025