CHIP 2022-10 BCMR: Bitcoin Cash Metadata Registries

Hi all, I just published a draft proposal for a new application-layer standard:

Bitcoin Cash Metadata Registries (BCMRs) share metadata between Bitcoin Cash wallets, allowing user-recognizable names, descriptions, icons, ticker symbols, etc. to be associated with on-chain artifacts like identities, tokens, and contract systems.

Registries can be found via DNS and updated using on-chain transactions, offering strong censorship resistance and the same security available to funds and tokens: multisignature wallets, offline signers, time-delayed vaults, bounties/honeypots, and more.

On-chain identities are represented by chains of transactions, so their history and broadcasts can be verified by light clients with tiny proofs (a few KBs). Think software update hashes, warrant canaries, tamper-evident logs, reusable payment addresses, .onion addresses, etc.

The full specification is available on GitHub:

A livestreamed tech talk + Q&A on Bitcoin Cash Metadata Registries will take place on November 1, 2022 at 13 UTC:

Feedback and reviews are appreciated, either in the GitHub issue tracker or below. Thanks!

8 Likes

Great discussion today. Appreciate you organizing that. Very ambitious goals. The one open question I still have is about making sure to identify any tradeoffs you had to take, or potential weaknesses you can imagine, for example off in the future when it is highly adopted.

5 Likes

Also mentioning it here, that a version 2 of the BCMR standard is in the works. Copying from the open PR, the v2 will be the standard on mainchain, v1 was only for experimentation on chipnet.

Ah, I didn’t respond to the question on supporting the v1 schema – yeah, I think v1 should definitely be dropped completely. In a sense, it only ever supported chipnet since the format can’t even indicate what chain it’s talking about.

We can worry a bit more about backwards compatibility after this major version. I’m hopeful we’ve found a lot of the issues for now though, and future changes will generally just add new, optional fields. (And/or use extensions rather than changing the standard!)

3 Likes

The bcmr v2 open PR has now been merged and the v2 version now marked as draft with a recent change: ā€œSimplified publication output encodingā€ which incorporated feedback on the IPFS encoding.

The version 2 BCMR standard is already implemented in Cashonize, the webwallet and partly implemented in the Electron Cash pc wallet. Both wallets allow for linking a bcmr in the genesis transaction when creating new CashTokens.

Multiple token projects have already launched on mainnet using the bcmr v2 standard. Currently there is not yet an easy applications which can manage authhead utxos to update tokenmetadata.

There is also now a serious, high-quality metadata registry for CashTokens metadata with the launch of OpenTokenRegistry by @bitjson.

4 Likes

And another important piece of infra supporting the BCMR standard is the blockexplorer by salemkode (explorer.salemkode.com) which has full BCMR support and now also resolves autchains for on-chainmetadata update!

For example this is the tokenId of bitcats nft collection on the blockexplorer.

3 Likes

Today @MathieuG released a video to make it easier for newcomers to get their tokens set up:

3 Likes

Thanks for sharing the introductory video here!

The video explains DNS-Resolved Registries & Chain-Resolved Registries.
I use my Cashonize wallet to demonstrate token creation.
The video also explains why self certified metadata is not considered ā€œverifiedā€ and that tokens need to be included on a trusted tokenlist to be considered verified.
I use opentokenregistry as the example and show the well-known uri where the tokenlist is located.
Lastly the concept of authchains for metadata updates is covered.

4 Likes

Two new important pieces of BCMR tooling were recently developed:

  1. There’s now an indexer for on-chain published BCMR data made by Paytaca! The indexer is open-source and they have a publicly available API at bcmr.paytaca.com and its homepage has some general statistics.

the API endpoints are:

  1. /api/tokens/<category-id> → will give specific token metadata for FTs and generic token info for NFTs
  2. /api/tokens/<category-id>/<commitment>/ → will give token metadata for NFT types
  3. /api/registries/<category-id>/latest/ → will give the latest registry record for the given category ID
  1. I built a tool to generate BCMR json files for fungible tokens from an easy fill-in form. You can find it at bcmr-generator.netlify.app
4 Likes

Some extensions for the BCMR standard are also beginning to be used by different projects, here’s an overview:

The Bitcats & Guru collectible NFT project use the extension attributes on specific NFT types and this has already been adopted by different applications (including wallets and an nft marketplace) to display attributes unique about the specific NFT.
Additionally Bitcats uses an image_hash extension for each nft because the nft images are not stored on IPFS.

The ā€œReal Bitcoin Famā€ token has used the contact extension that was used as example in the BCMR spec.

Lastly, I want to suggest a new extension, nftNumbering, so projects can use an alternative to the scriptnumbers used by default for NFT Ticker Symbols.

3 Likes

Can we verify a shared registry, like the ones that explorers use?

Here is the scenario:

every single token may publish themselves a BCMR, they can do that on their own location somewhere on the web. But it’s not very useful as users and wallets won’t be able to find them. As such there are places like otc.cash which download those JSONs and provide the data there again. This makes salemkode’s explorer able to find token data.

But here is a problem I noticed yesterday. The bcmr published by a token owner will need to include the ā€œregistryIdentityā€ type and its child-properties. So 100 different tokens have 100 different registryIdentities. Version numbers. Descriptions etc.

But the otc.cash one only has one registryIdentity, its own. Then it just lists the identities copied from the bcmrs it re-hosts.

And this means that it doesn’t host the files ā€˜as-is’, which then means you can’t use the hash, as published on the blockchain, to verify it is an accurate copy.

1 Like

If somebody still have alternative BCMR indexers and API endpoints / RPC calls. Let me know…

I’m looking for something fast that index and retrieve the data (eg. C++ or Go with a database behind it). I know we are now 2 years later… but I would love to have some performant indexer, similar to Fulcrum but focused on Cash Tokens.

bchexplorer.cash I have has a backend written in Typescript (and the frontend in TS as well), but like I said, it doesn’t have to be TS.

1 Like

My personal solution is bcmr.flowee.cash which solves all problems I’m aware off. It’s currently in need of manual update, but that could be automated if people use it.

Long intro here:
https://x.com/FloweeTheHub/status/1912154694794818028

2 Likes

Thanks, great! I have some feedback however:

  • I want to set Accept and User-Agent headers in my API request from my client, which I think is a good thing. Which would allow you to see which kind of service is contacting your server. By design, this will create an OPTIONS method call, see CORS documentation. However, your server is not responding well on this, giving me: 405 Not Allowed. I strongly recommend implementing CORS support and return just 200 OK for the OPTIONS requests for example. More info as well…
  • What are the possible string values for ā€œtrustā€? I thus far only saw ā€œhighā€. Example
  • Could you open-source the project for the longevity of the project and this would also allow me to host my own instance, to avoid your service getting overloaded.

Thanks for checking it out, definitely happy to see someone using it :slight_smile:

The ā€œserverā€ you’re talking to is a basic no-fluff nginx webserver and the urls all resolve to just simple files on the filesystem. I strongly believe in keeping stuff simple. My expectation is that the usecase is a wallet on a private device, though. Not some website.

The project and code is public: Flowee/registry: Tools to make a bitcoin cash metadata registry - registry - BitcoinCash Code

And the trust-levels are described here: registry/documentation/trust.md at master - registry - BitcoinCash Code

1 Like

The only two indexers I’m aware of right now are the Paytaca indexer and the Flowee indexer.

1 Like
  • Thanks for sharing the link with the code! And Flowee indexer so much faster than Paytaca indexer (no offense Joemar, if you are reading this)
  • Got it, so it can be: absent, marginal, good, high or ultimate
  • I fully agree with the simplicity, don’t get met wrong… You still might want to hide the Nginx version though… (please add server_tokens off; to your Nginx configs, for your own security).

I would like to come back again to CORS. Maybe I’m the first user that is using this indexer now from a javascript client (browser client)?
I like to help you by setting an User-Agent header on my side of the request, I do get it working now without it by sending a plain get request.
However, I think its better for you to also set a User-agent string from the client side. Allowing the server-side to identify the requests.

So I didn’t invented CORS, but the moment I would set a User-Agent header, a preflighted request will be done (out of my control). In in your case you can handle the OPTIONS requests and add the access-control-allow headers in the response, which will make the preflight request succeed.

Like you said, there is no ā€œbackendā€ but just a simple Nginx webserver. Which is fine, but that means you can configure CORS on the Nginx level.

I will use the ā€œBasic NGINX CORS Configurationā€ from: NGINX CORS Configuration: The Complete Guide (2026) in this example, since once again keep it simple stupid (KISS).

I think the only thing I’m missing is this implementation in your Nginx config for your domain: http://bcmr.flowee.cash:


location / {
        [....]

        add_header Access-Control-Allow-Origin "*" always;
        add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Content-Type, Accept" always;

        if ($request_method = OPTIONS) {
            add_header Access-Control-Allow-Origin "*" always;
            add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
            add_header Access-Control-Allow-Headers "Content-Type, Accept" always;
            add_header Access-Control-Max-Age 86400 always;
            add_header Content-Length 0 always;
            return 204;
        }
}

(Adapt the example I wrote for you to your own needs if you wish)

Thank you for helping. If you really really don’t want to support CORS, that is fine… but this not ideal. I won’t be able to set any HTTP headers.