mainnet-cash / mainnet-js

TypeScript/JavaScript interface for interacting with Bitcoin Cash network
MIT License
31 stars 25 forks source link

issues with BCMR support #170

Closed mr-zwets closed 1 year ago

mr-zwets commented 1 year ago

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!

I have not tested BCMR.addMetadataRegistryAuthChain yet

Also but unrelated to BCMR I found that

mainnet-pat commented 1 year ago

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.

mainnet-pat commented 1 year ago

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

mr-zwets commented 1 year ago

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

mainnet-pat commented 1 year ago

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

mr-zwets commented 1 year ago

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.

mr-zwets commented 1 year ago

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)

mainnet-pat commented 1 year ago

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

mainnet-pat commented 1 year ago

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

mr-zwets commented 1 year ago

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?

mainnet-pat commented 1 year ago

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) 2)

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()

mr-zwets commented 1 year ago

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...

mr-zwets commented 1 year ago

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
mr-zwets commented 1 year ago

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

A60AB5450353F40E commented 1 year ago

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
  }
}