Enhancing TX::Watch with CashTokens

4 min read

#cashtokens #app development


Adding CashTokens to TX::Watch

View TX::Watch here

Welcome to our latest update on TX::Watch, our real-time tool that visualizes Bitcoin and Bitcoin Cash transactions. Each transaction is depicted as a colored circle, varying by properties such as value or type, including specialized CashToken transactions.

Our newest feature integrates CashTokens, part of the Bitcoin Cash network, allowing users to create both fungible and non-fungible tokens directly on the blockchain. This addition enhances TX::Watch by broadening the range of visualizable transactions, deepening user insights into blockchain dynamics.

What are CashTokens?

CashTokens facilitate the creation of digital assets on the Bitcoin Cash blockchain, supporting a variety of applications from digital currencies to unique assets like NFTs. They are fully miner-verified and rely on the efficient UTXO network for scaling, making them ideal for complex transactions and smart contracts within the Bitcoin Cash ecosystem.

For more technical details on CashTokens, visit the GitHub repository:

Learn more about CashTokens

Detecting CashToken Transactions

To visualize CashTokens on TX::Watch, first we have to detect them. From reading the CashToken specification, we learned that there are two key components to identifying CashToken transactions:

  1. The information is in the script values of the transaction, so we'll have to decode those values.
  2. The script must start with PREFIX_TOKEN (0xef)

Our system processes transactions in real-time via a WebSocket, so as they come in, we'll add a check to classify them.

For this we used the JavaScript library @bitauth/libauth for its utility functions which will be helpful when decoding the transactions script. There doesn't appear to be utility to decode the script hex into it's OpCodes directly, so we'll have to write our own. Below is the script we wrote which identifies OP_CODES within a transaction script and gives them to us in an array:

import { binToHex, hexToBin, OpcodesBCH } from "@bitauth/libauth";
// note: `OpcodesBCH` has `OP_UNKNOWN239` as the value for `0xef`.
// We will update this article when that enum is updated to `PREFIX_TOKEN`

type ScriptOpcodes = {
  code: string;
  data?: string;
}[];

function decodeScript(hexScript: string): ScriptOpcodes {
  const scriptBytes = hexToBin(hexScript);
  const opcodes: ScriptOpcodes = [];

  let i = 0;
  while (i < scriptBytes.length) {
    const byte = scriptBytes[i];
    if (byte <= 255) {
      // OP_CODES range
      if (byte <= 75) {
        // OP_PUSHBYTES
        const size = byte;
        const data = scriptBytes.slice(i + 1, i + 1 + size);
        i += size; // Skip over the data bytes
        opcodes.push({
          code: OpcodesBCH[byte],
          data: binToHex(data),
        });
      } else if (byte <= 78) {
        // OP_PUSHDATA
        const size = scriptBytes[i + 1];
        const data = scriptBytes.slice(i + 2, i + 2 + size);
        i += size + 1; // Skip over the data bytes
        opcodes.push({
          code: OpcodesBCH[byte],
          data: binToHex(data),
        });
      } else {
        opcodes.push({
          code: OpcodesBCH[byte],
        });
      }
    } else {
      console.warn(`Data: ${binToHex(scriptBytes.slice(i, i + 1))}`);
    }
    i++;
  }
  return opcodes;
}

When analyzing a CashToken transaction script, the output might look like this:

{
    "opcodes": [
        {
            "code": "OP_UNKNOWN239" // PREFIX_TOKEN
        },
        {
            "code": "OP_MAX"
        },
        {
            "code": "OP_UNKNOWN225"
        },
        {
            "code": "OP_LESSTHANOREQUAL"
        },
        {
            "code": "OP_UNKNOWN249"
        },
        {
            "code": "OP_SHA256"
        },
        {
            "code": "OP_3DUP"
        },
        {
            "code": "OP_PUSHBYTES_75",
            "data": "redacted"
        }
    ]
}

To detect a CashToken transaction from the decoded script:

const opScript = tx.out[0].script;
const opCodes = decodeScript(opScript);
if (opCodes[0].code === "OP_UNKNOWN239") {
  console.log("CashToken transaction detected!");
}

Next Steps

This allows us to reliably detect CashToken transactions. Future updates will focus on classifying different token types and integrating visual indicators such as specific icons or animations to represent various tokens in TX::Watch. We welcome all feedback, suggestions and improvements.

Stay tuned for more updates on TX::Watch and other exciting developments in the Bitcoin Cash ecosystem. If you have feature suggestions, questions, or would like to support our work, feel free to reach out.

TX::Watch