All BSIPs
.md

BSIP-13

Interim .bso Name Registry

An ownerless Ethereum mainnet registry for .bso names, how it launches from names already in use, and how it moves to Bitsocial Chain.

draftAppchain
On this page

Abstract

This BSIP moves .bso names off ENS and into a registry of their own: an ownerless, non-upgradeable contract on Ethereum mainnet, forked from the .gwei Name Service (GNS). Names are ERC-721 tokens that expire, are registered by commit-reveal at fixed length-based prices, and carry ENS-style text records, so the bitsocial record of BSIP-10 does not change. Fees go to a hardcoded multisig that funds Bitsocial development. The multisig can only collect those fees and start a one-time sunset. It cannot change prices, and over names it has only the rights any account has. At launch, every .bso name in use through ENS at a snapshot block, subdomains included, is copied into the registry with the same owner and record, as long as the registry accepts its label and its entry is seeded before public registration opens. Anyone can seed an entry, and the maintainers must seed them all. Names that come into use later are not copied. The registry is temporary: when Bitsocial Chain launches, the Ethereum registry freezes and its unexpired names are copied onto the chain. This BSIP replaces steps 2–4 of BSIP-10’s .bso resolution and narrows BSIP-10’s .bso/.eth equivalence.

Motivation

Today .bso is an alias: memes.bso is resolved as memes.eth (BSIP-10). Every .bso name is therefore an ENS name, bought at ENS prices and on ENS terms. In October 2026 a maintainer was quoted more than $20 for three years for a new community name under ENS v2. Most owners will not pay that to try out a community, so they run key-only communities, which are harder to find and cannot recover from a key compromise (BSIP-10).

Bitsocial Chain, phase 2 of the Bitsocial master plan, is meant to host .bso names natively, but it does not exist yet. An interim registry on Ethereum mainnet makes a normal-length .bso name cost 0.0005 ETH a year now, and makes the later move to Bitsocial Chain a copy of state rather than a change of owners.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Terminology

  • Registry: the contract defined in Registry contract.
  • Fee recipient: the multisig address hardcoded in the registry (Fee recipient).
  • Seed list: the names copied into the registry at launch (Launch).
  • Activation: the point at which a client starts resolving .bso names through the registry (Resolving .bso names).

Deployment parameters

ParameterValue
ChainEthereum mainnet (chain ID 1)
Registry addressTBD at deployment
Upstreamlucadonnoh/gwei-names src/NameNFT.sol at commit 8e094ab343d0bfdbd9ec948594fc48f20bed6e5d
TLD nodenamehash("bso") = 0xe07ef0fd54600878e8c5c0087ff379e0fb9e1c49dfcc763bdada48721f534a20
Fee recipientSafe multisig, address TBD
Fee recipient signers and thresholdTBD (Fee recipient)
Snapshot block STBD, shortly before deployment
Seed period7 days from deployment, ending at SEED_END
Transition windowuntil TRANSITION_END = SEED_END + 90 days
Sunset notice30 days

Every TBD value MUST be filled in before this BSIP moves to Review, and the registry address MUST be added once the registry is deployed.

Registry contract

The registry is the upstream NameNFT with these changes and no others:

  1. TLD. The root node is namehash("bso"), and full names end in .bso. The ERC-721 name() is Bitsocial Names and symbol() is BSONAME. The symbol MUST NOT be BSO, which is the Bitsocial token’s.
  2. Fees are collected, not locked. Registration fees, renewal fees, and expiry premiums accumulate in the registry as they do upstream. A new function withdraw(), callable by anyone, transfers the registry’s entire ETH balance to FEE_RECIPIENT, a constant address. Apart from upstream’s refunds of overpayment, no other code path sends ETH.
  3. Seeding. A constant SEED_ROOT, a constant SEED_END = deployment time + 7 days, and a function seed (Seeding). Before SEED_END, reveal reverts.
  4. Sunset. A function sunset() that freezes the registry after a notice period (Sunset and migration).

Nothing else from the upstream repository is deployed: not SubdomainRegistrar, GnsUniversalResolver, HumanRegistrar, GnsPosts, or GnsIntegrationVoting.

The rest of the contract is unchanged, and clients rely on it:

  • A name is an ERC-721 token whose ID is uint256(namehash(name)) (EIP-137).
  • A label is 1 to 255 UTF-8 bytes. The registry lowercases ASCII letters and rejects control characters, space, ., DEL, invalid UTF-8, and a leading or trailing -. It does not apply Unicode normalization (ENSIP-15); clients do.
  • A top-level name is registered by commit-reveal, with 60 seconds to 24 hours between commit and reveal, for 365 days. Anyone may renew any top-level name, for 365 days counted from its current expiry.
  • After expiry a name has a 90-day grace period. During it the name can be renewed, but it does not resolve, cannot be transferred, and its records cannot be changed. After the grace period anyone may register it, paying a premium that starts at 100 ETH and falls linearly to zero over 21 days. Re-registration clears all records.
  • Subdomains are free, have no expiry of their own, and are active only while their parent is active and has not reclaimed them.
  • text(bytes32 node, string key) returns a name’s text record, or the empty string when the name is not active.

The registry has no owner, admin, proxy, pause, or upgrade path. Prices, FEE_RECIPIENT, SEED_ROOT, SEED_END, and every period above are constants.

Prices

Unchanged from upstream:

Label length (UTF-8 bytes)Price per 365 days
10.5 ETH
20.1 ETH
30.05 ETH
40.01 ETH
5 or more0.0005 ETH

Registration and renewal cost the same. Gas is paid separately to Ethereum.

Fee recipient

FEE_RECIPIENT is a Safe multisig on Ethereum mainnet controlled by the Bitsocial maintainers. Fees fund their development of Bitsocial while the registry is in use.

The fee recipient’s only powers over the registry are:

  1. receiving fees through withdraw(); and
  2. calling sunset(), once.

It cannot change prices, periods, or the seed list, and it cannot stop withdraw(). Over names it has no power beyond what any account has: like anyone, it can register an available name by commit-reveal and renew any top-level name, but it cannot transfer or edit a name it does not own. It holds the reserved names assigned to it (Seed list) as an ordinary owner.

Safe signers can be added, removed, or replaced without changing the Safe’s address, so the registry does not depend on any one signer. Signers:

SignerKeys
Tommaso Casaburi (@tomcasaburi)2
Rinse (@Rinse12)2
TBDTBD

Threshold: TBD. The signer set and threshold MUST satisfy both rules:

  • the threshold is higher than the number of keys held by any one person, so nobody acts alone; and
  • if any one person becomes unavailable, the keys held by everyone else still reach the threshold.

Two people with two keys each and a 3-of-4 threshold meet the first rule but not the second.

Any change to the signers or the threshold MUST be recorded in this BSIP.

Launch

Seed list

The seed list is a set of entries (label, parent, owner, record), fixed before deployment. parent is 0 for a top-level name, and for a subdomain it is uint256(namehash(p)), where p is the subdomain’s parent name in .bso form.

  1. Names in use. Every .eth name, at any level, that at Ethereum mainnet block S resolves in ENS (registered and, for a second-level name, not past ENS’s grace period) and has a non-empty bitsocial text record. The entry holds the name’s first label, its parent, the account that holds the .eth name at S (for a second-level name its registrant or the holder of the wrapped name, for a subname its owner in the ENS registry or the holder of the wrapped name), and the value of the bitsocial record.
  2. Ancestors. For every subname under rule 1, each of its ancestors up to the second-level name, held by the account that holds that .eth name at S. An ancestor that has its own bitsocial record is already listed under rule 1; any other ancestor is listed with an empty record.
  3. Reserved names. A short list of top-level names that identify the project, its apps, and its maintainers, with an empty record. A reserved label that is also listed under rule 1 or 2 is dropped from the reserved list. A name in use always goes to its current holder.

An entry whose label the registry rejects, such as a label that starts or ends with - (which ENSIP-15 allows) or is longer than 255 bytes, is left out, together with every subname under it. Its owner keeps the .eth name. seed applies the same label checks as reveal, and the script that builds the list MUST check every label against them, so every entry in the tree can be seeded.

Rules 1 and 2 take only .eth names whose labels are already ENS-normalized (ENSIP-15): normalizing the name leaves it unchanged. ENS registers unnormalized spellings such as MEMES.eth as separate names, but BSIP-10 clients normalize before resolving, so those names never served a Bitsocial identity. Leaving them out keeps them from competing with the normalized name for the same .bso label. The seed list MUST contain at most one entry per (label, parent), and the script MUST check this.

Proposed reserved names:

LabelsOwner
bitsocial, bitsocialnet, bitsocialforge, bsips, pkc, pkcprotocol, plebbit, 5chan, seedit, mintpass, agoraswapfee recipient
tom, tommaso, tomcasaburiTommaso Casaburi, address TBD
rinse, rinse12Rinse, address TBD
esteban, estebanabaroafee recipient

SEED_ROOT is the root of an OpenZeppelin StandardMerkleTree over the entries, with leaf encoding ["string", "uint256", "address", "string"] for (label, parent, owner, record). Before deployment, the seed list, the reserved list, and the script that builds them from block S MUST be published in assets/bsip-13/, so anyone can rebuild SEED_ROOT and check every entry. Block S SHOULD be as close to deployment as practical.

Seeding

seed(label, parent, owner, record, proof) may be called by anyone before SEED_END. If proof shows that the entry is in the tree and the name is not registered, the registry:

  • for a top-level entry, registers the label to owner for 365 days;
  • for a subdomain entry, requires parent to be registered and active, and registers the label under it to owner as a subdomain, with no expiry of its own as upstream; and
  • charges no fee and, if record is non-empty, sets the name’s bitsocial text record to record.

A parent must therefore be seeded before its subdomains. Seeding MUST NOT call onERC721Received, so a contract owner without that hook still receives its name. From SEED_END on, seed reverts.

Because reveal reverts before SEED_END, nobody can register a seeded label first. The maintainers MUST seed every entry before SEED_END, SHOULD do so within one day of deployment, and MUST publish a check that every entry is registered to its listed owner. An entry that is still unseeded at SEED_END loses that protection: a top-level label opens to public registration, and a subdomain is left to its parent’s owner.

At SEED_END the maintainers MUST also compare every seeded record with the name’s current ENS bitsocial record and publish the names whose records differ, so that their owners can update the .bso record (Transition window).

Resolving .bso names

On activation, a client resolves a .bso name with these steps, which replace steps 2–4 of Resolving .bso and .eth names:

  1. ENS-normalize the name (ENSIP-15).
  2. Compute node = namehash(name) (EIP-137).
  3. Call text(node, "bitsocial") on the registry.

Steps 1 and 5–7 of BSIP-10 still apply. An empty result, which includes a name that is unregistered, expired, or in its grace period, means none. Example:

name:   memes.bso
node:   0x32766e8bc53e343c21d132d673d112b27f0e1aa11965199b934d29721837a941
call:   text(node, "bitsocial") on the registry
value:  12D3KooWNsF2eMrdw3YFPycAaFEvZ9Eq3ekhNL3vrAAfN6dAwXLp

.eth names keep resolving through ENS as BSIP-10 specifies. They are no longer reached by rewriting a .bso suffix.

Each client activates when it ships a resolver that implements this section. Clients SHOULD NOT activate until every seed entry has been seeded or SEED_END has passed.

Transition window

A seeded record is the .eth record as it was at block S. If an owner later replaced the key on ENS, for example after a compromise, the registry still holds the old key, and an activated reader would treat it as a key migration back to that key. To prevent this, until TRANSITION_END an activated resolver that gets a key K from the registry for x.bso MUST also resolve x.eth through ENS as BSIP-10 specifies:

  • if ENS returns a different key K′, the resolver MUST fail, so the outcome is unknown and the reader keeps the identity it holds;
  • otherwise, including when ENS returns none or fails, the registry’s answer K stands.

The name stays unknown until its owner makes the two records agree. The same rule covers a name that was not seeded and that someone else registered after SEED_END: while its .eth record holds a different key, activated readers get unknown, not a migration. From TRANSITION_END on, the registry alone decides.

Name equivalence

On activation, BSIP-10’s Name equivalence rule 2 becomes: both spellings end in .bso, or both end in .eth (suffix compared case-insensitively), and they are identical after lowercasing. bot.bso and Bot.BSO are still the same name. bot.bso and bot.eth are different names, held in different registries, possibly by different owners.

There is one exception, for comments signed while .bso was still an alias. When a client checks whether a stored comment belongs to a community (rule 2 of Community membership of comments), the comment’s communityName is the record’s name with the other of the two suffixes, the comment’s timestamp is before SEED_END, and its communityPublicKey is present and equals the community’s identity key, the comment is a member. In every other case the new rule applies. A comment signed for a.eth before then, in a community that later renamed itself a.bso and kept its key, stays a member. A comment signed later, or under another community’s key, never passes as a member of a.bso. Comments that lack communityPublicKey, or that were signed before a key migration, lose membership across the two suffixes.

Sunset and migration

sunset() may be called only by FEE_RECIPIENT, and only once. It sets sunsetAt = block.timestamp + 30 days and emits an event. From sunsetAt on, the registry is frozen: every function that changes its state reverts, except withdraw(). Nobody can commit, register, renew, transfer, approve, or change a record. Names keep resolving from the frozen state until they expire. A sunset cannot be cancelled or delayed.

During the 30-day notice the registry works as before, so owners can still renew, transfer, and edit. The frozen state at sunsetAt is what the migration imports, so changes made during the notice period, renewals included, carry over.

The fee recipient MUST NOT call sunset() except to move .bso to Bitsocial Chain, and only once a BSIP that specifies Bitsocial Chain’s .bso registry has reached Last Call. That BSIP:

  • MUST import, at no charge, the registry’s state at sunsetAt: every top-level name that is active or in its grace period, with the same owner, expiry, and bitsocial text record, and every active subdomain under them, with the same parent, owner, and bitsocial text record. It SHOULD import their other records;
  • MUST define the .bso resolution that replaces Resolving .bso names from sunsetAt; and
  • defines its own fees and their recipient. This BSIP does not bind it.

Rationale

  • An interim registry instead of ENS. ENS prices and payment terms are set by ENS. Waiting for Bitsocial Chain would leave .bso tied to them for an unknown time. Ethereum mainnet gas is cheap enough today for a name registry, and a registry there can be copied onto Bitsocial Chain later without new owners or new records.
  • Fork GNS. GNS is ownerless and immutable, prevents front-running with commit-reveal, makes names expire so abandoned ones return, and exposes the ENS text(node, key) interface. Resolvers change only which contract they call, and BSIP-10’s record format is unchanged. The diff is limited to the four changes above, so most of the deployed code is code that already runs upstream.
  • Collect fees instead of burning them. Bitsocial has no other funding, and this registry is temporary. A fixed recipient is acceptable because it cannot change prices and has no special power over names. It is a multisig rather than one person’s address so that the registry survives the loss of any one key or person.
  • Seed from a snapshot instead of checking ENS on chain. The registry could let .eth holders claim matching .bso names by reading ENS during a claim window. That would tie an immutable contract to ENS contracts, which have changed before, and give .bso names to every .eth holder, squatters included. Seeding only names that have a bitsocial record, at any level, copies exactly the identities Bitsocial users rely on, records included, so those communities keep resolving without their owners doing anything. Subnames bring their ancestors so that the registry can hold them. The cost is that the maintainers build the list. Fixing it at block S and publishing the script makes it checkable.
  • A transition window instead of trusting the snapshot. The seed list freezes records at block S, and under BSIP-10 a changed record moves a community to another key. Comparing with ENS for 90 days turns a stale seed into an unknown outcome, which BSIP-10 never acts on, instead of a silent move back to a key the owner abandoned. It costs one extra lookup per .bso name during the window.
  • Pause public registration while seeding. The registry cannot tell whether an arbitrary label is on the seed list without storing the list. Pausing reveal until SEED_END removes the race instead.
  • Reserved names. Squatters can use project and maintainer names to impersonate them. The list is kept short so the registry stays neutral, and names in use take precedence over it.
  • Sunset freezes the registry, after notice. The migration imports the state at sunsetAt. If names could still be renewed, sold, or edited on Ethereum after that, a buyer would hold a token that controls nothing on Bitsocial Chain, and old and migrated clients would resolve different keys. Freezing everything but withdraw() keeps the Ethereum state and the imported state the same. The 30-day notice is enforced by the contract, so a sunset is public before it takes effect, and owners can renew or move names before the freeze.
  • Separate .bso and .eth. Once the two registries can have different owners, equivalence would let whoever holds bot.bso match identity-list entries written for bot.eth, and the reverse. The membership exception keeps pages with comments from the alias era valid. Its SEED_END cutoff stops it from applying to new comments. Its key check stops the holder of a.bso from showing comments that were posted to a different community at a.eth, since those carry that community’s key. timestamp is set by the comment’s author, so backdating only lets authors misfile their own comments. The exception decides only which comments a community may show, not who holds authority.

Backwards Compatibility

  • Every .bso name in use at block S, subdomains included, keeps its owner, key, and record in the registry once its entry is seeded, unless the registry rejects its label (Seed list). The maintainers must seed every entry before SEED_END, and an entry still unseeded then loses that guarantee (Seeding).
  • A name that comes into use on ENS after block S is not seeded. Its owner has to register the .bso name like anyone else, and someone else may get it first (Security Considerations).
  • Clients that have not activated keep resolving x.bso as x.eth. For a seeded name both registries give the same answer until an owner changes one of them. Until TRANSITION_END, activated clients treat a disagreement as unknown (Transition window). Owners SHOULD keep both records the same until then, and clients SHOULD activate promptly.
  • A .bso name that is not seeded stops resolving in activated clients until someone registers it in the registry.
  • .eth names keep resolving as before. They no longer match .bso spellings in identity lists or when a community is loaded by name (Name equivalence). Community owners whose identity lists rely on that match SHOULD list the .bso spelling.
  • No signed record becomes invalid.

Reference Implementation

To be written:

  • the registry: a fork of lucadonnoh/gwei-names at the upstream commit with the changes in Registry contract, with a test for each change, in a bitsocialnet repository;
  • the seed-list builder and its output, in assets/bsip-13/;
  • .bso resolution through the registry in bso-resolver.

Security Considerations

  • No upgrades. A bug in the registry is permanent. The upstream NameNFT, inherited from wei-names, has had automated reviews (Cantina Apex, Plainshift AI, Zellic V12), and its repository shows no manual audit. The added code (withdraw, seed, the SEED_END check, sunset, and the freeze) SHOULD be reviewed independently and tested on Sepolia and on a mainnet fork before deployment.
  • Fee recipient. If the signers can no longer reach the threshold, fees are stuck where nobody can reach them, and sunset() can never be called, so the Ethereum registry keeps selling names after a migration. The signer rules in Fee recipient exist to prevent this. Signers who reach the threshold can call sunset() early. After the 30-day notice the registry freezes, and without a migration each name lapses when the time already paid for it runs out. The notice makes such a call public before it takes effect, and because renewals are uncapped, upstream and here, owners can pay for more time during it. Signers cannot change prices or the seed list, and have no power over names beyond what any account has.
  • Seed list. A wrong owner, record, or omission in the seed list is permanent once SEED_ROOT is deployed, and an entry left unseeded at SEED_END is open to anyone. Anyone holding a .eth name at block S receives the .bso name, including a holder who had compromised it by then. The list MUST be published and checked before deployment, and the seeding check after it.
  • Stale seeded records. A record copied at block S can hold a key its owner has since replaced on ENS, possibly because it was compromised. Without the transition window, an activated reader would migrate back to that key. The window makes the name unknown instead, and the comparison published at SEED_END tells owners to update their .bso record. After TRANSITION_END the window no longer protects a name whose owner never did.
  • Names not on the seed list. After SEED_END, anything not seeded is first come, first served. That includes a .eth name that got its bitsocial record after block S, a label the registry rejects, and an entry left unseeded. Someone else can register x.bso and set their own key, and under BSIP-10 key migration every activated reader of x.bso follows it. Holding b.bso also lets them create memes.b.bso for free. Until TRANSITION_END, the transition window turns such a takeover into unknown whenever the .eth record holds a different key. After that, the takeover succeeds. Taking block S close to deployment narrows the gap. Owners of such names SHOULD register their .bso names as soon as public registration opens. Readers that load the community by its .eth name are unaffected.
  • Name hijack. Under BSIP-10, whoever controls a name controls where its community’s readers migrate (Key migration). A .bso name that passes its grace period can be registered by anyone, who can then move its readers to their own key. Owners SHOULD renew early. Renewal is permissionless, so others, such as a directory maintainer, can also renew a name for its owner.
  • Subdomains. A parent owner can reclaim any subdomain at any time and move its readers. A community named by a subdomain trusts its parent’s owner completely.
  • Look-alike names. The registry lowercases ASCII only, so Unicode confusables and non-normalized spellings can be registered. BSIP-10’s normalization and look-alike rules apply to .bso names unchanged.
  • Two registries during the transition. Someone who controls x.eth but not x.bso, for example by registering an x.eth that expired after block S, can move readers on clients that have not activated to their own key. On activated clients, until TRANSITION_END, they can only make the name unknown by setting a different ENS record. Prompt activation limits the first, and the window’s end limits the second.
  • Front-running and resolver trust. Commit-reveal stops a mempool watcher from registering a name first, and before SEED_END reveal is disabled entirely. BSIP-10’s resolver trust considerations apply to the Ethereum providers that clients read the registry through.

Copyright and related rights waived via CC0.