Skip to main content

Documentation Index

Fetch the complete documentation index at: https://dispatch-mintlify-changelog-1777248877.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Using the Network

Three ways to consume the Dispatch network: hit the gateway directly, run the local dispatch-proxy, or use the consumer SDK (trustless, signs receipts locally). Who manages on-chain GRT?
  • Gateway — the gateway is the on-chain payer. It maintains its own GRT escrow with each provider. You do not need to deposit GRT yourself; your X-Consumer-Address is used for per-consumer billing and rate-limiting only.
  • dispatch-proxy / Consumer SDK — you are the on-chain payer. You must deposit GRT into PaymentsEscrow before making requests (see Funding the escrow).

Via the Gateway

The gateway handles provider selection and TAP receipt signing. You must include your Ethereum address in every request via the X-Consumer-Address header — it is used for per-consumer billing and rate-limiting. The gateway manages its own on-chain GRT flow; you do not need to fund an escrow account to use the gateway. Live gateway: https://gateway.lodestar-dashboard.com
# curl
curl -s -X POST https://gateway.lodestar-dashboard.com/rpc/42161 \
  -H "Content-Type: application/json" \
  -H "X-Consumer-Address: 0xYOUR_ADDRESS" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# Check the attestation header
curl -si -X POST https://gateway.lodestar-dashboard.com/rpc/42161 \
  -H "Content-Type: application/json" \
  -H "X-Consumer-Address: 0xYOUR_ADDRESS" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
  | grep -E "x-drpc-attestation|result"
With ethers.js or viem:
import { createPublicClient, http } from "viem";
import { arbitrum } from "viem/chains";

const client = createPublicClient({
  chain: arbitrum,
  transport: http("https://gateway.lodestar-dashboard.com/rpc/42161", {
    fetchOptions: {
      headers: { "X-Consumer-Address": "0xYOUR_ADDRESS" },
    },
  }),
});

const block = await client.getBlockNumber();
Missing the X-Consumer-Address header returns 402 Payment Required. Routes:
POST /rpc/{chain_id}     # chain ID in path
POST /rpc                # chain ID via X-Chain-Id header
Currently live: Arbitrum One (42161) — Standard and Archive tiers.

dispatch-proxy (drop-in local server)

The easiest way to point any existing app at the Dispatch network without changing application code. Starts a standard JSON-RPC HTTP server on localhost; MetaMask, Viem, Ethers.js, and curl all work against it without modification.
cd proxy
npm install
npm start
On first run the proxy auto-generates a consumer keypair, saves it to ./consumer.key, and tells you where to fund escrow. No key needed upfront.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
dispatch-proxy v0.1.0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Chain:     Ethereum Mainnet (1)
Listening: http://localhost:8545
Consumer:  0xABCD...1234
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠  New consumer key generated → ./consumer.key
Fund escrow at:  https://lodestar-dashboard.com/dispatch
Consumer address: 0xABCD...1234
Or use an existing funded key: DISPATCH_SIGNER_KEY=0x...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Add to MetaMask  →  Settings → Networks → Add a network
  RPC URL:  http://localhost:8545
  Chain ID: 1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[12:34:56] ✓ eth_blockNumber      42ms  0.000004 GRT   total: 0.000004 GRT
[12:34:57] ✓ eth_getBalance       38ms  0.000008 GRT   total: 0.000012 GRT
Configuration:
VariableDefaultDescription
DISPATCH_SIGNER_KEY(auto-generated)Consumer private key. If unset, loaded from ./consumer.key or generated fresh
DISPATCH_CHAIN_ID1Chain to proxy (1 = Ethereum, 42161 = Arbitrum One, etc.)
DISPATCH_PORT8545Local port to listen on
DISPATCH_BASE_PRICE_PER_CU4000000000000GRT wei per compute unit
The proxy handles provider discovery, TAP receipt signing, QoS-scored provider selection, CORS, and JSON-RPC batch requests. On exit (Ctrl+C) it prints a session summary of total requests and GRT spent. Unlike the gateway, the proxy runs locally and signs receipts with your own key — you are the on-chain payer and pay providers directly from your own escrow. See Funding the escrow below.

Consumer SDK

For trustless access — signs receipts locally and talks directly to providers, no gateway in the loop.
npm install @lodestar-dispatch/consumer-sdk
import { DISPATCHClient } from "@lodestar-dispatch/consumer-sdk";

const client = new DISPATCHClient({
  chainId: 42161,                                               // Arbitrum One (only live chain)
  dataServiceAddress: "0xA983b18B8291F0c317Ba4Fe0dc0f7cc9373AF078",
  graphTallyCollector: "0x8f69F5C07477Ac46FBc491B1E6D91E2bb0111A9e",
  subgraphUrl: "https://api.studio.thegraph.com/query/1747796/rpc-network/v0.2.0",
  signerPrivateKey: process.env.CONSUMER_KEY as `0x${string}`,
  basePricePerCU: 4_000_000_000_000n,  // GRT wei per compute unit
});

const blockNumber = await client.request("eth_blockNumber", []);
const balance = await client.request("eth_getBalance", ["0x...", "latest"]);
The client discovers providers via the subgraph, selects one by QoS score, signs a TAP receipt per request, and tracks latency with an EMA.

Low-level utilities

import {
  discoverProviders,
  selectProvider,
  buildReceipt,
  signReceipt,
} from "@lodestar-dispatch/consumer-sdk";

// Discover active providers for a chain + tier
const providers = await discoverProviders(
  "https://api.studio.thegraph.com/query/1747796/rpc-network/v0.2.0",
  42161,  // chainId
  0,      // tier: 0 = Standard, 1 = Archive
);

const provider = selectProvider(providers);

// Build and sign a receipt
const receipt = buildReceipt(
  "0xA983b18B8291F0c317Ba4Fe0dc0f7cc9373AF078",  // dataService
  provider.address,                                // serviceProvider
  4_000_000_000_000n,                             // value (GRT wei)
);
const signed = await signReceipt(
  receipt,
  { verifyingContract: "0x8f69F5C07477Ac46FBc491B1E6D91E2bb0111A9e" },
  privateKey,
);

Funding the escrow

Gateway users skip this section. The gateway manages its own on-chain escrow. If you’re calling https://gateway.lodestar-dashboard.com directly, you do not need to deposit GRT.
If you’re using dispatch-proxy or the consumer SDK, you are the on-chain payer and must deposit GRT into PaymentsEscrow on Arbitrum One before providers will serve your requests.

Via the Lodestar dashboard (easiest)

Go to lodestar-dashboard.com/dispatch. Connect MetaMask, paste your consumer address, and deposit GRT. The dashboard calls depositTo() on the PaymentsEscrow contract so you can fund any address’s escrow directly — the consumer wallet itself needs no ETH or GRT. Useful for funding dispatch-proxy from a separate hot wallet.

Manually (cast / ethers)

// 1. Approve the escrow contract
GRT.approve(0xf6Fcc27aAf1fcD8B254498c9794451d82afC673E, amount);

// 2a. Deposit from your own address
PaymentsEscrow.deposit(
    0x8f69F5C07477Ac46FBc491B1E6D91E2bb0111A9e,  // collector: GraphTallyCollector
    providerAddress,                                // receiver: the indexer you're paying
    amount
);

// 2b. Or fund any address's escrow (useful for the proxy key)
PaymentsEscrow.depositTo(
    consumerAddress,                                // payer: the consumer key you're funding
    0x8f69F5C07477Ac46FBc491B1E6D91E2bb0111A9e,  // collector: GraphTallyCollector
    providerAddress,                                // receiver
    amount
);
Deposits are keyed by (payer, collector, receiver). dispatch-service draws down automatically on each collect() cycle (hourly by default). Providers reject requests from addresses with zero escrow balance (checked on-chain every 30 seconds). Check your balance with:
cast call 0xf6Fcc27aAf1fcD8B254498c9794451d82afC673E \
  "getBalance(address,address,address)(uint256)" \
  <YOUR_ADDRESS> \
  0x8f69F5C07477Ac46FBc491B1E6D91E2bb0111A9e \
  <PROVIDER_ADDRESS> \
  --rpc-url https://arb1.arbitrum.io/rpc