11# Airnode v2
22
3- > ** ⚠️ EXPERIMENTAL — DO NOT USE IN PRODUCTION ⚠️**
4- >
5- > This project is under active development. The code has ** not been audited** . The contracts, signature formats, and
6- > APIs are subject to breaking changes without notice. ** Do not use this software for production workloads, mainnet
7- > deployments, or any system where security or financial loss is a concern.**
3+ > ** This project is under active development. The code has not been audited. Signature formats, APIs, and contracts are
4+ > subject to breaking changes. Do not use for production workloads or mainnet deployments.**
85
9- An HTTP server that signs API responses. API providers run it alongside their existing APIs. Clients receive signed data
10- and can optionally submit it on-chain.
6+ Sign API responses with your private key and serve them over HTTP. Clients verify signatures off-chain or submit them to
7+ on-chain contracts. No chain scanning, no database, no coordinator — a stateless HTTP service that sits in front of your
8+ existing API.
119
12- ## What it does
10+ ## How it works
1311
1412```
15- Client → HTTP request → Airnode → upstream API → sign response → HTTP response
13+ Client ──POST──▶ Airnode ──HTTP──▶ Upstream API
14+ │ │
15+ │◀───JSON response───┘
16+ │
17+ ├─ Extract value (JSONPath)
18+ ├─ ABI-encode (int256, uint256, ...)
19+ ├─ Sign (EIP-191)
20+ │
21+ ▼
22+ Signed response ──▶ verify off-chain or submit on-chain
1623```
1724
18- The airnode never touches the chain. It calls upstream APIs, signs the responses with the operator's private key
19- (EIP-191), and returns the signed data. Clients can verify signatures off-chain or submit them to on-chain contracts.
25+ ** Pull** — client sends ` POST /endpoints/{endpointId} ` , gets a signed response back.
2026
21- Two delivery paths:
22-
23- - ** Pull** — client sends ` POST /endpoints/{endpointId} ` , gets a signed response back immediately
24- - ** Push** — server calls APIs on a timer, stores signed data, relayers poll ` GET /beacons/{beaconId} ` and push on-chain
25-
26- ## Prerequisites
27-
28- | Tool | Version | Install |
29- | ------------------------------------- | ------- | ----------------------------------------------------------- |
30- | [ Bun] ( https://bun.sh ) | latest | ` curl -fsSL https://bun.sh/install \| bash ` |
31- | [ Foundry] ( https://book.getfoundry.sh ) | >= 1.0 | ` curl -L https://foundry.paradigm.xyz \| bash && foundryup ` |
32- | [ uv] ( https://docs.astral.sh/uv/ ) | latest | ` curl -LsSf https://astral.sh/uv/install.sh \| sh ` |
33-
34- Python tools (Vyper, Slither, Halmos) are installed via [ uv] ( https://docs.astral.sh/uv/ ) :
35-
36- ``` bash
37- uv tool install vyper
38- uv tool install slither-analyzer
39- uv tool install halmos
40- ```
27+ ** Push** — server calls APIs on a timer, signs the data, stores it as beacons. Relayers poll ` GET /beacons/{beaconId} `
28+ and submit on-chain.
4129
4230## Quick start
4331
4432``` bash
4533bun install
46- bun src/cli/index.ts generate-key
34+ bun airnode generate-key # prints private key + address
4735cp examples/configs/minimal/config.yaml config.yaml
4836cp examples/configs/minimal/.env.example .env
49- # Edit .env with your generated private key
37+ # paste your private key into .env
5038bun run dev
5139```
5240
53- Test it:
54-
55- ``` bash
56- curl http://localhost:3000/health
57- ```
58-
59- ## Scripts
60-
61- | Script | Description |
62- | -------------------------- | ---------------------------------------- |
63- | ` bun run dev ` | Start the server with ` --watch ` |
64- | ` bun test ` | Run unit tests (src/) |
65- | ` bun run test:integration ` | Run integration tests (sequential) |
66- | ` bun run test:contracts ` | Run contract tests (Foundry) |
67- | ` bun run fmt ` | Format (Prettier) and lint-fix (ESLint) |
68- | ` bun run lint ` | Check formatting and linting |
69- | ` bun run lint:slither ` | Run Slither static analysis on contracts |
70-
71- ## Build
72-
73- Compile to a standalone binary:
41+ Make a request (replace ` {endpointId} ` with the ID printed at startup):
7442
7543``` bash
76- bun run build:osx # macOS ARM64
77- bun run build:linux-x64 # Linux x86_64
78-
79- ./dist/airnode start # Uses config.yaml + .env
80- ./dist/airnode start -c /path/to/config.yaml # Custom config path
44+ curl -X POST http://localhost:3000/endpoints/{endpointId} \
45+ -H " Content-Type: application/json" \
46+ -d ' {"parameters":{"ids":"ethereum","vs_currencies":"usd"}}'
8147```
8248
83- ## Project structure
84-
85- ```
86- src/
87- cli/ CLI entry point and commands
88- config/ Zod schema, YAML parser, validator, env interpolation
89- api/ HTTP call building and response processing
90- server.ts Bun.serve HTTP server (routes, CORS, rate limiting)
91- pipeline.ts Request processing pipeline (auth → validate → cache → API call → sign)
92- push.ts Background push loop and beacon store
93- auth.ts Client-facing authentication (free / apiKey)
94- cache.ts In-memory TTL response cache with periodic sweep
95- sign.ts EIP-191 signing, request ID and beacon ID derivation
96- endpoint.ts Specification-bound endpoint ID derivation
97- plugins.ts Plugin loader, hook registry, budget tracking
98- identity.ts DNS identity verification (ERC-7529)
99- logger.ts Structured logger with AsyncLocalStorage context
100- types.ts Shared Zod-inferred types
101- contracts/ Vyper contracts and Foundry tests
102- examples/
103- configs/ Reference configurations (complete + minimal)
104- plugins/ Example plugins (heartbeat, logger, slack-alerts, encrypted-channel)
105- integration/ Integration tests (22 scenario files)
106- book/ Documentation site (Docusaurus)
49+ ``` json
50+ {
51+ "airnode" : " 0x..." ,
52+ "endpointId" : " 0x..." ,
53+ "timestamp" : 1711234567 ,
54+ "data" : " 0x0000000000000000000000000000000000000000000000a2a15d09519be00000" ,
55+ "signature" : " 0x..."
56+ }
10757```
10858
109- ## Contracts
110-
111- Two Vyper 0.4+ contracts targeting the ** prague** EVM version:
112-
113- | Contract | Purpose |
114- | -------------------- | ----------------------------------------------------- |
115- | ` AirnodeVerifier.vy ` | Verify signature, prevent replay, forward to callback |
116- | ` AirnodeDataFeed.vy ` | Verify signature, store latest value, serve reads |
117-
118- Both use the same signature: ` keccak256(encodePacked(endpointId, timestamp, data)) ` with EIP-191 personal sign.
59+ ## What you can do
11960
120- See [ ` contracts/README.md ` ] ( contracts/README.md ) for architecture docs, consumer integration examples, and the full test
121- suite.
61+ - ** Sign any API response** with your key — turn untrusted data into a verifiable attestation
62+ - ** Serve data to smart contracts** — ABI-encoded responses ready for on-chain submission
63+ - ** Run continuous data feeds** — push signed prices, weather, or any updating data on a timer
64+ - ** Monetize access** — API keys, NFT-gated endpoints, or pay-per-request via x402
65+ - ** Control encoding at request time** — clients pass ` _type ` , ` _path ` , ` _times ` to choose what to extract
66+ - ** Deploy a cache server** — separate read layer that receives push data from multiple airnodes
67+ - ** Extend with plugins** — hooks at every pipeline stage for custom logic
12268
123- ### Contract testing
69+ ## Routes
12470
125- ``` bash
126- bun run test:contracts # Unit + invariant tests
127- halmos --contract AirnodeVerifierSymbolicTest # Symbolic execution
128- halmos --contract AirnodeDataFeedSymbolicTest
129- bun run lint:slither # Static analysis
130- ```
71+ | Method | Path | Description |
72+ | ------ | ------------------------- | -------------------------------- |
73+ | ` POST ` | ` /endpoints/{endpointId} ` | Call an endpoint with parameters |
74+ | ` GET ` | ` /beacons/{beaconId} ` | Read latest push beacon data |
75+ | ` GET ` | ` /beacons ` | List all available beacons |
76+ | ` GET ` | ` /requests/{requestId} ` | Poll an async request for status |
77+ | ` GET ` | ` /health ` | Version and airnode address |
13178
13279## Configuration
13380
134- Config is YAML with 4 sections: ` version ` , ` server ` , ` settings ` , ` apis ` .
81+ YAML config with ` ${ENV_VAR} ` interpolation. Bun loads ` .env ` automatically .
13582
13683``` yaml
13784version : ' 1.0'
13885
13986server :
14087 port : 3000
141- rateLimit :
142- window : 60000
143- max : 100
14488
14589settings :
14690 proof : none
@@ -165,16 +109,94 @@ apis:
165109 type : int256
166110 path : $.bitcoin.usd
167111 times : ' 1e18'
112+ push :
113+ interval : 10000
114+ ` ` `
115+
116+ See [` examples/configs/complete/config.yaml`](examples/configs/complete/config.yaml) for auth methods, caching, push
117+ targets, multi-value encoding, and all available fields.
118+
119+ # # Contracts
120+
121+ Two Vyper 0.4+ contracts (EVM target : ` prague` ):
122+
123+ | Contract | Purpose |
124+ | -------------------- | ----------------------------------------------------- |
125+ | `AirnodeVerifier.vy` | Verify signature, prevent replay, forward to callback |
126+ | `AirnodeDataFeed.vy` | Verify signature, store latest value, serve reads |
127+
128+ Both verify `keccak256(encodePacked(endpointId, timestamp, data))` with EIP-191 personal sign. See
129+ [`contracts/README.md`](contracts/README.md) for integration examples.
130+
131+ # # Development
132+
133+ # ## Prerequisites
134+
135+ | Tool | Install |
136+ | ------------------------------------- | ----------------------------------------------------------- |
137+ | [Bun](https://bun.sh) | `curl -fsSL https://bun.sh/install \| bash` |
138+ | [Foundry](https://book.getfoundry.sh) | `curl -L https://foundry.paradigm.xyz \| bash && foundryup` |
139+ | [uv](https://docs.astral.sh/uv/) | `curl -LsSf https://astral.sh/uv/install.sh \| sh` |
140+
141+ Vyper, Slither, and Halmos are installed via uv :
142+
143+ ` ` ` bash
144+ uv tool install vyper
145+ uv tool install slither-analyzer
146+ uv tool install halmos
147+ ` ` `
148+
149+ # ## Scripts
150+
151+ | Script | Description |
152+ | -------------------------- | ---------------------------------------- |
153+ | `bun run dev` | Start the server with `--watch` |
154+ | `bun test` | Run unit tests (src/) |
155+ | `bun run test:integration` | Run integration tests (sequential) |
156+ | `bun run test:contracts` | Run contract tests (Foundry) |
157+ | `bun run fmt` | Format (Prettier) and lint-fix (ESLint) |
158+ | `bun run lint` | Check formatting and linting |
159+ | `bun run lint:slither` | Run Slither static analysis on contracts |
160+
161+ # ## Build
162+
163+ Compile to a standalone binary :
164+
165+ ` ` ` bash
166+ bun run build:osx # macOS ARM64
167+ bun run build:linux-x64 # Linux x86_64
168+
169+ ./dist/airnode start -c config.yaml
168170` ` `
169171
170- See [` examples/configs/complete/config.yaml`](examples/configs/complete/config.yaml) for a full reference. Secrets use
171- ` ${ENV_VAR}` interpolation — Bun loads `.env` automatically.
172+ # ## Project structure
173+
174+ ```
175+ src/
176+ cli/ CLI commands (start, cache-server, generate-key, etc.)
177+ config/ Zod schema, YAML parser, env interpolation
178+ api/ Upstream API calls and response processing
179+ server.ts Bun.serve HTTP server
180+ pipeline.ts Request pipeline (auth → validate → cache → API → encode → sign)
181+ cache-server.ts Standalone cache server for signed beacon data
182+ push.ts Background push loop with external targets
183+ auth.ts Authentication (free, apiKey, nftKey, x402)
184+ sign.ts EIP-191 signing and signature verification
185+ endpoint.ts Specification-bound endpoint ID derivation
186+ plugins.ts Plugin hooks and budget tracking
187+ contracts/ Vyper contracts and Foundry tests
188+ examples/
189+ configs/ Reference configs (complete, minimal, cache-server)
190+ plugins/ Example plugins (heartbeat, logger, slack-alerts)
191+ book/ Documentation site (Docusaurus)
192+ ```
172193
173194## Documentation
174195
196+ Full docs at the [documentation site](book/). Run locally:
197+
175198```bash
176- bun run book:start # Local dev server
177- bun run book:build # Production build
199+ bun run book:start
178200```
179201
180202## License
0 commit comments