Skip to content

Update Bucket Privacy via Smart Contracts

Every bucket on DataHaven is created with a privacy flag that controls whether its contents are publicly visible or access-restricted. This guide shows you how to change that flag after the bucket already exists by calling the updateBucketPrivacy function on the FileSystem Precompile directly via walletClient.writeContract.

SDK support not yet available

The updateBucketPrivacy operation is not currently available through the StorageHub SDK. In this guide, to update a bucket's privacy, the FileSystem Precompile is called directly, instead of using the storageHubClient.

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 tsx ts-node @types/node
      
      yarn add -D typescript tsx ts-node @types/node
      
      npm install -D typescript tsx 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,
              "resolveJsonModule": true,
              "skipLibCheck": true,
              "outDir": "dist",
              "declaration": true,
              "sourceMap": true
          },
          "include": ["src/**/*.ts"]
      }
      
    5. Initialize the src directory:

      mkdir src && touch src/index.ts
      
  • Dependencies installed

  • Clients initialized

  • A bucket created with the ID handy

  • The FileSystem Precompile's ABI handy

Initialize the Script Entry Point

Create an index.ts file if you haven't already. Its run method will orchestrate all the logic in this guide, and you'll replace the labelled placeholders with real code step by step. By now, your services folder (including the MSP and client helper services) should already be created. If not, see the Get Started guide.

Add the following code to your index.ts file:

index.ts
import '@storagehub/api-augment';
import { initWasm } from '@storagehub-sdk/core';
import { polkadotApi } from './services/clientService.js';
import {
  updateBucketPrivacy,
  verifyBucketCreation,
} from './operations/bucketOperations.js';

async function run() {
  await initWasm();

  const bucketId = 'INSERT_BUCKET_ID'; // `0x${string}`

  // **PLACEHOLDER FOR STEP 1: UPDATE BUCKET PRIVACY**
  // **PLACEHOLDER FOR STEP 2: VERIFY PRIVACY CHANGE**

  await polkadotApi.disconnect();
}

await run();

Add the Update Bucket Privacy Helper

Create a bucketOperations.ts file within your operations folder (or add to an existing one). This helper calls walletClient.writeContract with functionName: 'updateBucketPrivacy', passing the bucket ID and a boolean isPrivate flag. Setting isPrivate to true makes the bucket private; false makes it public again.

operations/bucketOperations.ts
import {
  account,
  address,
  publicClient,
  walletClient,
  polkadotApi,
  chain,
} from '../services/clientService.js';
import { getMspInfo } from '../services/mspService.js';
import fileSystemAbi from '../abis/FileSystemABI.json' with { type: 'json' };
import { NETWORK } from '../config/networks.js';

export async function updateBucketPrivacy(
  bucketId: string,
  isPrivate: boolean,
): Promise<boolean> {
  // Update bucket privacy on chain by calling the FileSystem precompile directly
  const txHash = await walletClient.writeContract({
    account,
    address: NETWORK.filesystemContractAddress,
    abi: fileSystemAbi,
    functionName: 'updateBucketPrivacy',
    args: [bucketId as `0x${string}`, isPrivate],
    chain: chain,
  });
  console.log('updateBucketPrivacy() txHash:', txHash);
  if (!txHash) {
    throw new Error('updateBucketPrivacy() did not return a transaction hash');
  }

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

  console.log(
    `Bucket ${bucketId} privacy updated to ${isPrivate ? 'private' : 'public'}`,
  );
  return true;
}

Update the Bucket Privacy

Replace the placeholder // **PLACEHOLDER FOR STEP 1: UPDATE BUCKET PRIVACY** with the following code:

index.ts // **PLACEHOLDER FOR STEP 1: UPDATE BUCKET PRIVACY**
// Update bucket privacy to private
await updateBucketPrivacy(bucketId, true);

If you run the script, you should see the transaction hash and receipt confirming the update:

ts-node index.ts
updateBucketPrivacy() txHash: 0x8a3b1c5d7e9f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9
updateBucketPrivacy() txReceipt: {
  transactionHash: '0x8a3b1c5d7e9f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9',
  transactionIndex: 0,
  blockHash: '0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2',
  from: '0x00fa35d84a43db75467d2b2c1ed8974aca57223e',
  to: '0x0000000000000000000000000000000000000404',
  blockNumber: 175012n,
  cumulativeGasUsed: 28400n,
  gasUsed: 28400n,
  contractAddress: null,
  logs: [],
  status: 'success',
  effectiveGasPrice: 1000000000n,
  type: 'legacy'
}
Bucket 0xf7c6...d02a privacy updated to private

Verify the Privacy Change On-Chain

To confirm the privacy setting was actually updated, query the on-chain bucket data and check the private field. Add the following verifyBucketCreation helper to your bucketOperations.ts file:

operations/bucketOperations.ts
// Verify bucket creation on chain and return bucket data
export async function verifyBucketCreation(bucketId: string) {
  const { mspId } = await getMspInfo();

  const bucket = await polkadotApi.query.providers.buckets(bucketId);

  if (bucket.isEmpty) {
    throw new Error('Bucket not found on chain after creation');
  }

  const bucketData = bucket.unwrap().toHuman();
  console.log(
    'Bucket userId matches initial bucket owner address',
    bucketData.userId === address,
  );
  console.log(
    `Bucket MSPId matches initial MSPId: ${bucketData.mspId === mspId}`,
  );
  return bucketData;
}

Replace the placeholder // **PLACEHOLDER FOR STEP 2: VERIFY PRIVACY CHANGE** with the following code:

index.ts // **PLACEHOLDER FOR STEP 2: VERIFY PRIVACY CHANGE**
// Verify the privacy was updated on chain
const bucketDataAfterUpdate = await verifyBucketCreation(bucketId);
console.log('Bucket data after setting private:', bucketDataAfterUpdate);
console.log(`Privacy after update: ${bucketDataAfterUpdate.private}\n`);

Upon successful verification, the bucket data should now show private: true:

ts-node index.ts Bucket userId matches initial bucket owner address: true Bucket mspId matches initial mspId: true
Bucket data after setting private: {
  root: '0x03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
  userId: '0x00FA35D84a43db75467D2B2c1ed8974aCA57223e',
  mspId: '0x0000000000000000000000000000000000000000000000000000000000000001',
  private: true,
  readAccessGroupId: null,
  size_: '0',
  valuePropId: '0x628a23c7aa64902e13f63ffdd0725e07723745f84cabda048d901020d200da1e'
}
Privacy after update: true
View complete bucketOperations.ts
operations/bucketOperations.ts
import {
  account,
  address,
  publicClient,
  walletClient,
  polkadotApi,
  chain,
} from '../services/clientService.js';
import { getMspInfo } from '../services/mspService.js';
import fileSystemAbi from '../abis/FileSystemABI.json' with { type: 'json' };
import { NETWORK } from '../config/networks.js';

export async function updateBucketPrivacy(
  bucketId: string,
  isPrivate: boolean,
): Promise<boolean> {
  // Update bucket privacy on chain by calling the FileSystem precompile directly
  const txHash = await walletClient.writeContract({
    account,
    address: NETWORK.filesystemContractAddress,
    abi: fileSystemAbi,
    functionName: 'updateBucketPrivacy',
    args: [bucketId as `0x${string}`, isPrivate],
    chain: chain,
  });
  console.log('updateBucketPrivacy() txHash:', txHash);
  if (!txHash) {
    throw new Error('updateBucketPrivacy() did not return a transaction hash');
  }

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

  console.log(
    `Bucket ${bucketId} privacy updated to ${isPrivate ? 'private' : 'public'}`,
  );
  return true;
}

// Verify bucket creation on chain and return bucket data
export async function verifyBucketCreation(bucketId: string) {
  const { mspId } = await getMspInfo();

  const bucket = await polkadotApi.query.providers.buckets(bucketId);

  if (bucket.isEmpty) {
    throw new Error('Bucket not found on chain after creation');
  }

  const bucketData = bucket.unwrap().toHuman();
  console.log(
    'Bucket userId matches initial bucket owner address',
    bucketData.userId === address,
  );
  console.log(
    `Bucket MSPId matches initial MSPId: ${bucketData.mspId === mspId}`,
  );
  return bucketData;
}
View complete index.ts
index.ts
import '@storagehub/api-augment';
import { initWasm } from '@storagehub-sdk/core';
import { polkadotApi } from './services/clientService.js';
import {
  updateBucketPrivacy,
  verifyBucketCreation,
} from './operations/bucketOperations.js';

async function run() {
  await initWasm();

  const bucketId = 'INSERT_BUCKET_ID'; // `0x${string}`

  // Update bucket privacy to private
  await updateBucketPrivacy(bucketId, true);

  // Verify the privacy was updated on chain
  const bucketDataAfterUpdate = await verifyBucketCreation(bucketId);
  console.log('Bucket data after setting private:', bucketDataAfterUpdate);
  console.log(`Privacy after update: ${bucketDataAfterUpdate.private}\n`);

  await polkadotApi.disconnect();
}

await run();

Next Steps

Last update: February 24, 2026
| Created: February 24, 2026