Skip to content

Set Custom Gas Params

This guide shows how to calculate and set custom gas params in DataHaven. The StorageHub SDK already dynamically computes the necessary gas params, but you can set custom values if needed. The createBucket method will be used as an example, but the same approach applies to any SDK method that involves an on-chain transaction.

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,
              "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

  • Implemented the createBucket helper method from the Create a Bucket guide

Initialize the Script

Create an index.ts file if you haven't already. Its run method will orchestrate all the logic in this guide. By now, your services folder (including the MSP and client helper services) should already be created, along with the operations folder containing bucket operations helper methods, which means you should already have the createBucket helper method implemented. If not, see the Get Started guide and the Create a bucket 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 { createBucket } from './operations/bucketOperations.js';

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

  // --- Bucket creating logic ---
  // Create a bucket
  const bucketName = 'init-bucket';
  const { bucketId, txReceipt } = await createBucket(bucketName);
  console.log(`Created Bucket ID: ${bucketId}`);
  console.log(`createBucket() txReceipt: ${txReceipt}`);

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

await run();

In this code, the createBucket helper method from bucketOperations.ts is called. Once all params are ready within this method, the SDK's storageHubClient.createBucket method is called:

bucketOperations.ts // createBucket()
...
// Create bucket on chain
  const txHash: `0x${string}` | undefined = await storageHubClient.createBucket(
    mspId as `0x${string}`,
    bucketName,
    isPrivate,
    valuePropId
  );
...

Through this method, an on-chain transaction is executed with a gas amount dynamically set by the SDK. To pass custom values, an extra gasTxOpts param, of type EvmWriteOptions (imported from @storagehub-sdk/core), can be passed at the end of the param list, like so:

bucketOperations.ts // createBucket()
...
// Create bucket on chain
  const txHash: `0x${string}` | undefined = await storageHubClient.createBucket(
    mspId as `0x${string}`,
    bucketName,
    isPrivate,
    valuePropId,
    gasTxOpts
  );
...

The EvmWriteOptions type has the following structure:

type EvmWriteOptions = {

  // Explicit gas limit. If omitted, the SDK will estimate and multiply.
  // It's computed with an estimation from the contract call and a multiplier.
  gas?: bigint;

  // Multiplier applied over the SDK gas estimate when `gas` is not supplied.
  // Defaults to 5.
  gasMultiplier?: number;

  // Deprecated - do not use - Legacy gas price (wei)
  // StorageHub SDK is moving to EIP-1559 only. This field is ignored by the SDK.
  // Use `maxFeePerGas` and `maxPriorityFeePerGas` instead.
  gasPrice?: bigint;

  // EIP-1559: max fee per gas (wei). Use with `maxPriorityFeePerGas`.
  // maxFeePerGas = baseFeePerGas * safeMarginMultiplier + maxPriorityFeePerGas
  maxFeePerGas?: bigint;

  // EIP-1559: max priority fee per gas (wei).
  // The tip paid to validators and should be increased under network congestion.
  maxPriorityFeePerGas?: bigint;
};

In the following section, you will learn how to set and calculate these gas values within the EvmWriteOptions type.

Add Method to Set Gas Fees

To create the buildGasTxOpts helper method, follow these steps:

  1. Create a txOperations.ts file within the operations folder.

  2. Add the following code:

    txOperations.ts
    import { EvmWriteOptions } from '@storagehub-sdk/core';
    import { publicClient } from '../services/clientService.js';
    
    // Build custom gas transaction options
    export async function buildGasTxOpts(): Promise<EvmWriteOptions> {
      const gas = BigInt('1500000');
    
      // EIP-1559 fees based on latest block
      const latestBlock = await publicClient.getBlock({ blockTag: 'latest' });
      const baseFeePerGas = latestBlock.baseFeePerGas;
      if (baseFeePerGas == null) {
        throw new Error(
          'RPC did not return baseFeePerGas for the latest block. Cannot build EIP-1559 fees.',
        );
      }
    
      const maxPriorityFeePerGas = BigInt('1500000000'); // 1.5 gwei
    
      // maxFeePerGas = baseFeePerGas * safeMarginMultiplier + maxPriorityFeePerGas
      // safeMarginMultiplier should be some value that protects you from fee spikes (e.g., 1.5x or 2x)
      const maxFeePerGas = baseFeePerGas * BigInt(2) + maxPriorityFeePerGas;
    
      return { gas, maxFeePerGas, maxPriorityFeePerGas };
    }
    

Update Create Bucket Method

To update your existing createBucket helper method within your bucketOperations.ts file to include the gasTxOpts calculation, follow these steps:

  1. Add this line to your imports:

    bucketOperations.ts
    import { buildGasTxOpts } from './txOperations.js';
    
  2. Trigger the buildGasTxOpts method right before calling the SDK's storageHubClient.createBucket method and add the gasTxOpts param at the end of the param list, like so:

    bucketOperations.ts
    ...
    const gasTxOpts = await buildGasTxOpts();
    // Create bucket on chain
    const txHash: `0x${string}` | undefined = await storageHubClient.createBucket(
      mspId as `0x${string}`,
      bucketName,
      isPrivate,
      valuePropId,
      gasTxOpts
    );
    ...
    
View complete bucketOperations.ts file
bucketOperations.ts
import {
  storageHubClient,
  address,
  publicClient,
  polkadotApi,
} from '../services/clientService.js';
import { getMspInfo, getValueProps } from '../services/mspService.js';
import { buildGasTxOpts } from './txOperations.js';

export async function createBucket(bucketName: string) {
  // Get basic MSP information from the MSP including its ID
  const { mspId } = await getMspInfo();

  // Choose one of the value props retrieved from the MSP through the helper function
  const valuePropId = await getValueProps();
  console.log(`Value Prop ID: ${valuePropId}`);

  // Derive bucket ID
  const bucketId = (await storageHubClient.deriveBucketId(
    address,
    bucketName,
  )) as string;
  console.log(`Derived bucket ID: ${bucketId}`);

  // Check that the bucket doesn't exist yet
  const bucketBeforeCreation =
    await polkadotApi.query.providers.buckets(bucketId);
  console.log('Bucket before creation is empty', bucketBeforeCreation.isEmpty);
  if (!bucketBeforeCreation.isEmpty) {
    throw new Error(`Bucket already exists: ${bucketId}`);
  }

  const isPrivate = false;

  const gasTxOpts = await buildGasTxOpts();
  // Create bucket on chain
  const txHash: `0x${string}` | undefined = await storageHubClient.createBucket(
    mspId as `0x${string}`,
    bucketName,
    isPrivate,
    valuePropId,
    gasTxOpts,
  );

  console.log('createBucket() txHash:', txHash);
  if (!txHash) {
    throw new Error('createBucket() did not return a transaction hash');
  }

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

  return { bucketId, txReceipt };
}

Run Create Bucket Script

Execute the createBucket method by running the script:

ts-node index.ts

Upon successful execution, it should return an expected bucket-creation response like this:

ts-node index.ts Derived bucket ID: 0x659ca967940ee656b10ea85813bb14f054137d330ec87f9914a2c46a981196f6 Bucket before creation is empty true createBucket() txHash: 0x2f370c2a7906b830d6351857449af201a5abe90f0ace8e8a6c972509ca579cc8 Created Bucket ID: 0x659ca967940ee656b10ea85813bb14f054137d330ec87f9914a2c46a981196f6 createBucket() txReceipt: { transactionHash: '0x2f370c2a7906b830d6351857449af201a5abe90f0ace8e8a6c972509ca579cc8', transactionIndex: 0, blockHash: '0x773b4139cd5b1dc4374e137dcf279b89869a3f86caec070ec3478ce898adfc33', from: '0x00fa35d84a43db75467d2b2c1ed8974aca57223e', to: '0x0000000000000000000000000000000000000404', blockNumber: 174629n, cumulativeGasUsed: 111152n, gasUsed: 111152n, contractAddress: null, logs: [ { address: '0x0000000000000000000000000000000000000404', topics: [Array], data: '0x', blockHash: '0x773b4139cd5b1dc4374e137dcf279b89869a3f86caec070ec3478ce898adfc33', blockNumber: 174629n, transactionHash: '0x2f370c2a7906b830d6351857449af201a5abe90f0ace8e8a6c972509ca579cc8', transactionIndex: 0, logIndex: 0, transactionLogIndex: '0x0', removed: false } ], logsBloom: '0x00000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000080040000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000004000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000010000000800000000000000000000040000000000000000000000000000000010000000000000000000000000000080000', status: 'success', effectiveGasPrice: 1000000000n, type: 'legacy' }

Next Steps

Last update: January 29, 2026
| Created: January 29, 2026