Skip to main content

Public social recipients

A social-account escrow hides which account a coin's fees are for. Some creators want the opposite: a coin that openly says "fees go to @alice", so traders can check it. A public social recipient does exactly that. The account is public and verifiable, but the wallet that finally receives the money stays hidden from traders, from the creator and from the platform.

Stealth claim kitPrivate social escrowPublic social recipient
Who the fees are forHiddenHidden from the chain (attestors know)Public and verifiable
The recipient's walletHiddenHiddenHidden
One account across coinsNo (one key per coin)No (one escrow per coin)Yes: every coin naming @alice shares one account
Per-account totalsNoneNonePublic
How the recipient claimsClaim linkSocial login and bindSocial login and bind
ExitDirect or shieldedDirect or shieldedShielded only (Railgun)

How it works​

It is the same KIND_HANDLE FeeVault account as a private escrow, with two differences:

  • Deterministic commitment. The commitment's salt and nonce are fixed protocol constants instead of a secret salt and a random nonce: handleCommitment = keccak256(abi.encode(platformId, keccak256(userId), PUBLIC_HANDLE_SALT, PUBLIC_HANDLE_NONCE)). The beneficiary id therefore depends only on the account and the fallback, so anyone can recompute "@alice's account" (publicHandleId in the SDK). Every coin naming her pays into the same id.
  • Public hint. The launch's beneficiaryHint is plaintext rather than encrypted. It holds the platform, the numeric user id, the display handle and an attestor's EIP-712 signature over that label (PublicHandle(platformId, userId, handle, issuedAt)). The id commits only to the numeric id. The signature stops a creator from pairing someone's id with another person's @handle.

The label needs a handle lookup, so POST /v1/public-handle is paid with x402 exactly like a handle commitment: same price and the same generic payment description. A public label's payment therefore looks like any other lookup.

No contract changes are involved. Registration, bind, timelock, veto, fallback, consolidation and shield templates all work as for any handle escrow.

Claiming without revealing the wallet​

  1. Bind. The account owner logs in through the bind portal, and the browser makes a fresh stealth key. Attestors sign BindOwner for that key, and the timelock runs as usual. The key is public in BindProposed and therefore tied to the handle. It never holds funds and never sends a transaction; it only signs.
  2. Exit. Relayers and the web app only offer consolidate to USDT, then shield to Railgun. A direct claim to an address would publish the wallet behind a public name, so the relayer refuses it. The person's 0zk address and everything after the shield stay hidden.

Because exits must go through consolidation, public-recipient coins credit fees in the paired (quote) token only (FEE_IN.Paired).

Keeping private escrows private​

The same person may also have private escrows from other coins. Those must never be linked to the public account, so:

  • Public totals use the public id only. Private escrows have a random nonce, so their ids can never equal, or be derived from, the public id.
  • Separate binds with separate keys. Attestors refuse a bind request that mixes public and private escrows. They also refuse a stealth key that was already used for the other kind. The bind portal therefore binds them in two passes, each with its own fresh key and login. Otherwise one newOwner appearing in both BindProposed events would tie the private escrows to the handle.
  • Timing still leaks. Binding both kinds in the same minute lets an observer guess they belong together. Space them out.

Limits you should know about​

  • Naming is not endorsement. Anyone can launch a coin naming @alice. Until she binds, the token page says she has not claimed or endorsed it.
  • The handle-to-id label is attested, not proven. It is an attestor's signature from launch time. The id itself commits to the immutable numeric id, so a later handle change or resale cannot redirect funds.
  • Direct exits are refused by the relayer and the UI, not by the contract. An owner who self-submits a direct claim can still do it, and publishes their own wallet by doing so.
  • The platform learns nothing extra. Attestors see the user id and the stealth key, but in this mode both are already public. They never see the Railgun address.
  • Attestors must be live. Like private escrows, binding needs attestorThreshold attestors on the FeeVault. Until they are configured, fees can only leave through the fallback.