Network

Users & Identity

An identity on Buzzer is a uid — a plain incrementing number (the first uid is 1). It is not an NFT and not an address; it is a durable account that one or more addresses act for. This indirection is the heart of the model: an address acts on behalf of a uid, it does not own one, so keys can be added, rotated and recovered without ever changing the identity.

Addresses and their roles

Every uid has exactly one custody address and any number of other addresses attached to it. What an address can do is decided by the roles it holds.

Role How many What it can do
Custody exactly one Full control. Implicitly holds every permission; can transfer or delete the profile, add and remove keys, set recovery and payout.
Recovery zero or one One power only: start a recovery to a new custody (7-day timelock). Exempt from the one-profile-per-address rule, so a single hardware wallet can guard many profiles.
Linked address any number An address granted a specific set of permission bits. One profile per address.

Permission bits

A linked address holds a 256-bit permission bitmap. Custody grants and revokes these freely; a linked key can never hold the full custody bit.

Bit Name Grants
0 VERIFIED "This wallet belongs to this profile" — login / attribution. No on-chain power by itself.
1 POST buzz, communityBuzz, deleteBuzz, registerMedia
2 REACT react (tips are pulled from the acting address)
3 GRAPH setRelationships, setMemberEdge
4 PROFILE setProfileData
5 COMMUNITY create communities and act as owner/admin/member
6 MESSAGE sendMessage (the on-chain messaging tier)
7–255 reserved —

Adding a key takes the address's consent: either addLink with an EIP-712 LinkConsent signed by that address (bound to the current custody, so a consent given to one owner can't be redeemed by the next), or a two-step proposeLink / acceptLink with a 7-day validity window. Any linked address can detach itself with unlinkSelf.

There is no hard cap on keys or communities per profile — the counters are uint24 (max 16,777,215 each), which is a storage width, not a policy limit.

Custody transfer & recovery

Both paths that change the custody key are two-step, so nothing can be forced onto an address:

  • Transfer — custody calls transferCustody, then the new address must acceptCustody. It must not already be linked elsewhere. Recovery, pending recovery and payout are cleared; existing linked keys are kept for the new owner to review.
  • Recovery — the recovery address calls startRecovery(newCustody), which sets a 7-day timelock. During the window custody can cancelRecovery and rotate the guardian (it sees the RecoveryStarted event). After the delay, the new custody itself calls executeRecovery. This protects a lost custody key, while the timelock protects against a stolen recovery key.

useNonce burns the caller's current EIP-712 nonce, invalidating any signed-but-unsubmitted Execute or LinkConsent message.

User names (handles)

A handle is one globally-unique name per uid — 1 to 20 characters, [a-z0-9] only, stored as a right-padded bytes32 (so it reads directly on-chain, no hash lookup).

  • setName (custody only) pays NAME_FEE by length and releases the old name immediately. A first name is never rate-limited; every later change is subject to a 30-day interval. clearName is free and respects the same interval.
  • Pricing rewards longer names: 1 char = 1 ETH, 2 = 0.1, 3 = 0.01, 4 = 0.001, 5–16 = 0.0001 ETH, 17–20 = free.
  • The name follows the uid through custody transfer and recovery, and is released on deleteProfile.

Community handles live in a separate namespace, so a user and a community may share the same name.

Profile data

Profile fields are an open map, key → value bytes, written with setProfileData (requires PROFILE). Keys are right-padded ASCII conventions — name, bio, pfp, cover — that the contract stores but never interprets. An empty value clears a key. Only ProfileDataSet(uid, key) is emitted; the value is read from storage.

Creating a profile

createProfile(recovery, name, referrerUid, keys[], values[]) mints the next uid, makes the caller the custody address, and optionally sets the name and initial profile data in one call. It costs PROFILE_FEE (0.0004 ETH) plus any name fee, paid exact-match and pushed instantly to the treasury. The referrerUid is emitted once in ProfileCreated and never stored — referral rewards are an off-chain concern that reads that event.

Genesis invite gate

A deploy-time option makes the first users invite-only. While active, plain createProfile reverts InviteRequired and users call createProfileInvited with a bearer invite code. The gate is driven by an immutable signer address and can only ever open, never re-close or re-key — it lifts forever once either 1,000 profiles exist or a fixed time window (20 days on mainnet) passes, whichever comes first. The time fallback means a lost signer key can never brick onboarding. address(0) disables the gate entirely (an open network from block zero). See the contract API for the full redemption flow.

Deleting a profile

deleteProfile (custody only) requires that all linked keys are removed and all communities transferred first, so nothing can act as a dead uid and no community handle is ever frozen. Custody, recovery and payout are zeroed and the name released.