> ## Documentation Index
> Fetch the complete documentation index at: https://dispatch.lodestar-dashboard.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Consumers

# Using the Network

Two ways to consume the Dispatch network: hit the gateway directly or use the consumer SDK (trustless, signs receipts locally). Both require GRT in your escrow — there are no free queries.

***

## 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 — the gateway encodes it into the TAP receipt so GRT is drawn from **your** escrow on-chain, not the gateway's.

**Live gateway:** `https://gateway.lodestar-dashboard.com`

```bash theme={null}
# 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:

```typescript theme={null}
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`. Requests from addresses with no funded escrow are rejected by the provider. See [Funding the escrow](#funding-the-escrow) below.

**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.

```bash theme={null}
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:**

| Variable                     | Default            | Description                                                                     |
| ---------------------------- | ------------------ | ------------------------------------------------------------------------------- |
| `DISPATCH_SIGNER_KEY`        | *(auto-generated)* | Consumer private key. If unset, loaded from `./consumer.key` or generated fresh |
| `DISPATCH_CHAIN_ID`          | `1`                | Chain to proxy (1 = Ethereum, 42161 = Arbitrum One, etc.)                       |
| `DISPATCH_PORT`              | `8545`             | Local port to listen on                                                         |
| `DISPATCH_BASE_PRICE_PER_CU` | `4000000000000`    | GRT 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 pay providers directly from your own escrow. See [Funding the escrow](#funding-the-escrow) below.

***

## Consumer SDK

For trustless access — signs receipts locally and talks directly to providers, no gateway in the loop.

```bash theme={null}
npm install @lodestar-dispatch/consumer-sdk
```

```typescript theme={null}
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

```typescript theme={null}
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

Before GRT flows to providers you need to deposit into `PaymentsEscrow` on Arbitrum One. This is required regardless of which access method you use — the gateway, proxy, and consumer SDK all charge from your own escrow.

### Via the Lodestar dashboard (easiest)

Go to [lodestar-dashboard.com/dispatch](https://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)

```solidity theme={null}
// 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:

```bash theme={null}
cast call 0xf6Fcc27aAf1fcD8B254498c9794451d82afC673E \
  "getBalance(address,address,address)(uint256)" \
  <YOUR_ADDRESS> \
  0x8f69F5C07477Ac46FBc491B1E6D91E2bb0111A9e \
  <PROVIDER_ADDRESS> \
  --rpc-url https://arb1.arbitrum.io/rpc
```
