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:
-
Create a new project folder by executing the following command in the terminal:
-
Initialize a
package.jsonfile using the correct command for your package manager: -
Add the TypeScript and Node type definitions to your projects using the correct command for your package manager:
-
Create a
tsconfig.jsonfile in the root of your project and paste the following configuration: -
Initialize the
srcdirectory:
-
-
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:
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.
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:
// 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:
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:
// 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:
// 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:
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
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
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¶
-
Manage Files and Buckets via Smart Contracts
Learn how to get file info, request file removal from the network, and how to delete buckets via smart contracts.
-
Build a Data Workflow End-to-End via Smart Contracts
Learn step-by-step how to store a file on DataHaven via smart contracts and retrieve it from the network.
| Created: February 24, 2026