Parsing a Bitcoin Transaction

Intro

While we can verify that a transaction was mined using the clarity-bitcoin-lib contract library, we can also parse a Bitcoin transaction using Clarity directly.

If you aren't familiar with how Bitcoin transactions are encoded in raw form, take a quick look at that. The tl;dr is that all of the data from a Bitcoin transaction is encoded in hexadecimal form in a string of bytes; we can slice out pieces of that hex value to pull out all of our transaction data components.

The process to do this is relatively complex, but the clarity-bitcoin-lib provides a function called parse-tx or parse-wtx (for witness transactions) that makes this simple. All we need to do is pass in a raw transaction hex and we get back the data of the transaction, including inputs and outputs.

circle-info

The current version of the clarity-bitcoin-lib is version 7. Click herearrow-up-right for the deployed mainnet contract.

The parse-tx function of the clarity-bitcoin-lib contract looks like this:

clarity-bitcoin-lib
;; --snip--

(define-read-only (parse-tx (tx (buff 4096)))
  (let (
      (ctx {
        txbuff: tx,
        index: u0,
      })
      (parsed-version (try! (read-uint32 ctx)))
      (parsed-txins (try! (read-txins (get ctx parsed-version))))
      (parsed-txouts (try! (read-txouts (get ctx parsed-txins))))
      (parsed-locktime (try! (read-uint32 (get ctx parsed-txouts))))
    )
    ;; check if it is a non-segwit transaction?
    ;; at least check what happens
    (asserts! (is-eq (len tx) (get index (get ctx parsed-locktime)))
      (err ERR-LEFTOVER-DATA)
    )
    (ok {
      version: (get uint32 parsed-version),
      ins: (get txins parsed-txins),
      outs: (get txouts parsed-txouts),
      locktime: (get uint32 parsed-locktime),
    })
  )
)

Where txRaw is a string containing the raw transaction hex. Passing that buffer into parse-tx returns the parsed transaction object with version, inputs (ins), outputs (outs), and locktime. You can then extract whatever fields you need from that returned data.


Steps

1

Get the raw transaction hex

Obtain the raw transaction hex from a Bitcoin explorer API. This is a single hex string representing the entire transaction.

Example raw bitcoin transaction hex:

0200000000010196277c04c986c1ad78c909287fd12dba2924324699a0232e0533f46a6a3916bb0100000000ffffffff026400000000000000160014274ae586ad2035efb4c25049c155f98310d7e106ca16440000000000160014599bcef6387256c6b019030c421b4a4d382fe2600247304402204d94a1e4047ca38a450177ccb6f88585ca147f1939df343d8ac5d962c5f35bb302206f7fa42c21c47ebccdc460393d35c5dfd3b6f0a26cf10fac23d3e6fab71835c20121020cb972a66e3fb1cdcc9efcad060b4457ebec534942700d4af1c0d82a33aa13f100000000

circle-info

You can paste this into a raw transaction decoder like this one to inspect the decoded fields: https://live.blockcypher.com/btc/decodetx/arrow-up-right

2

Pass the transaction hex into Clarity-Bitcoin's parser

Convert the hex string to a Clarity buffer and pass it to the parse-tx function (via your stack.js read-only function call). In stacks.js:

If using stacks.js, pass the raw hex to your Clarity function as a Clarity typed buffer:

3

Examine and use the parsed result

parse-tx returns an object containing:

  • version

  • ins (transaction inputs)

  • outs (transaction outputs)

  • locktime

Extract whatever fields you need from that returned object.


Example Usage

Square Runes

A Clarity implementation for parsing Bitcoin Runes protocol data, allowing Stacks smart contracts to understand and react to Runes transactions on the Bitcoin chain.

Check out the project repo herearrow-up-right.

Last updated

Was this helpful?