@valve-tech/trueblocks-sdk 0.10.1 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +225 -0
- package/CHANGELOG.md +23 -0
- package/package.json +3 -1
- package/skills/trueblocks-sdk-integration/SKILL.md +228 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Terse reference for AI agents (Claude Code, Cursor, Aider, etc.) integrating
|
|
4
|
+
`@valve-tech/trueblocks-sdk`. The full README is for humans; this file is for
|
|
5
|
+
agents that need to ground their work in the package's actual surface
|
|
6
|
+
quickly.
|
|
7
|
+
|
|
8
|
+
(For contributor-facing notes — codegen pipeline, file map,
|
|
9
|
+
clean-room rule, test pattern — see `INTERNALS.md` in the package
|
|
10
|
+
root, not shipped in the npm tarball.)
|
|
11
|
+
|
|
12
|
+
## What this package does
|
|
13
|
+
|
|
14
|
+
Typed TypeScript HTTP client to a running [TrueBlocks](https://trueblocks.io)
|
|
15
|
+
`chifra daemon`. Same verb surface as the upstream Go SDK, delivered
|
|
16
|
+
as `fetch`-based REST calls — no Go runtime, no subprocess spawning,
|
|
17
|
+
browser/mobile safe.
|
|
18
|
+
|
|
19
|
+
54 methods total: 18 base methods (one per chifra HTTP endpoint) +
|
|
20
|
+
36 narrowed variant accessors on the polymorphic ones (e.g.
|
|
21
|
+
`client.blocks.logs(...)` returns `Log[]` instead of the polymorphic
|
|
22
|
+
`(Block | LightBlock | Log | …)[]` union).
|
|
23
|
+
|
|
24
|
+
**No peer dependencies.** Uses `globalThis.fetch` (Node 18+, every
|
|
25
|
+
modern browser).
|
|
26
|
+
|
|
27
|
+
**Prerequisite:** a running `chifra daemon` somewhere this client
|
|
28
|
+
can reach over HTTP. This package does NOT bundle or invoke chifra —
|
|
29
|
+
the user installs `trueblocks-core` separately and indexes the chains
|
|
30
|
+
they care about. If they can't run chifra, this package isn't for
|
|
31
|
+
them.
|
|
32
|
+
|
|
33
|
+
## Public API
|
|
34
|
+
|
|
35
|
+
All exports live under `src/index.ts`. Single subpath; no sub-exports.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import {
|
|
39
|
+
createTrueblocksClient, // primary constructor
|
|
40
|
+
TrueblocksError, // typed error class
|
|
41
|
+
// verb-machinery exports (rare to import directly)
|
|
42
|
+
createVerbs,
|
|
43
|
+
makeVerb,
|
|
44
|
+
// types
|
|
45
|
+
type CreateTrueblocksClientOptions,
|
|
46
|
+
type TrueblocksClient,
|
|
47
|
+
type FetchFn,
|
|
48
|
+
type RequestFn,
|
|
49
|
+
type Query,
|
|
50
|
+
type Response,
|
|
51
|
+
type VerbFn,
|
|
52
|
+
type Verbs,
|
|
53
|
+
type IsRequiredQuery,
|
|
54
|
+
// raw OpenAPI types (escape hatch when the verb wrapper isn't enough)
|
|
55
|
+
type components,
|
|
56
|
+
type operations,
|
|
57
|
+
type paths,
|
|
58
|
+
} from '@valve-tech/trueblocks-sdk'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Three things you must know
|
|
62
|
+
|
|
63
|
+
| | |
|
|
64
|
+
|---|---|
|
|
65
|
+
| **Constructor** | `createTrueblocksClient({ baseUrl: 'http://localhost:8080' })` returns a `TrueblocksClient` with one method per chifra endpoint. Optional `fetch` override for testing or custom transport. |
|
|
66
|
+
| **Verb shape** | Every chifra HTTP endpoint is a typed method on the client. Method names match the chifra CLI verbs (`list`, `export`, `blocks`, `transactions`, etc.). |
|
|
67
|
+
| **Polymorphic vs variant** | Base methods return the OpenAPI polymorphic union (useful when flag combinations are constructed at runtime). Variants (`client.blocks.logs(...)`) preselect a flag and narrow the return type to the single concrete shape that flag produces. Mirrors the Go SDK's `XxxOptions.XxxFlag()` pattern. |
|
|
68
|
+
|
|
69
|
+
## The verb surface (54 methods)
|
|
70
|
+
|
|
71
|
+
| Group | Method | Endpoint | Variants |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| Accounts | `client.list(...)` | `GET /list` | — |
|
|
74
|
+
| Accounts | `client.export(...)` | `GET /export` | `.appearances` `.receipts` `.logs` `.approvals` `.traces` `.neighbors` `.statements` `.transfers` `.assets` `.balances` `.withdrawals` `.count` |
|
|
75
|
+
| Accounts | `client.monitors(...)` | `GET /monitors` | — |
|
|
76
|
+
| Accounts | `client.names(...)` | `GET /names` | — |
|
|
77
|
+
| Accounts | `client.abis(...)` | `GET /abis` | — |
|
|
78
|
+
| Chain Data | `client.blocks(...)` | `GET /blocks` | `.hashes` `.uncles` `.traces` `.uniq` `.logs` `.withdrawals` `.count` |
|
|
79
|
+
| Chain Data | `client.transactions(...)` | `GET /transactions` | `.traces` `.uniq` `.logs` |
|
|
80
|
+
| Chain Data | `client.receipts(...)` | `GET /receipts` | — |
|
|
81
|
+
| Chain Data | `client.logs(...)` | `GET /logs` | — |
|
|
82
|
+
| Chain Data | `client.traces(...)` | `GET /traces` | `.count` |
|
|
83
|
+
| Chain State | `client.when(...)` | `GET /when` | — |
|
|
84
|
+
| Chain State | `client.state(...)` | `GET /state` | `.call` |
|
|
85
|
+
| Chain State | `client.tokens(...)` | `GET /tokens` | — |
|
|
86
|
+
| Admin | `client.config(...)` | `GET /config` | — |
|
|
87
|
+
| Admin | `client.status(...)` | `GET /status` | — |
|
|
88
|
+
| Admin | `client.chunks(...)` | `GET /chunks` | `.manifest` `.index` `.blooms` `.pins` `.addresses` `.appearances` `.stats` |
|
|
89
|
+
| Admin | `client.init(...)` | `GET /init` | — |
|
|
90
|
+
| Other | `client.slurp(...)` | `GET /slurp` | `.appearances` `.count` |
|
|
91
|
+
|
|
92
|
+
`client.send(...)` (`chifra send`) is NOT exposed — the upstream
|
|
93
|
+
OpenAPI spec doesn't currently cover it, and this package is
|
|
94
|
+
codegen-driven so unspec'd endpoints are not in the surface. To send
|
|
95
|
+
transactions, use a wallet library (viem/ethers/wagmi) or
|
|
96
|
+
`@valve-tech/wallet-adapter` directly.
|
|
97
|
+
|
|
98
|
+
## Polymorphic vs variant — when to use which
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// Polymorphic — narrow at the call site:
|
|
102
|
+
const result = await client.blocks({ blocks: ['18000000'], logs: true })
|
|
103
|
+
// result.data is (Block | LightBlock | Log | …)[]
|
|
104
|
+
if (result.data[0]?.address) {
|
|
105
|
+
// narrowed to Log
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Variant — concrete return type, no narrowing needed:
|
|
109
|
+
const result = await client.blocks.logs({ blocks: ['18000000'] })
|
|
110
|
+
// result.data is Log[]
|
|
111
|
+
result.data[0]?.address // ✓ already narrowed
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use the variant when the flag is known statically. Use the polymorphic
|
|
115
|
+
shape when flag combinations are computed at runtime (e.g. building a
|
|
116
|
+
chifra query from a UI toggle).
|
|
117
|
+
|
|
118
|
+
## Errors
|
|
119
|
+
|
|
120
|
+
Every chifra-side failure throws a `TrueblocksError`:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
try {
|
|
124
|
+
await client.status()
|
|
125
|
+
} catch (err) {
|
|
126
|
+
if (err instanceof TrueblocksError) {
|
|
127
|
+
err.path // chifra endpoint that failed (e.g. '/status')
|
|
128
|
+
err.status // HTTP status if applicable
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
No silent fallbacks: if the daemon returns an error or an unexpected
|
|
134
|
+
shape, you get a typed throw.
|
|
135
|
+
|
|
136
|
+
## Pitfalls (read these)
|
|
137
|
+
|
|
138
|
+
1. **Forgetting the daemon prerequisite.** This package is a *client* —
|
|
139
|
+
it talks to a running `chifra daemon`. If `baseUrl` doesn't have a
|
|
140
|
+
chifra serving on the other end, every call throws a
|
|
141
|
+
`TrueblocksError` with a connection failure. The package can't help
|
|
142
|
+
the user install or run chifra; redirect them to
|
|
143
|
+
https://trueblocks.io/docs/install/install-core/.
|
|
144
|
+
|
|
145
|
+
2. **Calling `client.send(...)`.** It doesn't exist — chifra's send
|
|
146
|
+
surface isn't in the upstream OpenAPI spec, so it's not in the
|
|
147
|
+
typed client. To send a transaction, use viem/ethers/wagmi or
|
|
148
|
+
`@valve-tech/wallet-adapter`. Use trueblocks-sdk for the *read*
|
|
149
|
+
side (history, receipts, traces, balances).
|
|
150
|
+
|
|
151
|
+
3. **Mixing `client.blocks(...)` polymorphic with branch-by-shape
|
|
152
|
+
logic.** When the result is the polymorphic union, narrow with a
|
|
153
|
+
type guard or an `if (data[0]?.specificField)` check. Use the
|
|
154
|
+
variant accessor (`client.blocks.logs(...)`) instead if the
|
|
155
|
+
polymorphism isn't load-bearing — it removes the narrowing
|
|
156
|
+
ceremony.
|
|
157
|
+
|
|
158
|
+
4. **Treating `client.list(...)` results as full transactions.**
|
|
159
|
+
`list` returns *appearances* (lightweight pointers — `bn`/`tx_id`/
|
|
160
|
+
`address` triples), not full transactions or receipts. To go from
|
|
161
|
+
appearance to data, follow up with `client.transactions(...)` /
|
|
162
|
+
`client.receipts(...)`.
|
|
163
|
+
|
|
164
|
+
5. **Calling `client.export(...)` without `addrs`.** Most `export`
|
|
165
|
+
variants are address-scoped — the request shape will be a TS
|
|
166
|
+
error if `addrs` is required, but worth flagging because the
|
|
167
|
+
error message points at the codegen'd schema, not the
|
|
168
|
+
human-readable docs.
|
|
169
|
+
|
|
170
|
+
6. **Building URLs by hand to add a flag the SDK doesn't expose.**
|
|
171
|
+
The codegen'd types reflect the spec — every flag the spec
|
|
172
|
+
declares is on the verb method's `Query` type. If something
|
|
173
|
+
appears missing, check the chifra version pinned in
|
|
174
|
+
`scripts/codegen.mjs` (in the source repo) — the spec may be
|
|
175
|
+
newer than the pin.
|
|
176
|
+
|
|
177
|
+
7. **bigint vs string at numeric boundaries.** Generated types
|
|
178
|
+
carry whatever the spec said (often `string` for safety —
|
|
179
|
+
block numbers, gas, fees can exceed 2^53). The verb wrappers
|
|
180
|
+
convert at the boundary where appropriate, but always-string
|
|
181
|
+
fields stay strings. Test before assuming a `bigint` arrived.
|
|
182
|
+
|
|
183
|
+
8. **No retry / backoff built in.** The client makes one fetch call
|
|
184
|
+
per verb invocation. If the user wants retries, they wrap the
|
|
185
|
+
call themselves or pass a custom `fetch` that retries.
|
|
186
|
+
|
|
187
|
+
## Composition
|
|
188
|
+
|
|
189
|
+
trueblocks-sdk is read-side history/state. It composes with:
|
|
190
|
+
|
|
191
|
+
- **`@valve-tech/wallet-adapter`** — for the write/send side, since
|
|
192
|
+
the SDK doesn't expose `send`.
|
|
193
|
+
- **`@valve-tech/tx-tracker`** — for live per-tx state-machine work.
|
|
194
|
+
trueblocks gives you historical reads; tx-tracker watches
|
|
195
|
+
in-flight txs as they confirm. Different layers, complementary.
|
|
196
|
+
- **`@valve-tech/chain-source`** — for raw block/mempool streams.
|
|
197
|
+
trueblocks is server-side indexed history; chain-source is local
|
|
198
|
+
RPC observation.
|
|
199
|
+
|
|
200
|
+
## When to skip this package
|
|
201
|
+
|
|
202
|
+
- **No running chifra daemon.** Use viem/ethers directly against an
|
|
203
|
+
RPC. Chifra's value is precomputed indexes (appearances,
|
|
204
|
+
monitors); without the daemon, this package is just an HTTP
|
|
205
|
+
client to an endpoint that won't respond.
|
|
206
|
+
- **Live in-flight tx tracking.** Use `@valve-tech/tx-tracker`.
|
|
207
|
+
trueblocks is for historical reads, not push-style observation
|
|
208
|
+
of new chain events.
|
|
209
|
+
- **Sending transactions.** Use a wallet library (or
|
|
210
|
+
`@valve-tech/wallet-adapter`). chifra's send surface isn't
|
|
211
|
+
exposed here.
|
|
212
|
+
|
|
213
|
+
## Skills (for AI agents)
|
|
214
|
+
|
|
215
|
+
`skills/` ships in the npm tarball. If you're an AI agent working in a
|
|
216
|
+
project that has installed this package, look in
|
|
217
|
+
`node_modules/@valve-tech/trueblocks-sdk/skills/trueblocks-sdk-integration/SKILL.md`
|
|
218
|
+
for trigger conditions, anti-pattern flags, and integration recipes.
|
|
219
|
+
|
|
220
|
+
## Verifying provenance
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npm view @valve-tech/trueblocks-sdk@latest --json | jq .dist.attestations
|
|
224
|
+
npm audit signatures
|
|
225
|
+
```
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,29 @@ this file.
|
|
|
6
6
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
7
7
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
8
8
|
|
|
9
|
+
## [0.11.1] — 2026-05-11
|
|
10
|
+
|
|
11
|
+
### Notes
|
|
12
|
+
|
|
13
|
+
- Synchronized release — no changes to this package. Republished at
|
|
14
|
+
0.11.1 alongside the rest of the toolkit; the substantive fix is
|
|
15
|
+
in `@valve-tech/tx-tracker` (upgrade-path crash on the first
|
|
16
|
+
block tick after upgrading a persistent store from ≤0.10 to
|
|
17
|
+
0.11.0). See `@valve-tech/tx-tracker`'s CHANGELOG for details.
|
|
18
|
+
|
|
19
|
+
## [0.11.0] — 2026-05-11
|
|
20
|
+
|
|
21
|
+
### Notes
|
|
22
|
+
|
|
23
|
+
- Synchronized release — no changes to this package. Bumped in
|
|
24
|
+
lockstep with the rest of the toolkit alongside the v0.11.0
|
|
25
|
+
feature work in `@valve-tech/gas-oracle` (20-block ring lifecycle,
|
|
26
|
+
reorg detection, gap bridging), `@valve-tech/tx-tracker` (audit
|
|
27
|
+
fixes — durable rehydrate, retention enforcement, replaced-by
|
|
28
|
+
dedup, receipt-poll race, helper extraction), `@valve-tech/
|
|
29
|
+
wallet-adapter` (five wallet bridge examples), and
|
|
30
|
+
`@valve-tech/chain-source` (canonical-owner docs for wire types).
|
|
31
|
+
|
|
9
32
|
## [0.10.1] — 2026-05-08
|
|
10
33
|
|
|
11
34
|
**First successful npm publish at the v0.10.x line.** v0.10.0's
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valve-tech/trueblocks-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Typed TypeScript HTTP client to a running TrueBlocks chifra daemon. Wraps chifra's REST surface (the same one served by `chifra daemon`) with TS types generated from the upstream OpenAPI spec; no Go runtime, no shelling-out.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/valve-tech/evm-toolkit/tree/main/packages/trueblocks-sdk#readme",
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
34
|
"dist",
|
|
35
|
+
"skills",
|
|
35
36
|
"README.md",
|
|
37
|
+
"AGENTS.md",
|
|
36
38
|
"CHANGELOG.md",
|
|
37
39
|
"LICENSE"
|
|
38
40
|
],
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: trueblocks-sdk-integration
|
|
3
|
+
description: Integrate `@valve-tech/trueblocks-sdk` — typed TypeScript HTTP client to a running TrueBlocks `chifra daemon` — into a dapp, indexer, analytics tool, or backend. Use when the user wants to query historical chain data via chifra (`list` appearances, `export` receipts/logs/transfers/balances, `blocks` / `transactions` / `receipts` / `traces` / `logs` reads, `monitors` / `names` / `abis` lookups, `when` / `state` / `tokens` chain-state queries, or `chunks` / `init` / `config` / `status` admin endpoints), is asking how to wire a chifra daemon URL into TS code, needs to discriminate the polymorphic `client.blocks(...)` return vs use a variant accessor like `client.blocks.logs(...)`, or sees imports from `@valve-tech/trueblocks-sdk`. Also fires for "how do I get all transfers for an address", "list ERC-20 holders", "address appearances", "decode receipts via chifra", or questions about `TrueblocksError`, the `baseUrl` option, the `fetch` override, the 54-method/36-variant surface, or why `client.send(...)` doesn't exist (the upstream OpenAPI spec doesn't cover chifra's send surface — that's intentional). Skip when the user wants to SEND transactions (delegate to wallet-adapter-integration — chifra's send isn't in the typed surface), wants live in-flight tx tracking via push/poll (delegate to tx-tracker-integration — trueblocks is historical reads, not live observation), wants raw RPC block/mempool streams (delegate to chain-source-integration), or doesn't have a running chifra daemon and isn't planning to install trueblocks-core (the SDK requires it; recommend they install or use a different read source like viem `client.getLogs` / The Graph / Alchemy enhanced APIs).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Integrating `@valve-tech/trueblocks-sdk`
|
|
7
|
+
|
|
8
|
+
Typed TypeScript HTTP client to a running TrueBlocks `chifra daemon`.
|
|
9
|
+
Same verb surface as the upstream Go SDK, delivered as `fetch`-based
|
|
10
|
+
REST calls. This skill is for AI agents working in a project that
|
|
11
|
+
imports the package — especially helping the user pick the right verb
|
|
12
|
+
+ variant for what they're trying to read.
|
|
13
|
+
|
|
14
|
+
## Hard prerequisite — flag this first
|
|
15
|
+
|
|
16
|
+
The user **must** have a running `chifra daemon` reachable from their
|
|
17
|
+
runtime. This package is a CLIENT, not a server. It does NOT bundle,
|
|
18
|
+
spawn, or install chifra. If the user doesn't have chifra running,
|
|
19
|
+
no amount of TS-side configuration helps.
|
|
20
|
+
|
|
21
|
+
Before recommending integration code, confirm:
|
|
22
|
+
- [ ] User has installed `trueblocks-core` (https://trueblocks.io/docs/install/install-core/).
|
|
23
|
+
- [ ] User has indexed the chain(s) they care about (`chifra init`).
|
|
24
|
+
- [ ] User has the daemon running (`chifra daemon`) and knows the URL
|
|
25
|
+
it's serving on (default `http://localhost:8080`).
|
|
26
|
+
|
|
27
|
+
If any of these are unclear, ASK before writing code. A working
|
|
28
|
+
client wired to a non-running daemon throws `TrueblocksError` on
|
|
29
|
+
every call — frustrating, and the SDK can't help.
|
|
30
|
+
|
|
31
|
+
## Decision tree: which verb to use
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
What does the user want to know?
|
|
35
|
+
├── "Which transactions involve this address?"
|
|
36
|
+
│ → client.list({ addrs: [address] }) (lightweight appearances)
|
|
37
|
+
│
|
|
38
|
+
├── "Full transactions / receipts / logs / transfers / balances for this address"
|
|
39
|
+
│ → client.export(...) + the variant they want:
|
|
40
|
+
│ .receipts / .logs / .transfers / .balances / .approvals / etc.
|
|
41
|
+
│
|
|
42
|
+
├── "Block X" / "blocks N..M"
|
|
43
|
+
│ → client.blocks({ blocks: [...] }) + variant:
|
|
44
|
+
│ .logs / .uncles / .traces / .withdrawals / .uniq / .count
|
|
45
|
+
│
|
|
46
|
+
├── "Transaction by hash"
|
|
47
|
+
│ → client.transactions({ transactions: [...] }) + variant:
|
|
48
|
+
│ .traces / .uniq / .logs
|
|
49
|
+
│
|
|
50
|
+
├── "Receipt(s) by hash"
|
|
51
|
+
│ → client.receipts({ transactions: [...] })
|
|
52
|
+
│
|
|
53
|
+
├── "When did block X happen / what block was at timestamp T"
|
|
54
|
+
│ → client.when({ blocks: [...] | timestamps: [...] })
|
|
55
|
+
│
|
|
56
|
+
├── "Read contract state / call view function"
|
|
57
|
+
│ → client.state({ addrs, parts }) or client.state.call({ addrs, call })
|
|
58
|
+
│
|
|
59
|
+
├── "Token balances / transfers"
|
|
60
|
+
│ → client.tokens({ addrs, blocks }) or client.export.balances(...)
|
|
61
|
+
│
|
|
62
|
+
├── "Daemon status / config / chunks"
|
|
63
|
+
│ → client.status() / client.config() / client.chunks(...)
|
|
64
|
+
│
|
|
65
|
+
└── "Send a transaction"
|
|
66
|
+
→ NOT in this SDK. Delegate to wallet-adapter-integration.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## How to recognize this package in the user's code
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import {
|
|
73
|
+
createTrueblocksClient,
|
|
74
|
+
TrueblocksError,
|
|
75
|
+
} from '@valve-tech/trueblocks-sdk'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`package.json` will show `"@valve-tech/trueblocks-sdk": "^0.10.x"`. No peer deps.
|
|
79
|
+
|
|
80
|
+
## Canonical setup
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { createTrueblocksClient, TrueblocksError } from '@valve-tech/trueblocks-sdk'
|
|
84
|
+
|
|
85
|
+
const client = createTrueblocksClient({
|
|
86
|
+
baseUrl: process.env.CHIFRA_URL ?? 'http://localhost:8080',
|
|
87
|
+
// optional: pass a custom fetch for retry/auth/logging
|
|
88
|
+
// fetch: myCustomFetch,
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const status = await client.status()
|
|
93
|
+
if (!status.is_responding) {
|
|
94
|
+
throw new Error('chifra daemon not ready')
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (err instanceof TrueblocksError) {
|
|
98
|
+
console.error('chifra error', err.path, err.status, err.message)
|
|
99
|
+
}
|
|
100
|
+
throw err
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Polymorphic vs variant — the most-likely-to-confuse decision
|
|
105
|
+
|
|
106
|
+
`client.blocks(...)` (polymorphic) returns a union of every shape the
|
|
107
|
+
flag combination COULD produce:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const result = await client.blocks({ blocks: ['18000000'], logs: true })
|
|
111
|
+
// result.data is (Block | LightBlock | Log | Withdrawal | …)[]
|
|
112
|
+
// — narrow with a type guard before accessing fields
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`client.blocks.logs(...)` (variant) preselects the `logs` flag and
|
|
116
|
+
narrows to the single concrete shape:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const result = await client.blocks.logs({ blocks: ['18000000'] })
|
|
120
|
+
// result.data is Log[] — no narrowing needed
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Use the variant when the flag is known at code-time. Use the
|
|
124
|
+
polymorphic when flag combinations are computed at runtime (UI toggles,
|
|
125
|
+
config-driven queries).
|
|
126
|
+
|
|
127
|
+
## Anti-patterns to flag
|
|
128
|
+
|
|
129
|
+
When reviewing user code, watch for these and suggest fixes:
|
|
130
|
+
|
|
131
|
+
1. **Calling `client.send(...)`.** Doesn't exist. Chifra's send
|
|
132
|
+
surface isn't in the upstream OpenAPI spec, so it's not in the
|
|
133
|
+
typed client. Redirect: use viem / ethers / wagmi or
|
|
134
|
+
`@valve-tech/wallet-adapter` for the write side. Trueblocks is
|
|
135
|
+
read-only history.
|
|
136
|
+
|
|
137
|
+
2. **No daemon URL guard.** A `createTrueblocksClient({ baseUrl })`
|
|
138
|
+
call to a non-running daemon doesn't fail at construction — it
|
|
139
|
+
fails on the first verb call. Add a `client.status()` probe at
|
|
140
|
+
startup if your code path needs early failure (boot, healthcheck,
|
|
141
|
+
smoke test).
|
|
142
|
+
|
|
143
|
+
3. **Treating `client.list(...)` results as full transactions.**
|
|
144
|
+
`list` returns *appearances* — lightweight pointers (`bn`,
|
|
145
|
+
`tx_id`, `address`). To get full data, chain through
|
|
146
|
+
`client.transactions(...)` or `client.export(...)`:
|
|
147
|
+
```ts
|
|
148
|
+
const apps = await client.list({ addrs: [address] })
|
|
149
|
+
const txs = await client.transactions({
|
|
150
|
+
transactions: apps.data.map(a => `${a.bn}.${a.tx_id}`),
|
|
151
|
+
})
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
4. **Polymorphic `client.blocks(...)` when a variant exists.** If
|
|
155
|
+
the flag is known statically, use the variant — narrower types,
|
|
156
|
+
no in-place narrowing required:
|
|
157
|
+
```ts
|
|
158
|
+
// ❌ then narrows in user code
|
|
159
|
+
const r = await client.blocks({ blocks, logs: true })
|
|
160
|
+
const logs = (r.data as Log[]).filter(...)
|
|
161
|
+
|
|
162
|
+
// ✅ already narrowed
|
|
163
|
+
const r = await client.blocks.logs({ blocks })
|
|
164
|
+
r.data.filter(...)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
5. **`client.export(...)` without `addrs`.** Most export variants
|
|
168
|
+
are address-scoped — TS will catch missing `addrs`, but the
|
|
169
|
+
error points at the generated schema. Reframe: "you need to
|
|
170
|
+
pass `addrs: [...]`".
|
|
171
|
+
|
|
172
|
+
6. **Hand-building URLs to access a missing flag.** The codegen'd
|
|
173
|
+
types reflect the OpenAPI spec at the pinned chifra commit. If
|
|
174
|
+
a flag appears missing, check the spec version — chifra may
|
|
175
|
+
have advanced past the pin. The SDK doesn't expose runtime
|
|
176
|
+
escape-hatch URL building (deliberately, to keep the surface
|
|
177
|
+
typed).
|
|
178
|
+
|
|
179
|
+
7. **bigint vs string at numeric boundaries.** Generated types
|
|
180
|
+
carry the spec's choice (often `string` for safety — block
|
|
181
|
+
numbers, gas, fees can exceed 2^53). The verb wrappers
|
|
182
|
+
convert at the boundary where appropriate, but always-string
|
|
183
|
+
fields stay strings. Don't `BigInt(field)` without checking
|
|
184
|
+
the type.
|
|
185
|
+
|
|
186
|
+
8. **No retry / backoff for flaky daemon connections.** The
|
|
187
|
+
client makes one fetch call per verb. If the daemon is
|
|
188
|
+
intermittent, wrap the call (or pass a `fetch` override that
|
|
189
|
+
retries):
|
|
190
|
+
```ts
|
|
191
|
+
createTrueblocksClient({
|
|
192
|
+
baseUrl,
|
|
193
|
+
fetch: async (url, init) => {
|
|
194
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
195
|
+
try { return await fetch(url, init) }
|
|
196
|
+
catch (e) { if (attempt === 2) throw e; await sleep(100 * 2**attempt) }
|
|
197
|
+
}
|
|
198
|
+
throw new Error('unreachable')
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
9. **Querying chains the daemon hasn't indexed.** chifra serves
|
|
204
|
+
only chains the user has run `chifra init` for. If they ask
|
|
205
|
+
about a new chain (e.g. they indexed mainnet but query
|
|
206
|
+
PulseChain), every call returns empty / errors. Confirm
|
|
207
|
+
indexed chains via `client.config()` if uncertain.
|
|
208
|
+
|
|
209
|
+
## When to skip this package
|
|
210
|
+
|
|
211
|
+
- **Sending transactions** — use wallet-adapter / viem / ethers.
|
|
212
|
+
- **Live in-flight tx state-machine** — use `@valve-tech/tx-tracker`
|
|
213
|
+
(trueblocks is historical reads, not push observation).
|
|
214
|
+
- **Raw block/mempool streams** — use `@valve-tech/chain-source`.
|
|
215
|
+
- **No chifra daemon and not installing one** — recommend viem
|
|
216
|
+
`client.getLogs` / The Graph / Alchemy enhanced APIs / Etherscan
|
|
217
|
+
API instead. Don't try to make trueblocks work without its server.
|
|
218
|
+
|
|
219
|
+
## Where to find more
|
|
220
|
+
|
|
221
|
+
- Full API + types: `node_modules/@valve-tech/trueblocks-sdk/AGENTS.md`
|
|
222
|
+
- Human-facing docs: `node_modules/@valve-tech/trueblocks-sdk/README.md`
|
|
223
|
+
- Compiled output: `node_modules/@valve-tech/trueblocks-sdk/dist/`
|
|
224
|
+
- Upstream chifra docs: https://trueblocks.io/docs/
|
|
225
|
+
- Sibling skills:
|
|
226
|
+
- wallet-adapter-integration for the write/send side
|
|
227
|
+
- tx-tracker-integration for live tx watching
|
|
228
|
+
- chain-source-integration for raw RPC streams
|