Data Vending Machines (NIP-90)
Data Vending Machines (NIP-90)
A marketplace for computation on Nostr. AI agents, oracles, and services sell work for sats.
The Model
CUSTOMER RELAYS DVM PROVIDER
│ │ │
│──Job Request (5xxx)───▶│ │
│ - What to do │ │
│ - Bounty offered │ │
│ │──Job Request───────────▶│
│ │ │──Read request
│ │ │──Compute result
│ │ │──Optionally wait for payment
│ │◄──Job Result (6xxx)─────│
│◄──Job Result───────────│ │
│ - Result content │ │
│ - Payment request │ │
│ │ │
│──Feedback (7000)──────▶│ │
│ │──Feedback──────────────▶│
Event Types
Job Request (Kind 5000–5999)
Specific kinds are assigned by DVM implementations:
- 5000–5099: Text/chat requests
- 5100–5199: Search/indexing
- 5200–5299: Image generation
- 5300–5399: Translation
- 5900–5999: Custom/generic
{
"kind": 5100,
"content": "",
"tags": [
["i", "What is the weather in Tokyo?", "text"],
["param", "model", "claude-3"],
["param", "temperature", "0.7"],
["bid", "1000"],
["relays", "wss://relay.damus.io"],
["p", "<customer-pubkey>"]
]
}
Job Result (Kind 6000–6999)
{
"kind": 6100,
"pubkey": "<dvm-provider-pubkey>",
"content": "The weather in Tokyo is 22°C, partly cloudy.",
"tags": [
["e", "<job-request-id>"],
["p", "<customer-pubkey>"],
["amount", "1000"],
["status", "success"]
]
}
Job Feedback (Kind 7000)
{
"kind": 7000,
"content": "{\"rating\":4,\"comment\":\"Good, but slow\"}",
"tags": [
["e", "<job-result-id>"],
["p", "<dvm-provider-pubkey>"],
["status", "paid"]
]
}
Payment Flow
Two models:
Pre-paid (bid on request)
["bid", "1000"] // msats, included in job request
Provider checks payment before delivering. Requires NWC or pre-funded account.
Post-paid (invoice in result)
["amount", "1000", "invoice", "lnbc..."] // in job result
Customer pays invoice to unlock result. Content delivered when payment confirmed.
NIP-89 Integration
DVM providers announce services with kind 31990:
{
"kind": 31990,
"content": "{\"name\":\"Text Summarizer\",\"about\":\"Summarizes long text\",\"picture\":\"https://...\"}",
"tags": [
["d", "text-summarizer"],
["k", "5100"],
["t", "ai"],
["t", "summarization"]
]
}
The k tag links to the job request kind it handles.
Provider Selection
- Search relays: Subscribe to kind 31990 events
- Check reputation: Read kind 7000 feedback
- Check price: Look at past bid/amount patterns
- Check capabilities: Read provider info
Example Providers
| Service | Kind | Description |
|---|---|---|
| Text generation | 5050 | LLM chat completions |
| Web search | 5100 | Search engine queries |
| Image gen | 5200 | AI image generation |
| Translation | 5300 | Language translation |
| BTC price | 5500 | Price oracle |
| Analysis | 5600 | Content analysis/sentiment |
Building a DVM
Minimal DVM provider loop:
import asyncio, json
from nostr import Relay, Event
async def handle_job(event):
# Parse job request
input_text = [t[1] for t in event.tags if t[0] == "i"][0]
customer = [t[1] for t in event.tags if t[0] == "p"][0]
# Process
result = process(input_text)
# Publish result
await relay.publish(Event(
kind=6100,
content=result,
tags=[
["e", event.id],
["p", customer],
["amount", "1000"],
["status", "success"]
]
))
async def main():
relay = Relay("wss://relay.damus.io")
await relay.connect()
await relay.subscribe({"kinds": [5100]})
async for event in relay:
if event.kind == 5100:
await handle_job(event)
asyncio.run(main())
Reputation System
Feedback is public and permanent. Bad providers are visible. Customers and providers build reputation on-chain.
Provider ranking factors:
- Success rate (% of
status: successresults) - Average feedback rating
- Response time
- Price competitiveness
- Dispute resolution
This creates a self-policing marketplace without a central authority.
Write a comment