Posts (Buzz)
A post is called a buzz. Posting is intentionally the cheapest thing the network
does: there is no per-post storage — a buzz is one increment of a global counter
(bidCounter, first bid = 1) plus a single event. Ownership, threading, and content
are all reconstructed by indexers from the log. Deleting a post that isn't yours is a
no-op that indexers ignore.
Everything is an event
buzz(uid, BuzzInput[]) emits one Buzzed event per item and returns the created bids,
so an integrating contract can compose on the result. There is no bidOwner slot, no
reply table, and no reaction counter in state — dropping ~20k gas of storage per post is
exactly why this is affordable.
Buzzed(uint256 indexed uid, uint256 indexed bid, uint256 indexed parentBid,
bytes32 postType, bytes32[] content, uint256[] taggedUsers, bytes32[] settings)
BuzzDeleted(uint256 indexed uid, uint256 indexed bid)
The API is batch-only: you always pass an array of BuzzInput. A dedicated
single-post function would save only ~1k gas, not worth a second code path.
Every action takes the acting uid explicitly, and the contract checks
permissions[uid][actor]. Passing a uid you don't hold POST for simply reverts — an
address acts for a uid, it never implicitly owns one.
Post types
postType is a bytes32 that is self-describing — it carries its own meaning as
right-padded ASCII, with no registry and no numeric IDs:
- The empty word (
0x0) is a plaintext post:parentBid == 0is an original, any otherparentBidis a reply. - Every other value is an ASCII tag —
bytes32("repost"),bytes32("quote"),bytes32("poll"),bytes32("article"), and so on.
The contract does not validate postType or parentBid; clients decide what to
render and what to filter. New post types are therefore a client convention, never a
contract change — this is how a single immutable contract supports an open-ended and
growing catalog of content formats.
Content
content is an opaque bytes32[]. It can be raw text chunks packed into words, an IPFS
CID, an Arweave id, an encrypted envelope, or anything else. How to decode it is signalled
by the settings word, so a client reads settings first and interprets content
accordingly. taggedUsers is a parallel list of uids mentioned in the post.
Content settings
settings is a bytes32[] of self-describing flags travelling with the post — encoding
scheme, content type, visibility hints, and other client conventions. Like post types,
these bits are meaning agreed between clients, not interpreted by the contract. Keeping
encoding out of the contract is what lets content formats evolve without redeploying.
Reactions
Reactions are not stored on-chain either — react emits an event and, optionally,
moves an ERC-20 tip in the same call. It is batch-only and requires the REACT
permission.
Reacted(uint256 indexed uid, uint256 indexed bid, uint256 reactionType,
address token, uint256 amount, uint256 toUid, address to)
reactionType0–15 are the reserved core set (0 = none / remove); values ≥ 1024 are client-defined. Not validated.- A tip is the reactor's own money and carries no protocol cut — the full amount is
sent to the recipient's payout address via
transferFrom. The recipient uid and resolved address are in the event so indexers can attribute tips without trusting the client. - The token must be a real contract (codeless addresses revert), so a
Reactedevent can never fabricate a tip against an EOA. A malicious token can still lie, so indexers should verify tip amounts against the token's ownTransferlogs before displaying them. - If the recipient's payout resolves to
address(0)the tip reverts — tokens are never burned or partially moved.
Media
Buzzes reference media by a fileId registered separately, so images and files are not
inlined into post content. See Media for the file registry.