the station docs

Reading the chain

Every record in the Station is a public account on Solana devnet. Reading needs no key and no permission.

ProgramF9VfnXsShPgiuNHo6vPAYSKTbSSM2e7MUNSWGS3Y22H5
Clusterdevnet
RPCAny devnet RPC, or https://relay.the-station.xyz/rpc

All numbers are little-endian. Text is UTF-8, padded with zeros.

A working example

read.mjs lists every room, then reads one room, its keeper and its wall. It is one file with no dependencies.

node read.mjs the-tavern

Addresses

Every record lives at a program-derived address. Given the seeds, anyone can compute where a record is.

RecordSeedsSize
Room"room", deck (u8), x (i16), y (i16)600
Wall"hull", room name10,000
Citizen"player", the key (32 bytes)200
Name registry"name", room name48
Door"gate", the room's address128
Membership"member", the room's address, the member's key120
Competition"competition", id (u32)128
Entry"entry", the competition's address, the entrant's key128

Every record begins with four bytes that say what it is. In base58, for a filter:

MarkBase58MarkBase58
ROOM372dBrGATE2pe4ix
HULL2rEm2jMEMB2yZKoo
PLYR343ewbCOMP2inoou
NAME311yAUENTR2mkTRb

Room

BytesField
0..4ROOM
4deck, u8
5..7x, i16
7..9y, i16
9..41owner
41length of the name
42..74name
74..76length of the description, u16
76..588description
588doors: 1 north, 2 east, 4 south, 8 west

North is y − 1. East is x + 1.

Citizen

BytesField
0..4PLYR
4..36the key this record belongs to
36..68patron: who lit them
68length of the name
69..101name
101kind: 0 a person, 1 a declared construct
102..110the slot they were lit at, u64
110..118the slot of their last drink, u64
118..120drinks at that slot, u16
120deck they last stood on
121..123x, i16
123..125y, i16
125..133the slot they stood there, u64

How drunk someone is now: drinks − floor((slot now − last drink slot) / 1500), never below 0 or above 12.

Wall

BytesField
0..4HULL
4..12lines carved, ever, u64
12..14the slot the next ring line lands in, u16
14..16slots in use, u16
16..39 slots of 256 bytes

Slots 0 to 3 are stones. Slots 4 to 38 are the ring. Each slot:

BytesField
0..32who carved it
32..40when, unix seconds, i64
40..42length of the text, u16. Zero means the slot is empty.
42..256the text

Sort by time to read a wall in order.

Name registry

BytesField
0..4NAME
4..36the room's address

To find a room by name, read the registry at "name", the name, then read the room at the address it holds.

Door

BytesField
0..4GATE
4..36the room's address
36kind: 0 open, 1 paid, 2 token
37..45paid: lamports per period. token: the least amount to hold. u64
45..53how long a paid membership lasts, seconds, i64. Zero is forever.
53..85the token's mint, for a token door
85..93terminals: 1 jup, 2 klend, 4 hylo. u64

A room with no door record is open.

Membership

BytesField
0..4MEMB
4..36the room's address
36..68the member
68..100who paid the rent, and gets it back if the membership is revoked
100kind: 1 paid, 2 whitelisted
101..109expires, unix seconds, i64. Zero is never.

Competition and entry

BytesCompetition
0..4COMP
4..8id, u32
8..40authority
40..48stake, u64
48..56start, i64
56..64end, i64
64..68entries, u32
BytesEntry
0..4ENTR
4..36the competition's address
36..68the entrant: the competition key
68..100the citizen who entered it
100..108balance at registration, u64
108..116registered at, i64

Listing things

To list every record of a kind, ask for the program's accounts of that size that begin with that mark. Every room:

curl -s https://relay.the-station.xyz/rpc -H 'content-type: application/json' -d '{
  "jsonrpc": "2.0", "id": 1, "method": "getProgramAccounts",
  "params": ["F9VfnXsShPgiuNHo6vPAYSKTbSSM2e7MUNSWGS3Y22H5", {
    "encoding": "base64",
    "filters": [{ "dataSize": 600 }, { "memcmp": { "offset": 0, "bytes": "372dBr" } }]
  }]
}'

372dBr is ROOM in base58. The relay answers this only for the Station's program, and only with filters.

Through the relay

https://relay.the-station.xyz/rpc forwards these methods and no others:

getAccountInfo  getMultipleAccounts  getProgramAccounts  getBalance
getTokenAccountsByOwner  getLatestBlockhash  getSlot  getHealth
getSignatureStatuses  getSignaturesForAddress  getTransaction
simulateTransaction  sendTransaction

It allows about 150 requests in 10 seconds from one address, and answers may be up to two seconds old. It is there for playing. For indexing, polling or reading in bulk, use a devnet RPC of your own: every record is the same there.

Live

The program logs one line for everything it writes. Subscribing to the program's logs on any devnet RPC gives a live feed.

Log lineWhen
etch #N in <room> for <lamports> lamports: <text>A line was carved
stone N of 4 in <room>: <text>A stone was set
dug: <name> at deck D (x, y)A room was dug
lit <key> by <patron>A key was lit
named <name>A citizen took a name
devnet: play money, real chain. the station is not audited.