How to resolve BNS X names


As mentioned here, we’re working on a BNS upgrade to overcome the challenges that are currently holding BNS back. We’re calling this upgrade BNS X.

What BNS X functionality will be available in this first release?

The major feature in this first release is the ability to ‘wrap’ an existing BNS name in a smart contract, which allows users to consolidate and manage multiple names under one wallet. This, combined with SIP9 compliance of these BNS X names, will automatically open up a ton of functionality to apps that support the Stacks NFT standard (like marketplaces and wallets).

What is changing on BNS v1?


What is changing with BNS X?

Because users will be wrapping their BNS name and transferring it to a smart contract, there will be a mismatch between the on-chain lookup of a BNS name and the ‘true’ owner.

Example: I wrap hank.btc:

  • If you query the BNS contract, the owner of hank.btc will be a contract principal
  • If you query my address in BNS, it’ll show that I don’t own any names

Users who wrap their names will want to still enjoy the benefits of showing their name ownership in apps. Similarly, users will want to know the true owner of a given name, even if it is wrapped.

To solve for this, we have a ‘registry’ contract that stores the relationship between a BNS name and a BNS X name. To get the true owner of a name, you can lookup who owns the ‘wrapped’ name.


  • I wrap hank.btc
  • I minted the nft .bns-x::names with some integer ID
  • An event is propogated with the data { wrapped-id: id, name: name, wrapper-contract: principal }
  • Your systems store this mapping and are able to resolve that I own hank.btc

It’s possible for a wrapped name to be transferred. In that case, your app should resolve the owner of a name to the current owner of the wrapped BNS X name.

  • Example: I mint hank.btc, and then transfer it to Alice. If you lookup the owner of the “wrapped” hank.btc, you’ll show Alice as the owner.

Primary names are a mechanism to keep the ‘one-name-one-owner’ behavior that allows apps to show a single name for a STX address. In our protocol, if anyone owns a BNS X name, they’ll have a primary name stored on-chain. Users don’t have to set this manually, although they can change their primary name if they own multiple BNS X names.

I’m an app: What do I need to do to resolve BNS X names?

On day one, we’ll provide an API endpoint that mimick the Stacks Blockchain API BNS endpoints 1-for-1. For BNS-related API calls, you’ll only need to update your app to query our URL for those endpoints.

We will extend the current API interface to also include BNS X-specific data, like a user’s primary name and the NFT’s integer ID.


  • I own hank.btc, and I’ve wrapped it
    • /v1/names/hank.btc will return me as the owner, not the wrapper.
    • /v1/addresses/stacks/SP123... will return hank.btc as the name.
      • If will also return other names if I own multiple wrapped names.
  • Alice owns alice.btc, and it’s not wrapped
    • The API endpoints described above will resolve exactly as they do today.

I’m an NFT wallet or marketplace: What do I need to do to list BNS X names properly?

If you support SIP9 NFTs: Nothing. You are all set.

I’m the Hiro API: What can I do to help?

We are aiming to work together with Hiro and the community to get BNS X name resolution included by default in the Stacks Blockchain API repo. With that change, apps that use that API for BNS info won’t have to do anything to allow users to resolve their names properly.

What happens when I do an on-chain transfer of a primary name out from under the wrapped names? ie Wallet1Account1-on chain(‘primary’) bns = dan.btc, wrapped = ‘foo.btc’, ‘bar.btc’ … now I transfer ‘dan.btc’ to Wallet2Account7.

If I call `/v1/addresses/stacks/<wallet 1, account 1> will I get a “blank” name for the “primary name” (ie 3 names returned)? Or will I only get the 2 wrapped names that remain?

Thanks for putting together this proposal @hank

I have a question regarding alternate approaches to wrapping. You must have considered the following approach already, but I’m curious why we’re not going with something similar.

What if we create a new BNSv2 contract which:

  1. Is SIP-9 compatible.
  2. Allows multiple names per address.
  3. Look-ups pass through to BNSv1 if name isn’t registered on v2.
  4. Names can only be registered on BNSv2 if it hasn’t already been registered via BNSv1.
  5. Users can migrate their name to BNSv2 by calling a function on the v2 contract which will call the name-revoke function on BNSv1 to make it unresolvable, and then mint the name on BNSv2.
  6. Users can continue to register and use v1 names if they wish. The community would gradually migrate all of the tooling and frontends to v2.

I’m not sure if I’m interpreting your question correctly, but I think what you’re asking is:

  • I wrap dan.btc
    • Now I own this on BNS X, and the “legacy” BNS name is owned by a wrapper contract
  • I transfer dan.btc
  • Now, if you request /v1/address/stacks/wallet-1, you’ll have no names

Or if you’re asking about if you own multiple BNS X names?

If so, if you own multiple BNS X names, and transfer the “primary”, the BNS X contracts will automatically set your “next” name as primary. There’s no way of transferring without this logic getting triggered. If you don’t own any BNS X names, and you own a “legacy” BNS name, then I think we’ll have the primary field in the API return your legacy name. I’m not 100% sure on that, but no matter what the names array will be backwards compatible, so you can have something like:

displayName = data.primaryName || data.names[0]

Interesting - this is definitely very similar to our approach. Keep in mind that what we’re building is a “gradual” approach, and we want to make the transition as frictionless as possible, especially to start. At launch we’re only allowing BNS X names to be minted if you own the v1 name. We don’t yet want to get in a “state fork” where the same name can have different owners on v1 and v2. Similarly, forcing users to wrap (instead of name-revoke/burning it) allows users to get the “best of both worlds” - they can go back to v1 if needed. It also should make BNS X names more valuable , because it comes “bundled” with ownership of the v1 name.

Obviously would love to chat more with you about this!

Good mention thank you!

So there would eventually be a BNS v2 contract and the only difference between your proposal and what I posted is the wrapping vs name-revoke.

How would the existing Stacks node API handle ownership of BNS v2 NFTs? Since the names are owned by contracts and not directly by the wallet address. As wallets and other apps currently use the Stacks node API to determine NFT ownership, a wrapped BNS name would not show up under assets on look up. Is there any work being done on the API side at the same time to support this?

Also this approach that will break BNS functionality in production apps. Currently Xverse, and other apps like Gamma, use the owner address of the BNS name as the recipient for STX token and NFT transfers. If the owner of the BNS name is a contract, this functionality would break.

Yeah, I totally understand this concern. That’s exactly why we’re trying to prioritize working with integrators before launching, along with hosting a backwards-compatible API. The ideal situation is of course to also have the Stacks API support BNSx, which we are working towards.

1 Like

Okay, let me know how we can help.

1 Like

There is no way to avoid a state fork here, as @yukan pointed out. This wrapper approach is asking for trouble when the alternative is so much simpler. The new contract should mint the new name and revoke the old one with the following logic.

  • If name does not exist on old contract, mint it there first.
  • If user owns old name, mint new name.
  • Revoke old name.

This can all be done in one transaction and aborted in case of failure. The standard API endpoint should be updated to check the new contract first and fallback to the old contract.

Take care not to rush this out without extensive peer review.

Could you elaborate more on what you mean in regards to asking for trouble? Trouble in the short term or long term?

I think I’d definitely agree that a 1-tx name revoke plan is more simple from a technical point of view. Our thought is not that wrapping is technically simpler (definitely isn’t), but that is more likely to lead to long-term success. If we launched today and said “here’s this thing, please destroy your BNS name to use it”, would that lead to more users migrating? My guess is that would be “no” - the guess is that users are more likely to adopt a gradual approach vs something that gives the benefits with much less risk. Then, over time, a state fork has greater chance of success once there is momentum behind it.