mainnet-cash/mainnet-js

issues with BCMR support

Closed this issue · 14 comments

While adding BCMR support to my Cashtokens Webwallet I found a few issues and areas for improvement for the library. My project uses vanilla JS.

The previous issue #166 was handled very professionally with all issues resolved so thanks again for that!

  • BCMR.getTokenInfo(tokenId) does not get the tokenInfo from the identities array as it should
    (see example-bcmr
  • No option to add additional outputs to wallet.tokenGenesis
    this means no op_return info can be added to use authchain resolution and the authchain output can not be separately controlled.
  • hash256 (single?) needs to be exposed to hash the BCMR and add it to the opreturn

I have not tested BCMR.addMetadataRegistryAuthChain yet

Also but unrelated to BCMR I found that

  • wallet.getMaxAmountToSend()` does not work correctly for wallet with cashtokens

Hey Mathieu @mr-zwets
I have tested getMaxAmountToSend with an address with following utxos:

    [
      {
        txid: '0decf61b7d493dbc0691c5db370f00fdc2df49bca6cfc855654cab75c4746a75',
        vout: 0,
        satoshis: 5000,
        height: 0,
        token: undefined
      },
      {
        txid: '0decf61b7d493dbc0691c5db370f00fdc2df49bca6cfc855654cab75c4746a75',
        vout: 1,
        satoshis: 1000,
        height: 0,
        token: {
          amount: 25,
          tokenId: '4fabc9375983a8192d6316ebd8a2ed97efe41362c4cc0b25954858e5db95c755',
          capability: undefined,
          commitment: undefined
        }
      }
    ]

It reports BalanceResponse { bch: 0.0000478, sat: 4780, usd: 0 } Which is perfectly reasonable number for me. It will not take into account any token utxos and their satoshi value.

hash256 (single?) needs to be exposed to hash the BCMR and add it to the opreturn

sha256 and Mainnet.sha256 are available and point to the same object. Use sha256.hash() to hash anything. do binToHex() to convert the result to hex string

Thanks for resolving the issues! I marked 3/4 as solved!
I tried testing it in the web wallet some more and getMaxAmountToSend does not work once there is any tokenUtxos

Please drop here a chipnet address on which I can test this

see for example bchtest:zzf5fexgnw59t70hm36fe6tkyuqck5pwdczmrq3m46
Create a new wallet, got 0.101 tbch from the chipnet faucet, created an NFT which brings the webwallet ballance to 10098165 satoshis.
Now I try send max with getMaxAmountToSend and it gives 10098165 satoshis.
This results in the error:
Error: Amount required was not met, 10098667 satoshis needed, 10098526 satoshis available.
So clearly the max amount to send is wrong.

Also ran into a problem constructing a correct BCMR opreturn output.
the format is OP_RETURN <'BCMR'> <hash> [<https_url>]
My current code is:

        const bcmr = await reponse.json();
        const hashContent = binToHex(Mainnet.sha256.hash(bcmr));
        const chunks = ["BCMR", hashContent, url];
        opreturnData = OpReturnData.fromArray(chunks);

But this interprets hashContent as a UTF8 string instead of a hexadecimal.
So I'd like to know how to combine UTF8 strings and hexadecimals in one opreturn.
Or if i can just give the raw hex for the opreturn data is can use 0x6a0442434d52 + hashContent + hex(url)

Re: last question - binToHex produces you a hex string. So you get exactly what you instruct it to do. If you look at our tests you will see:

    const contentHash_v1 = sha256
      .hash(utf8ToBin(JSON.stringify(registry_v1, null, 2)))
      .reverse();
...
    let chunks = [
      "BCMR",
      contentHash_v1,
      "https://mainnet.cash/.well-known/bitcoin-cash-metadata-registry_v1.json",
    ];

where contentHash_v1 is binary data 32 bytes long

Note that the hash is in reversed layout, as written in chip: encoded in OP_SHA256 byte order https://github.com/bitjson/chip-bcmr#https-publication-outputs

Thank you!! this was super helpful! Had not taken a look at the code of the tests before.

Succeeded in making an onchain publication output for raw.githubusercontent.com/mr-zwets/example_bcmr/main/example_bcmr.json
https://chipnet.chaingraph.cash/tx/ddec4b40f4eccc239899092bdd1888a1f8cf0ad52585f56d71648d753acc9fea

However I also ran into an issue where if I wanted to include the https:// prefix and the opreturn data would get over 228 hexadecimal character in length i would get an error

Error: the transaction was rejected by network rules.
scriptpubkey (code 64)

so it seems there is some problem when the urls get too long?

  1. Note, that according to chip, your url should read something like https://mr-zwets.com/.well-known/bitcoin-cash-metadata-registry.json (which can be a redirect to your github hosted one)
const bcmr = await reponse.json();
const hashContent = binToHex(Mainnet.sha256.hash(bcmr));

This hashes the response object and not the text content of remote file. Either stringify your json object or use response.text()

My bad! I didn't understand why the stingify was necessary, going with response.text() instead of .json()!
Will look into the 'well known uri' standard, because I don't understand why this is mandatory...

made a publication output at token gensis on chipnet
https://chipnet.chaingraph.cash/tx/0090123ce181289927317ee6c209d66bf5934ed389f555da7715b46e843a24ed

However when I try

  const authChain = await BCMR.addMetadataRegistryAuthChain({
    transactionHash: "51094fb26daa7c9804cc7938716cd5b8d50d5c3df3a38c90d03931ce4e904e23",
    followToHead: true
  });

I get

Uncaught (in promise) TypeError: e is undefined
    buildAuthChain https://cdn.mainnet.cash/mainnet-1.0.12.js:2
    addMetadataRegistryAuthChain https://cdn.mainnet.cash/mainnet-1.0.12.js:2

Request for additional tokendata: for example in my wallet I'd like to display general info on tokens
for fungible tokens: how many were created in the genesis transaction and at what date
for NFTs: total supply, creation date & if a minting token still exists

fyi, you can easily fetch minting (or mutable) tokens by using chaingraph, here's an example query:

query {
  output(
    where: {
      token_category: {
        _eq: "\\xca66c43764e1b46fc00fd632a569d68654056e1eb8ce44c630760891921c53e4"
      }
      _or: [
        { nonfungible_token_capability: { _eq: "minting" } }
        { nonfungible_token_capability: { _eq: "mutable" } }
      ]
      _not: { spent_by: {} }
      transaction: {
        block_inclusions: {
          block: { accepted_by: { node: { name: { _eq: "bchn-chipnet" } } } }
        }
      }
    }
  ) {
    token_category
    nonfungible_token_capability
    spent_by {
      transaction {
        hash
      }
    }
    locking_bytecode
    output_index
    transaction_hash
    value_satoshis
  }
}