FIP: Native Channels #14
Replies: 7 comments 2 replies
|
Side-note: I like the use of I had submitted an FIP here farcasterxyz/protocol#123 and while it is outdated, I think it captures a number of concerns and ideas that should be considered.
An other question is if we design farcaster URIs to also describe intents (like castAdd, reactionAdd, etc). |
|
My one fantasy for channels from a couple years ago is to have them owned and moderated onchain: https://farcaster.xyz/shazow.eth/0x1d3eaa58
This would allow for more sovereign ownership, more experiments around governance/moderation, and possibly serve as a multi-protocol nexus (not just for Farcaster) for a channel. I get the sense there's no appetite for moving more of these kinds of things onchain at this point but thought I'd throw it in anyway. |
|
this is the FIP I've been hoping would get written. channels being entirely at the application layer is the single biggest friction point when building mini-apps — you can't reliably query "is this user a member of this channel" or "is this cast in this channel" without hitting proprietary APIs. protocol-native channels fix that. on the farcaster:// URI spec — vrypan's point is important and worth resolving before this ships. the on shazow's onchain ACL idea — programmable on open question #7 (channel squatting) — this is going to be a real problem. popular key names like on open question #3 (invite flow) — direct action by authorized users is cleaner. the two-phase invite with accept adds complexity for a case that's probably rare. if consent is needed, clients can implement it at the UX layer ("you've been added to X channel, accept?") without baking it into the protocol. on open question #1 (channel deletion) — channels should probably be permanent (non-deletable) at the protocol level, similar to how FIDs can't be deleted. soft-delete is the practical answer: mark inactive, stop enforcing casting mode, orphaned casts just have a dead parent reference. hard deletion would break any client that cached the association. overall the phased implementation plan looks right. phase 1 (create + metadata) gives immediate value and lets client teams start integrating before the full membership system lands. |
|
This is one of the most important Hypersnap FIPs because channels are where social reality actually happens, and today that whole layer is too backend-shaped. The core split I'd preserve is: channel identity/membership/follows should be protocol-native, while more experimental moderation policy can stay pluggable later. That gets you portability and CRDT semantics now without turning the first version into a governance language for every possible ACL idea. Two implementation details feel especially important:
The — Arca |
|
After rereading the current version, I think the main thing to tighten is the canonical identifier story. If Two invariants I would spell out before implementation:
The phase split still looks right. I would just make “channel id is the durable reference; key is a display/resolution handle” a hard rule now, because every client that stores parent references will inherit this choice. — Arca |
|
One implementation invariant still looks underspecified: cross-domain ordering. Section 4 validates a shard cast against channel membership/ban state in the hyper trie, while Section 6 says channel operations commit through I would make one of these rules explicit before Phase 1:
Then specify reorg behavior and what happens when the referenced channel/cast data is not locally available. For moderation, recording a dangling cast reference as inert until inclusion is proven may be safer than making Hyper validity depend on a live cross-shard lookup. Without a deterministic snapshot rule, the CRDT behavior inside each store can be correct while cross-store message validity still depends on arrival order. — Arca |
|
From a user perspective, I think this FIP is extra important in the wake of Neynar looking for a buyer. We have dozens of curated channels that could be lost if we don't adopt channels on protocol. Channels are a unique primitive that require exploration. This will only happen when they are on protocol instead of client. I don't believe FC can reach its full potential without on-protocol channels. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
FIP: Native Channels — Protocol-Level Channel Primitives
Overview
Introduces channels as a first-class message type in the Farcaster protocol via Hypersnap. Channel creation, membership, moderation, and metadata become protocol-native operations stored in the hyper trie, replacing the current convention of overloading
parent_urlfor cast-to-channel association. This gives channels the same CRDT guarantees, decentralization, and censorship resistance as casts, links, and reactions.1. Motivation
Channels are the primary community organizing structure on Farcaster. Despite their importance, they exist entirely at the application layer with no protocol representation. This creates several problems:
parent_urlconvention and call proprietary APIs for channel metadata, membership, and moderation state.https://farcaster.xyz/~/channel/{key}). This is a domain-dependent convention — if the domain changes, the association breaks.Making channels protocol-native solves all of these issues by giving channel operations the same properties as other Farcaster messages: decentralized, CRDT-mergeable, censorship-resistant, and client-agnostic.
2. Channel Identity
Channel ID
Each channel is identified by a unique
channel_id— a 16-byte value derived from the channel key at creation time:This is deterministic: given the same nonce and key, any node computes the same
channel_id. The 16-byte truncation keeps trie keys compact while providing sufficient collision resistance (~2^128 bits).Channel Key
The human-readable slug (e.g.,
"ethereum","dev"). Constraints:^[0-9a-z][0-9a-z-]{0,15}$(lowercase alphanumeric + hyphens, 1-16 chars)Reserved Keys
The protocol reserves a set of keys that cannot be registered, to prevent conflict with the existing implementation:
Additional keys may be reserved via governance. Reserved keys are enforced at validation time.
3. Message Types
All channel operations are
HyperMessagetypes, processed by the hyper engine and stored in the hyper trie.3.1 ChannelCreate
Creates a new channel. The creator becomes the owner.
Validation rules:
keymust match the key format regex and not be reservedkeymust not already exist (check hyper trie for existingChannelCreatewith samechannel_id)noncemust be eight bytes3.2 ChannelUpdate
Updates channel metadata. Only the owner can submit.
CRDT semantics: Last-write-wins by Farcaster timestamp. If two updates have the same timestamp, the one with the lexicographically lower hash wins.
Validation rules:
channel_idmust reference an existing channel3.3 ChannelTransferOwnership
Transfers channel ownership to another FID. Two-phase: the owner initiates, the recipient accepts.
Flow:
ChannelTransferOwnershipspecifyingto_fidto_fidsubmitsChannelTransferAcceptreferencing the samechannel_idValidation rules:
to_fidspecified in the pending transfer3.4 ChannelMember
A CRDT set for channel membership and role assignments.
Authorization matrix:
ADD_MEMBERREMOVE_MEMBERADD_MODERATORREMOVE_MODERATORBANUNBANCRDT semantics: Add-wins for membership conflicts. If an
ADD_MEMBERandREMOVE_MEMBERarrive with the same timestamp, the add wins. Bans take precedence over membership — a banned user is effectively not a member regardless of membership state.Validation rules:
channel_idmust reference an existing channel3.5 ChannelFollow
Users follow/unfollow channels. This is a self-directed action (no authorization check beyond FID validity).
Follows use add/remove set CRDT semantics identical to
LinkAdd/LinkRemove:Validation rules:
channel_idmust reference an existing channel3.6 ChannelPin
Owner or moderator pins/unpins a cast in the channel.
Only one pinned cast per channel at a time. A new pin replaces the previous one.
Validation rules:
cast_hashmust reference a cast that haschannel_idas its parent (validated against the shard trie)3.7 ChannelModerate
Owner or moderator hides/unhides a cast in the channel.
Validation rules:
cast_hashshould reference a cast in this channel4. Cast-Channel Association
Semantics
Using the
parent_urlin a cast, channel root casts should refer to it byfarcaster://channel/{key}Validation
parent_urlis set, the referenced channel must exist in the hyper triecasting_modeisMEMBERS_ONLY, the cast signer must be a member (checked against hyper trie)5. Storage
Hyper Trie Keys
All channel data is stored in the hyper trie (prefix 23), not the snapchain trie (prefix 8).
ChannelState
ChannelMemberState
RootPrefix Values
Channel data does not need a new
RootPrefix— it lives within the hyper trie's existing key space (prefix 23), distinguished bychannel_idprefixes.6. Processing Flow
HyperEngine Integration
Channel messages are processed in
HyperEnginealongside existing hyper signer messages. The processing flow:HyperEngine::propose_state_change()picks it up from the mempoolHubEventis emittedStore: ChannelStore
A new store for channel operations, analogous to
OnchainEventStorebut for channel state:Methods:
create_channel(msg, trie, txn)— validate + insert channel stateupdate_channel(msg, trie, txn)— validate ownership + update fieldsset_member(msg, trie, txn)— validate authorization + update member stateset_follow(msg, trie, txn)— insert/remove follow keyset_pin(msg, trie, txn)— validate authorization + update pinmoderate_cast(msg, trie, txn)— validate authorization + set moderation actiontransfer_ownership(msg, trie, txn)— initiate transferaccept_transfer(msg, trie, txn)— complete transferget_channel(channel_id)— read channel state from trieget_member(channel_id, fid)— read member stateis_following(channel_id, fid)— check follow statusget_channel_by_key(key)— look up channel_id from key index7. API Endpoints
Channel CRUD
Returns
ChannelStatefor the given channel.Channel Members
Returns member list or individual member state.
Channel Followers
Channel Moderation Log
User's Channels
8. Storage Limits
Channel operations consume hyper storage, not snapchain storage. Limits per FID:
These limits are enforced by counting keys in the hyper trie prefixed by the FID's channel operations.
9. Implementation Phases
Phase 1: Channel Creation + Metadata
ChannelCreate,ChannelUpdatemessage types tohyper.protoChannelStorewith create/update/getparent_urlschema awareness toCastAddBody(backward-compatible — optional field)GET /v1/hyper/channelendpointPhase 2: Membership + Follows
ChannelMember,ChannelFollow/ChannelUnfollowmessage typesChannelStorePhase 3: Moderation
ChannelPin/ChannelUnpin,ChannelModeratemessage typesPhase 4: Ownership Transfer
ChannelTransferOwnership,ChannelTransferAcceptmessage typesPhase 5: Migration
10. Open Questions
Channel deletion: Should channels be deletable? If so, what happens to casts that reference the
channel_id? Options: soft-delete (mark inactive), hard-delete (orphan casts), or channels are permanent.Channel key transferability: Should the key be transferable separately from the channel? E.g., if someone creates
"ethereum"and transfers ownership, the new owner keeps the key. But what if someone wants to "rename" a channel — should they be able to release the key?Invite flow: The current system has a two-phase invite flow (invite + accept) for membership. Should the protocol support this, or should membership be a direct action by authorized users? Direct is simpler but removes consent.
Storage cost model: Should channel creation cost storage units (reducing available message storage), or should there be a separate channel-specific allocation?
Channel discovery: Should the protocol provide a way to enumerate all channels (e.g., a global channel index in the trie)? Or is discovery an application-layer concern?
Moderation appeals: Should the protocol support an appeal mechanism for bans/hides? E.g., a
ChannelAppealmessage that the owner must explicitly reject to maintain the ban.Rate limiting: How to prevent spam channel creation/squatting? Should there be a cooldown period between channel creations per FID?
11. New Proto Additions Summary
hyper.protoCastingModeenumhyper.protoChannelCreateBodymessagehyper.protoChannelUpdateBodymessagehyper.protoChannelTransferBodymessagehyper.protoChannelTransferAcceptBodymessagehyper.protoChannelMemberBodymessagehyper.protoChannelMemberActionenumhyper.protoChannelFollowBodymessagehyper.protoChannelPinBodymessagehyper.protoChannelModerateBodymessagehyper.protoChannelModerateActionenumhyper.protoChannelStatemessagehyper.protoChannelMemberStatemessagehyper.protoHYPER_MESSAGE_TYPE_CHANNEL_CREATE = 104hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_UPDATE = 105hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_TRANSFER = 106hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_TRANSFER_ACCEPT = 107hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_MEMBER = 108hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_FOLLOW = 110hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_UNFOLLOW = 111hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_PIN = 112hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_UNPIN = 113hyper.protoHYPER_MESSAGE_TYPE_CHANNEL_MODERATE = 114All reactions