Production Nostr relay for the ATTN Protocol (attention marketplace). This relay extends City Protocol Relay to add attention marketplace functionality.
City Protocol Relay (foundation)
└── ATTN Protocol Relay (extends City)
ATTN Relay inherits all validation from City Relay, which means it supports:
AuthHooks and ATTNHooks interfaces| Kind | Name | Description |
|---|---|---|
| 38188 | Marketplace | Marketplace configuration |
| 38288 | Billboard | Billboard service announcement |
| 38388 | Promotion | Promotion request with bid |
| 38488 | Attention | Viewer availability signal |
| 38588 | Billboard Confirmation | Billboard confirms display |
| 38688 | Attention Confirmation | Viewer confirms watching |
| 38788 | Marketplace Confirmation | Final confirmation |
| 38888 | Match | Promotion-attention match |
| 38988 | Attention Payment Confirmation | Payment receipt attestation |
| Kind | Name | Description |
|---|---|---|
| 38808 | Block | Bitcoin block arrival (foundational timing primitive) |
| 38818 | City | City identity and configuration |
| 38828 | Page View | Block-synchronized page tracking |
| 38838 | Analytics | Application-specific events |
| 38848 | Block Summary | Aggregated statistics for a block |
All 22+ supporting Nostr kinds from City Protocol are inherited, including:
# Clone the repository
git clone https://github.com/joinnextblock/attn-protocol.git
cd attn-protocol/packages/relay
# Build
go build -o relay ./cmd/relay
# Run
./relay
docker-compose up -d
| Variable | Default | Description |
|---|---|---|
RELAY_NAME |
ATTN Protocol Relay | Relay name (NIP-11) |
RELAY_DESCRIPTION |
Relay description | |
RELAY_PORT |
8008 | WebSocket port |
RELAY_DOMAIN |
localhost | Domain for NIP-42 validation |
STORAGE_TYPE |
sqlite | Storage backend type |
SQLITE_DB_PATH |
./relay.db | Path to SQLite database |
AUTH_PLUGIN |
none | Auth plugin to use |
LOG_LEVEL |
INFO | Log level (DEBUG, INFO, WARN, ERROR) |
attn-protocol/packages/relay/
├── cmd/relay/main.go # Relay entry point
├── pkg/
│ ├── validation/
│ │ └── validation.go # Routes ATTN → local, else → City Relay
│ ├── logger/ # Zerolog wrapper
│ └── ratelimit/ # Rate limiting
├── plugin/
│ ├── attn_hooks.go # ATTN Protocol lifecycle hooks
│ ├── auth_hooks.go # Authentication hooks
│ └── noauth.go # No-op implementations
└── internal/
├── config/ # Configuration loading
└── storage/ # Storage implementations
Event Received
│
▼
┌─────────────────────────────────┐
│ validation.ValidateEvent(event) │
└─────────────────────────────────┘
│
├── ATTN Protocol Kind (38188-38988)?
│ └── Route to ATTN validators (go-core)
│
└── City Protocol or Supporting Kind?
└── Delegate to City Protocol validation
type MyAuthHooks struct {
// Your auth fields
}
func (h *MyAuthHooks) OnConnection(stats rely.Stats, req *http.Request) error {
// Handle connection
}
func (h *MyAuthHooks) OnAuth(client rely.Client) error {
// Handle authentication
}
// ... implement other methods
type MyATTNHooks struct {
plugin.NoATTNHooks // Embed for default implementations
}
func (h *MyATTNHooks) AfterMatchEvent(ctx context.Context, event *nostr.Event) error {
// Trigger settlement logic when a match is created
return nil
}
func (h *MyATTNHooks) AfterPromotionEvent(ctx context.Context, event *nostr.Event) error {
// Notify billboard services of new promotion
return nil
}
Implement the Storage interface for any backend:
type Storage interface {
StoreEvent(ctx context.Context, event *nostr.Event) error
QueryEvents(ctx context.Context, filter *nostr.Filter) ([]*nostr.Event, error)
DeleteEvent(ctx context.Context, eventID string) error
}
This package imports validation from City Protocol Relay:
import city_validation "github.com/joinnextblock/city-protocol/relay/pkg/validation"
For local development, the go.mod includes replace directives:
replace (
github.com/joinnextblock/attn-protocol/go-core => ../go-core
github.com/joinnextblock/city-protocol/relay => ../../../protocol-city/packages/relay
github.com/joinnextblock/city-protocol/go-core => ../../../protocol-city/packages/go-core
)
MIT