Mesh LogoMesh

Offline Fetcher

Test and develop Cardano applications without network connectivity

Overview

The OfflineFetcher provides access to blockchain data without requiring network connectivity. It stores data locally and returns it when queried, making it a drop-in replacement for other providers.

Use OfflineFetcher when you need:

  • Unit testing without network dependencies
  • Development in offline environments
  • Mocking blockchain state for specific scenarios
  • Reproducible test fixtures

The OfflineFetcher implements the same interface as online providers like BlockfrostProvider, so you can swap them interchangeably.

Quick Start

Install the MeshJS package:

npm install @meshsdk/core

Create and populate the fetcher:

import { OfflineFetcher } from "@meshsdk/core";

// Create a new instance
const fetcher = new OfflineFetcher();

// Add test data
fetcher.addUTxOs([
  {
    input: {
      txHash: "abc123...",
      outputIndex: 0,
    },
    output: {
      address: "addr_test1...",
      amount: [{ unit: "lovelace", quantity: "5000000" }],
    },
  },
]);

// Use like any other provider
const utxos = await fetcher.fetchAddressUTxOs("addr_test1...");

Configuration Options

ParameterTypeRequiredDescription
networkstringNoNetwork identifier (e.g., "mainnet", "preprod")

Example:

import { OfflineFetcher } from "@meshsdk/core";

// Create with default network
const fetcher = new OfflineFetcher();

// Create with specific network
const mainnetFetcher = new OfflineFetcher("mainnet");
const preprodFetcher = new OfflineFetcher("preprod");

Adding Data

Before fetching data, you must add it to the OfflineFetcher. The following methods populate the internal data store.

addAccount

Add stake account information.

fetcher.addAccount(address: string, info: AccountInfo): void
ParameterTypeRequiredDescription
addressstringYesThe stake address
infoAccountInfoYesAccount information object

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addAccount("stake_test1...", {
  balance: "1000000000",
  rewards: "50000000",
  withdrawals: "10000000",
  poolId: "pool1...", // optional
});

addUTxOs

Add UTxOs to the fetcher. These are returned by fetchAddressUTxOs and fetchUTxOs.

fetcher.addUTxOs(utxos: UTxO[]): void
ParameterTypeRequiredDescription
utxosUTxO[]YesArray of UTxO objects

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addUTxOs([
  {
    input: {
      txHash: "abc123def456...",
      outputIndex: 0,
    },
    output: {
      address: "addr_test1qpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0uafhxhu32dys6pvn6wlw8dav6cmp4pmtv7cc3yel9uu0nq93swx9",
      amount: [
        { unit: "lovelace", quantity: "5000000" },
        { unit: "d9312da562da182b02322fd8acb536f37eb9d29fba7c49dc172555274d657368546f6b656e", quantity: "1" },
      ],
    },
  },
  // Add script UTxOs with additional fields
  {
    input: {
      txHash: "def789...",
      outputIndex: 0,
    },
    output: {
      address: "addr_test1...",
      amount: [{ unit: "lovelace", quantity: "10000000" }],
      scriptHash: "abcd1234...",
      dataHash: "ef567890...",
      plutusData: "...",
      scriptRef: "...",
    },
  },
]);

addAssetAddresses

Add address holdings for a specific asset.

fetcher.addAssetAddresses(asset: string, addresses: AssetAddress[]): void
ParameterTypeRequiredDescription
assetstringYesThe asset unit (policy ID + asset name)
addressesAssetAddress[]YesArray of addresses and quantities

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addAssetAddresses(
  "d9312da562da182b02322fd8acb536f37eb9d29fba7c49dc172555274d657368546f6b656e",
  [
    { address: "addr_test1...", quantity: "1" },
    { address: "addr_test2...", quantity: "5" },
  ]
);

addAssetMetadata

Add metadata for an asset.

fetcher.addAssetMetadata(asset: string, metadata: AssetMetadata): void
ParameterTypeRequiredDescription
assetstringYesThe asset unit (policy ID + asset name)
metadataAssetMetadataYesAsset metadata object

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addAssetMetadata(
  "d9312da562da182b02322fd8acb536f37eb9d29fba7c49dc172555274d657368546f6b656e",
  {
    name: "MeshToken",
    image: "ipfs://QmXyz...",
    description: "A test token",
    // Any other CIP-25 metadata fields
  }
);

addProtocolParameters

Add protocol parameters.

fetcher.addProtocolParameters(params: Protocol): void
ParameterTypeRequiredDescription
paramsProtocolYesProtocol parameters object

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addProtocolParameters({
  epoch: 290,
  minFeeA: 44,
  minFeeB: 155381,
  maxBlockSize: 73728,
  maxTxSize: 16384,
  maxBlockHeaderSize: 1100,
  keyDeposit: 2000000,
  poolDeposit: 500000000,
  minPoolCost: "340000000",
  priceMem: 0.0577,
  priceStep: 0.0000721,
  // ... other parameters
});

addSerializedTransaction

Add a serialized transaction for tracking.

fetcher.addSerializedTransaction(txHash: string): void
ParameterTypeRequiredDescription
txHashstringYesThe transaction hash

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addSerializedTransaction(
  "f4ec9833a3bf95403d395f699bc564938f3419537e7fb5084425d3838a4b6159"
);

State Persistence

The OfflineFetcher can save and load its state, enabling test fixtures and data sharing.

toJSON

Export the current state as JSON.

const state = fetcher.toJSON(): string

Returns: JSON string representation of all stored data.

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

// Add data
fetcher.addUTxOs([...]);
fetcher.addProtocolParameters({...});

// Save state
const state = fetcher.toJSON();
localStorage.setItem("fetcher-state", state);

// Or save to file
import fs from "fs";
fs.writeFileSync("test-fixtures.json", state);

fromJSON

Create a new OfflineFetcher from saved state.

const fetcher = OfflineFetcher.fromJSON(json: string): OfflineFetcher
ParameterTypeRequiredDescription
jsonstringYesJSON state from toJSON()

Returns: New OfflineFetcher instance with loaded data.

Example:

import { OfflineFetcher } from "@meshsdk/core";

// Load from localStorage
const savedState = localStorage.getItem("fetcher-state");
const fetcher = OfflineFetcher.fromJSON(savedState);

// Or load from file
import fs from "fs";
const fileState = fs.readFileSync("test-fixtures.json", "utf-8");
const fetcher = OfflineFetcher.fromJSON(fileState);

API Reference

All fetch methods work identically to online providers but return data from the internal store.

get

Fetch data from a URL path (returns empty for offline).

await fetcher.get(endpoint: string): Promise<any>

fetchAccountInfo

Retrieve stake account information.

await fetcher.fetchAccountInfo(address: string): Promise<AccountInfo>
ParameterTypeRequiredDescription
addressstringYesThe stake address

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addAccount("stake_test1...", {
  balance: "1000000000",
  rewards: "50000000",
  withdrawals: "10000000",
});

const accountInfo = await fetcher.fetchAccountInfo("stake_test1...");
console.log(accountInfo.balance);

fetchAddressAssets

Fetch assets held by an address.

await fetcher.fetchAddressAssets(address: string): Promise<Asset[]>
ParameterTypeRequiredDescription
addressstringYesThe wallet address

Returns: Array of assets derived from UTxOs at that address.


fetchAddressUTxOs

Fetch UTxOs controlled by an address.

await fetcher.fetchAddressUTxOs(address: string, asset?: string): Promise<UTxO[]>
ParameterTypeRequiredDescription
addressstringYesThe wallet address
assetstringNoFilter by asset unit

Example:

import { OfflineFetcher } from "@meshsdk/core";

const fetcher = new OfflineFetcher();

fetcher.addUTxOs([
  {
    input: { txHash: "abc123...", outputIndex: 0 },
    output: {
      address: "addr_test1...",
      amount: [{ unit: "lovelace", quantity: "5000000" }],
    },
  },
]);

// Fetch all UTxOs
const utxos = await fetcher.fetchAddressUTxOs("addr_test1...");

// Fetch UTxOs with specific asset
const filtered = await fetcher.fetchAddressUTxOs(
  "addr_test1...",
  "d9312da562da182b02322fd8acb536f37eb9d29fba7c49dc172555274d657368546f6b656e"
);

fetchAssetAddresses

Fetch addresses holding a specific asset.

await fetcher.fetchAssetAddresses(asset: string): Promise<AssetAddress[]>

fetchAssetMetadata

Fetch metadata for an asset.

await fetcher.fetchAssetMetadata(asset: string): Promise<AssetMetadata>

fetchBlockInfo

Fetch block information.

await fetcher.fetchBlockInfo(hash: string): Promise<BlockInfo>

fetchCollectionAssets

Fetch assets in a collection by policy ID.

await fetcher.fetchCollectionAssets(policyId: string, cursor?: number): Promise<{ assets: Asset[]; next: number | null }>

fetchHandleAddress

Resolve an ADA Handle to an address.

await fetcher.fetchHandleAddress(handle: string): Promise<string>

fetchHandle

Fetch CIP-68 handle metadata.

await fetcher.fetchHandle(handle: string): Promise<HandleMetadata>

fetchProtocolParameters

Fetch protocol parameters.

await fetcher.fetchProtocolParameters(epoch?: number): Promise<Protocol>

fetchTxInfo

Fetch transaction information.

await fetcher.fetchTxInfo(hash: string): Promise<TransactionInfo>

fetchUTxOs

Fetch UTxOs by transaction hash.

await fetcher.fetchUTxOs(hash: string, index?: number): Promise<UTxO[]>

fetchGovernanceProposal

Fetch governance proposal information.

await fetcher.fetchGovernanceProposal(txHash: string, certIndex: number): Promise<ProposalInfo>

Complete Example

import { OfflineFetcher, MeshTxBuilder } from "@meshsdk/core";
import { MeshCardanoHeadlessWallet, AddressType } from "@meshsdk/wallet";

// Create and populate fetcher
const fetcher = new OfflineFetcher("preprod");

// Add protocol parameters
fetcher.addProtocolParameters({
  epoch: 290,
  minFeeA: 44,
  minFeeB: 155381,
  maxBlockSize: 73728,
  maxTxSize: 16384,
  maxBlockHeaderSize: 1100,
  keyDeposit: 2000000,
  poolDeposit: 500000000,
  minPoolCost: "340000000",
  priceMem: 0.0577,
  priceStep: 0.0000721,
  maxValSize: 5000,
  collateralPercent: 150,
  maxCollateralInputs: 3,
  coinsPerUtxoSize: "4310",
});

// Add test UTxOs
fetcher.addUTxOs([
  {
    input: {
      txHash: "abc123def456789abc123def456789abc123def456789abc123def456789abc1",
      outputIndex: 0,
    },
    output: {
      address: "addr_test1qpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0uafhxhu32dys6pvn6wlw8dav6cmp4pmtv7cc3yel9uu0nq93swx9",
      amount: [{ unit: "lovelace", quantity: "100000000" }],
    },
  },
]);

// Use in tests
async function testTransaction() {
  const wallet = await MeshCardanoHeadlessWallet.fromMnemonic({
    networkId: 0,
    walletAddressType: AddressType.Base,
    fetcher: fetcher,
    mnemonic: ["test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test", "test"],
  });

  const utxos = await wallet.getUtxosMesh();
  console.log(`Wallet has ${utxos.length} UTxOs`);

  const txBuilder = new MeshTxBuilder({
    fetcher: fetcher,
  });

  const unsignedTx = await txBuilder
    .txOut("addr_test1...", [{ unit: "lovelace", quantity: "5000000" }])
    .changeAddress(await wallet.getChangeAddressBech32())
    .selectUtxosFrom(utxos)
    .complete();

  console.log("Transaction built successfully");
}

// Save state for reuse
const state = fetcher.toJSON();
console.log("State saved:", state.length, "bytes");

Troubleshooting

Empty Results

Problem: Fetch methods return empty arrays or undefined.

Solution: Ensure you've added the corresponding data before fetching. The OfflineFetcher only returns data that has been explicitly added.

Address Mismatch

Problem: UTxOs not found for an address.

Solution: Verify the address in addUTxOs matches exactly what you're querying. Addresses are case-sensitive.

Missing Protocol Parameters

Problem: Transaction building fails without protocol parameters.

Solution: Call addProtocolParameters with complete parameter object before building transactions.

State Not Loading

Problem: fromJSON throws an error.

Solution: Ensure the JSON string is valid and was created by toJSON. Check for corruption if loading from file.

On this page