Skip to content

Commit b5bad7b

Browse files
authored
feat: add x402 client for agents (#1016)
* feat: add x402 client for agents Signed-off-by: Tomás Migone <tomas@edgeandnode.com> * chore: move x402 examples to examples folder Signed-off-by: Tomás Migone <tomas@edgeandnode.com> --------- Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
1 parent c2ed90a commit b5bad7b

File tree

16 files changed

+1810
-1007
lines changed

16 files changed

+1810
-1007
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Example: Typed SDK configuration
2+
#
3+
# Generates a fully typed SDK from your subgraph schema.
4+
#
5+
# Prerequisites:
6+
# npm install @graphprotocol/client-cli @graphprotocol/client-x402
7+
#
8+
# Build:
9+
# export X402_PRIVATE_KEY=0x...
10+
# export X402_CHAIN=base-sepolia
11+
# npx graphclient build
12+
# rm .graphclient/package.json # Required: mesh generates broken ESM exports
13+
#
14+
# Run:
15+
# npx tsx index.ts
16+
17+
customFetch: '@graphprotocol/client-x402'
18+
19+
sources:
20+
- name: thegraph
21+
handler:
22+
graphql:
23+
endpoint: http://localhost:7700/api/x402/deployments/id/QmXU9FEf1tUwSjsnGGsuvMHFmGq3CeEi1RiWrNXSQXzkAi
24+
25+
documents:
26+
- ./queries/*.graphql

examples/client-x402/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# x402 Examples
2+
3+
## Mode 1: CLI
4+
5+
See [`cli.sh`](./cli.sh) - query directly from the terminal.
6+
7+
```bash
8+
export X402_PRIVATE_KEY=0x...
9+
export X402_CHAIN=base-sepolia
10+
./cli.sh http://localhost:7700/api/x402/deployments/id/Qm... '{ indexers { id } }'
11+
```
12+
13+
## Mode 2: Programmatic
14+
15+
See [`programmatic.ts`](./programmatic.ts) - use in scripts without a build step.
16+
17+
```bash
18+
export X402_PRIVATE_KEY=0x...
19+
export X402_CHAIN=base-sepolia
20+
npx tsx programmatic.ts http://localhost:7700/api/x402/deployments/id/Qm... '{ indexers { id } }'
21+
```
22+
23+
## Mode 3: Typed SDK
24+
25+
See [`index.ts`](./index.ts) + [`.graphclientrc.yml`](./.graphclientrc.yml) - full type safety with generated SDK.
26+
27+
```bash
28+
export X402_PRIVATE_KEY=0x...
29+
export X402_CHAIN=base-sepolia
30+
npx graphclient build
31+
npx tsx index.ts
32+
```

examples/client-x402/cli.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
# Example: Query a paid subgraph endpoint using the CLI
3+
#
4+
# Prerequisites:
5+
# npm install -g @graphprotocol/client-x402
6+
#
7+
# Usage:
8+
# export X402_PRIVATE_KEY=0x...
9+
# export X402_CHAIN=base-sepolia
10+
# ./cli.sh <endpoint> '<query>'
11+
#
12+
# Example:
13+
# ./cli.sh http://localhost:7700/api/x402/deployments/id/Qm... '{ indexers { id } }'
14+
15+
set -e
16+
17+
if [ -z "$X402_PRIVATE_KEY" ]; then
18+
echo "Error: X402_PRIVATE_KEY is required"
19+
exit 1
20+
fi
21+
22+
if [ -z "$X402_CHAIN" ]; then
23+
echo "Error: X402_CHAIN is required (base or base-sepolia)"
24+
exit 1
25+
fi
26+
27+
if [ -z "$1" ] || [ -z "$2" ]; then
28+
echo "Usage: ./cli.sh <endpoint> '<query>'"
29+
exit 1
30+
fi
31+
32+
graphclient-x402 "$2" \
33+
--endpoint "$1" \
34+
--chain "$X402_CHAIN"

examples/client-x402/index.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Example: Typed SDK usage
3+
*
4+
* For applications that want full type safety.
5+
*
6+
* Prerequisites:
7+
* npm install @graphprotocol/client-cli @graphprotocol/client-x402
8+
*
9+
* Build the SDK first:
10+
* export X402_PRIVATE_KEY=0x...
11+
* export X402_CHAIN=base-sepolia
12+
* npx graphclient build
13+
*
14+
* Then run this file:
15+
* npx tsx index.ts
16+
*/
17+
18+
import { execute, GetIndexersDocument } from './.graphclient'
19+
20+
async function main() {
21+
// Execute with full type safety - result is typed based on your schema and query
22+
const result = await execute(GetIndexersDocument, {})
23+
24+
if (result.errors) {
25+
console.error('GraphQL errors:', result.errors)
26+
return
27+
}
28+
29+
// result.data is fully typed
30+
for (const indexer of result.data?.indexers ?? []) {
31+
console.log(`Indexer ${indexer.id}: ${indexer.stakedTokens} staked, ${indexer.allocations.length} allocations`)
32+
}
33+
}
34+
35+
main().catch(console.error)

examples/client-x402/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "client-x402-examples",
3+
"version": "1.0.0",
4+
"description": "See [`cli.sh`](./cli.sh) - query directly from the terminal.",
5+
"license": "MIT",
6+
"author": "Tomás Migone <tomas@edgeandnode.com>",
7+
"type": "module",
8+
"main": "index.js",
9+
"scripts": {
10+
"test": "echo \"Error: no test specified\" && exit 1"
11+
},
12+
"dependencies": {
13+
"@graphprotocol/client-x402": "^1.0.0"
14+
}
15+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Example: Programmatic usage with createGraphQuery
3+
*
4+
* For scripts, bots, or simple integrations. No build step, no types.
5+
*
6+
* Prerequisites:
7+
* npm install @graphprotocol/client-x402
8+
*
9+
* Usage:
10+
* export X402_PRIVATE_KEY=0x...
11+
* export X402_CHAIN=base-sepolia
12+
* npx tsx programmatic.ts <endpoint> '<query>'
13+
*
14+
* Example:
15+
* npx tsx programmatic.ts http://localhost:7700/api/x402/deployments/id/Qm... '{ indexers { id } }'
16+
*/
17+
18+
import { createGraphQuery } from '@graphprotocol/client-x402'
19+
20+
const endpoint = process.argv[2]
21+
const queryString = process.argv[3]
22+
23+
if (!process.env.X402_PRIVATE_KEY) {
24+
console.error('Error: X402_PRIVATE_KEY is required')
25+
process.exit(1)
26+
}
27+
28+
if (!process.env.X402_CHAIN) {
29+
console.error('Error: X402_CHAIN is required (base or base-sepolia)')
30+
process.exit(1)
31+
}
32+
33+
if (!endpoint || !queryString) {
34+
console.error("Usage: npx tsx programmatic.ts <endpoint> '<query>'")
35+
process.exit(1)
36+
}
37+
38+
const query = createGraphQuery({
39+
endpoint,
40+
chain: process.env.X402_CHAIN as 'base' | 'base-sepolia',
41+
})
42+
43+
const result = await query(queryString)
44+
console.log(JSON.stringify(result.data, null, 2))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Example GraphQL query document
2+
# After running `graphclient build`, this generates typed functions
3+
4+
query GetIndexers {
5+
indexers {
6+
id
7+
stakedTokens
8+
allocations {
9+
id
10+
}
11+
}
12+
}

packages/x402/README.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# @graphprotocol/client-x402
2+
3+
Query The Graph's gateway with automatic payment handling using the [x402 protocol](https://github.com/coinbase/x402), no API key required!
4+
5+
## Installation
6+
7+
```bash
8+
npm install @graphprotocol/client-x402
9+
```
10+
11+
## Environments
12+
13+
| Environment | Gateway endpoint | Payment network |
14+
| ------------ | ----------------------------------------------- | --------------- |
15+
| `production` | `https://gateway.thegraph.com/api/x402` | `base` |
16+
| `testnet` | `https://testnet.gateway.thegraph.com/api/x402` | `base-sepolia` |
17+
18+
## Usage
19+
20+
Three ways to use this package, from simplest to most complete:
21+
22+
### 1. CLI
23+
24+
For quick queries, testing, or shell scripts. No code required.
25+
26+
```bash
27+
export X402_PRIVATE_KEY=0xabc123...
28+
29+
graphclient-x402 "{ pairs(first: 5) { id } }" \
30+
--endpoint https://gateway.thegraph.com/api/x402/subgraphs/id/<SUBGRAPH_ID> \
31+
--chain base
32+
```
33+
34+
### 2. Programmatic
35+
36+
For scripts, bots, or simple integrations. No build step, no types.
37+
38+
```typescript
39+
import { createGraphQuery } from '@graphprotocol/client-x402'
40+
41+
const query = createGraphQuery({
42+
endpoint: 'https://gateway.thegraph.com/api/x402/subgraphs/id/<SUBGRAPH_ID>',
43+
chain: 'base',
44+
})
45+
46+
const result = await query('{ pairs(first: 5) { id } }')
47+
console.log(result.data)
48+
```
49+
50+
### 3. Typed SDK
51+
52+
For applications that want full type safety. Uses the `@graphprotocol/client-cli` build workflow to generate a typed SDK from your schema.
53+
54+
**Install:**
55+
56+
```bash
57+
npm install @graphprotocol/client-cli @graphprotocol/client-x402
58+
```
59+
60+
**Configure `.graphclientrc.yml`:**
61+
62+
```yaml
63+
customFetch: '@graphprotocol/client-x402'
64+
65+
sources:
66+
- name: uniswap
67+
handler:
68+
graphql:
69+
endpoint: https://gateway.thegraph.com/api/x402/subgraphs/id/<SUBGRAPH_ID>
70+
71+
documents:
72+
- ./src/queries/*.graphql
73+
```
74+
75+
**Define your queries in `src/queries/pairs.graphql`:**
76+
77+
```graphql
78+
query GetPairs($first: Int!) {
79+
pairs(first: $first) {
80+
id
81+
token0 {
82+
symbol
83+
}
84+
token1 {
85+
symbol
86+
}
87+
}
88+
}
89+
```
90+
91+
**Build:**
92+
93+
```bash
94+
export X402_PRIVATE_KEY=0xabc123...
95+
export X402_CHAIN=base
96+
graphclient build
97+
rm .graphclient/package.json # Required: mesh generates broken ESM exports
98+
```
99+
100+
**Use with full type safety:**
101+
102+
```typescript
103+
import { execute, GetPairsDocument } from './.graphclient'
104+
105+
const result = await execute(GetPairsDocument, { first: 5 })
106+
// ^ fully typed based on your schema and query
107+
```
108+
109+
## Configuration
110+
111+
All configuration is via environment variables:
112+
113+
```bash
114+
export X402_PRIVATE_KEY=0x... # Required: private key for signing payments
115+
export X402_CHAIN=base # Optional: "base" (default) or "base-sepolia"
116+
```
117+
118+
### Private Key
119+
120+
Required for signing payment permits. Can also be provided via:
121+
122+
- `privateKey` option in `createGraphQuery()` (Mode 2)
123+
- `config.x402PrivateKey` in `execute()` context (Mode 3)
124+
125+
### Chain
126+
127+
The payment chain can also be specified via:
128+
129+
- `chain` option in `createGraphQuery()` (Mode 2)
130+
- `--chain` flag in CLI (Mode 1)

0 commit comments

Comments
 (0)