Graph

graph.cash is a GraphQL indexer for the Memo network. It exposes posts, profiles, transactions, blocks, and SLP token data through queries and live subscriptions.


Endpoint

The endpoint accepts POST for queries and mutations, and a WebSocket upgrade for subscriptions.

HTTP

https://graph.cash/graphql

WebSocket

wss://graph.cash/graphql

Subscriptions follow the graphql-transport-ws protocol. A live playground with introspection is available for development.


Schema

Top-level types and the operations that return them.

type Query {
    tx(hash: Hash!): Tx
    txs(hashes: [Hash!]): [Tx]
    address(address: Address!): Lock
    addresses(addresses: [Address!]): [Lock]
    block(hash: Hash!): Block
    block_by_height(height: Int!): Block
    block_newest: Block
    blocks(newest: Boolean, start: Uint32): [Block!]
    profiles(addresses: [Address!]): [Profile]
    posts(txHashes: [Hash!]): [Post]
    posts_newest(start: Date, tx: Hash, limit: Uint32): [Post]
    room(name: String!): Room!
}

type Subscription {
    tx(hash: Hash!): Tx
    address(address: Address!): Tx
    addresses(addresses: [Address!]): Tx
    blocks: Block
    posts(hashes: [Hash!]): Post
    profiles(addresses: [Address!]): Profile
    rooms(names: [String!]): Post
    room_follows(addresses: [Address!]): RoomFollow
}

type Mutation {
    broadcast(raw: String!): Boolean!
}

Selected object types most relevant for building feeds and profile views:

type Post {
    tx_hash: Hash!
    address: Address!
    text: String!
    tx: Tx!
    lock: Lock!
    likes: [Like!]
    parent: Post
    replies: [Post!]
    room: Room
}

type Profile {
    address: Address!
    lock: Lock!
    name: SetName
    profile: SetProfile
    pic: SetPic
    following(start: Date): [Follow]
    followers(start: Date): [Follow]
    posts(start: Date, newest: Boolean): [Post]
    rooms(start: Date): [RoomFollow!]
}

type Lock {
    address: Address
    profile: Profile
    txs(start: Date, tx: Hash, limit: Uint32): [Tx!]
}

type Tx {
    hash: Hash!
    raw: Bytes!
    inputs: [TxInput!]!
    outputs: [TxOutput!]!
    blocks: [TxBlock]
    seen: Date
    version: Int32!
    locktime: Uint32!
}

type Room {
    name: String!
    posts(start: Int): [Post!]
    followers(start: Int): [RoomFollow!]
}

Queries

Newest posts

Page through recent posts. Pass tx with the oldest post's hash from the previous page to paginate.

query Newest($limit: Uint32) {
  posts_newest(limit: $limit) {
    tx_hash
    text
    address
    tx { seen }
    lock { profile { name { name } } }
    room { name }
  }
}

Single post and replies

query Post($hash: Hash!) {
  posts(txHashes: [$hash]) {
    tx_hash
    text
    address
    likes { address tip }
    replies {
      tx_hash
      text
      address
    }
  }
}

Profile with recent posts

query Profile($address: Address!) {
  profiles(addresses: [$address]) {
    address
    name { name }
    profile { text }
    pic { pic }
    posts(newest: true) {
      tx_hash
      text
      tx { seen }
    }
  }
}

Address transactions

query AddressTxs($address: Address!) {
  address(address: $address) {
    txs(limit: 25) {
      hash
      seen
      outputs { amount lock { address } }
    }
  }
}

Calling from JavaScript

async function graphql(query, variables) {
    const res = await fetch("https://graph.cash/graphql", {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify({query, variables})
    });
    const json = await res.json();
    if (json.errors) {
        console.error(json.errors);
    }
    return json.data;
}

Subscriptions

Subscriptions stream new events as they are indexed. Pass an empty list to posts(hashes: []) to receive every new post on the network; pass specific hashes to receive replies and likes for those posts.

All new posts

subscription {
  posts(hashes: []) {
    tx_hash
    text
    address
    tx { seen }
    lock { profile { name { name } } }
    room { name }
  }
}

Replies and likes for specific posts

subscription Watch($hashes: [Hash!]) {
  posts(hashes: $hashes) {
    tx_hash
    text
    parent { tx_hash }
    likes { address tip }
  }
}

Address activity

subscription Activity($address: Address!) {
  address(address: $address) {
    hash
    seen
  }
}

New blocks

subscription {
  blocks {
    hash
    height
    timestamp
  }
}

Connecting from JavaScript

Subscriptions use the graphql-transport-ws sub-protocol over a WebSocket. The minimum handshake is connection_initconnection_ack, then subscribe for each subscription, and next messages stream back.

const ws = new WebSocket("wss://graph.cash/graphql", "graphql-transport-ws");

ws.onopen = () => {
    ws.send(JSON.stringify({type: "connection_init"}));
};

ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    if (msg.type === "connection_ack") {
        ws.send(JSON.stringify({
            id: "1",
            type: "subscribe",
            payload: {
                query: "subscription { posts(hashes: []) { tx_hash text address } }"
            }
        }));
    } else if (msg.type === "next") {
        console.log("new post", msg.payload.data.posts);
    } else if (msg.type === "ping") {
        ws.send(JSON.stringify({type: "pong"}));
    }
};

Mutations

The graph supports broadcasting raw transactions. Sign the transaction client-side (for example with JMemo) and submit the hex-encoded raw transaction:

mutation Broadcast($raw: String!) {
  broadcast(raw: $raw)
}

Scalars

  • Hash — 32-byte transaction or block hash, hex-encoded.
  • Address — Bitcoin Cash address (legacy 1... form).
  • Bytes — arbitrary byte sequence, hex-encoded.
  • Date — RFC 3339 timestamp.
  • Int32, Int64, Uint8, Uint32, Uint64 — sized integers.
  • HashIndex — transaction hash + output index pair.

Live example

See the posts feed example for a self-contained page that renders the live posts subscription and paginates with posts_newest.