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/coreCreate 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
| Parameter | Type | Required | Description |
|---|---|---|---|
network | string | No | Network 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| Parameter | Type | Required | Description |
|---|---|---|---|
address | string | Yes | The stake address |
info | AccountInfo | Yes | Account 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| Parameter | Type | Required | Description |
|---|---|---|---|
utxos | UTxO[] | Yes | Array 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| Parameter | Type | Required | Description |
|---|---|---|---|
asset | string | Yes | The asset unit (policy ID + asset name) |
addresses | AssetAddress[] | Yes | Array 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| Parameter | Type | Required | Description |
|---|---|---|---|
asset | string | Yes | The asset unit (policy ID + asset name) |
metadata | AssetMetadata | Yes | Asset 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| Parameter | Type | Required | Description |
|---|---|---|---|
params | Protocol | Yes | Protocol 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| Parameter | Type | Required | Description |
|---|---|---|---|
txHash | string | Yes | The 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(): stringReturns: 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| Parameter | Type | Required | Description |
|---|---|---|---|
json | string | Yes | JSON 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>| Parameter | Type | Required | Description |
|---|---|---|---|
address | string | Yes | The 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[]>| Parameter | Type | Required | Description |
|---|---|---|---|
address | string | Yes | The 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[]>| Parameter | Type | Required | Description |
|---|---|---|---|
address | string | Yes | The wallet address |
asset | string | No | Filter 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.
Related Links
- Offline Evaluator - Evaluate Plutus scripts offline
- MeshJS Transaction Builder
- MeshJS Testing Guide