Graphs
The social graph is a set of directed, per-user relationships stored on-chain — one of the few things the contract keeps in state, because the graph must be authoritative and queryable. Unlike posts and reactions (which are events only), a relationship is durable storage you can read directly.
A relationship is a bitmap
mapping(uint256 uid => mapping(uint256 target => bytes32)) relationships;
Each (uid → target) edge holds a bytes32 — a 256-bit bitmap. The contract stores it
and never interprets it. Bit meanings are a client/registry convention. A single edge
can carry many relationships at once, because they are just different bits set in the same
word.
Suggested low bits (a convention, not enforced): bit 0 = follow, bit 1 = block, bit 2 = mute, and so on, with higher ranges reserved for community-registered and private-use meanings. Because it is 256 bits, one edge expresses up to 256 distinct kinds of relationship simultaneously — not just a single "follow."
Writing the graph
setRelationships(uid, uint256[] targets, bytes32[] values) // requires GRAPH
Setting an edge requires the GRAPH permission on the acting uid. It is batch-only —
you pass parallel arrays of targets and values. Each pair emits one event:
RelationshipSet(uint256 indexed uid, uint256 indexed target, bytes32 value)
The contract does not check that target exists (that would cost gas for no safety
gain), so you can express a relationship to any uid, and clients validate as needed.
Graph types
Because the edge is an open bitmap, the "graph" is really many overlaid graphs sharing one storage map — a follow graph, a block graph, a mute graph, a labels graph — each just a different bit. Clients read the bits they care about and ignore the rest. New graph types are added by agreeing on a new bit in the convention layer, never by changing the contract.
The community membership graph (a member's standing in a community, and the member's own edge back to it) works the same way — see Communities.