0

How to differentiate between BTC transactions and BRC20 transactions on a blockchain using the RCP interface?

This is a transaction record that contains BRC20 tokens which I found on a blockchain explorer.

When I using the RPC to scan blocks and retrieve transaction records like this one, how can I use Python3 to determine whether the transaction is a BRC20 or BTC transaction?

{
    "hash": "331d02db3d6ee0cffae9052be5799bd7754c6ebb2020e422058b73334c59bf85",
    "ver": 2,
    "vin_sz": 1,
    "vout_sz": 2,
    "size": 359,
    "weight": 734,
    "fee": 7360,
    "relayed_by": "0.0.0.0",
    "lock_time": 0,
    "tx_index": 4705820269244017,
    "double_spend": false,
    "time": 1682913851,
    "block_index": 787738,
    "block_height": 787738,
    "inputs": [
        {
            "sequence": 4294967293,
            "witness": "03405d88c3c66893b950a42d3672f3009a9f15e674f248a1d1c435609440b91e426598d9505752c560b24ba6261f1b3c7e997941006c9ead7b0378ca7c92c65519418320117f692257b2331233b5705ce9c682be8719ff1b2b64cbca290bd6faeb54423eac061b237bd58701750063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800357b2270223a226272632d3230222c226f70223a226d696e74222c227469636b223a2266726565222c22616d74223a2231303030227d6821c0117f692257b2331233b5705ce9c682be8719ff1b2b64cbca290bd6faeb54423e",
            "script": "",
            "index": 0,
            "prev_out": {
                "addr": "bc1pejeuynu5edq5fvfa8elpkem6zuzvrvqx20zundhpyuy3h3y8wumslwyd5h",
                "n": 0,
                "script": "5120ccb3c24f94cb4144b13d3e7e1b677a1704c1b00653c5c9b6e127091bc4877737",
                "spending_outpoints": [
                    {
                        "n": 0,
                        "tx_index": 4705820269244017
                    }
                ],
                "spent": true,
                "tx_index": 6896182349770388,
                "type": 0,
                "value": 10000
            }
        }
    ],
    "out": [
        {
            "type": 0,
            "spent": false,
            "value": 546,
            "spending_outpoints": [],
            "n": 0,
            "tx_index": 4705820269244017,
            "script": "51208873ed390476c5c7b6c825bae7eca675a46bc200cc7a82354b0debec19f83abc",
            "addr": "bc1p3pe76wgywmzu0dkgykaw0m9xwkjxhssqe3agyd2tph47cx0c827qd4yq9x"
        },
        {
            "type": 0,
            "spent": true,
            "value": 2094,
            "spending_outpoints": [
                {
                    "tx_index": 1274202281123575,
                    "n": 0
                }
            ],
            "n": 1,
            "tx_index": 4705820269244017,
            "script": "0014ea410b1701aeaa64dbf721cd55fce1231f2144a3",
            "addr": "bc1qafqsk9cp464xfklhy8x4tl8pyv0jz39rhhh0s7"
        }
    ]
}

How to analyze ? Witness component 1 , Witness component 2, Witness component 3.

If I want a complete analysis, what should I do.

The analogy is as follows:

{
  "p": "brc-20",
  "op": "mint",
  "tick": "free",
  "amt": "1000"
}
ID 331d02db3d6ee0cffae9052be5799bd7754c6ebb2020e422058b73334c59bf85i0
Length 53
Type text/plain;charset=utf-8
Timestamp 01 May 2023 12:04:11
Block height 787738
Size 133
Standard: brc-20
Operation: mint
Token: free
Amount: 1000

1 Answer 1

3

How to differentiate between BTC transactions and BRC20 transactions

Well, you can't because they are not disjoint sets, all BRC-20 transactions are also BTC transactions.

You identify BTC transactions that are also BRC-20 transactions in two stages:

  1. Does it contain an Ordinals Inscription
  2. Does the inscription contain a BRC-20 operation.

You look in the penultimate witness component for the Ordinals signature ("ord" etc)

You look in the inscription for JSON text content that matches the BRC-20 patterns.

In your example, just converting your "witness" from hexadecimal to ASCII produces

... ord ... text/plain;charset=utf-8 ... {"p":"brc-20","op":"mint","tick":"free","amt":"1000"}

But parsing it properly would be more reliable.


Parsing the Witness data

Hexadecimal data Meaning
03 There are three witness components
40 Length of first component is 0x40 = 64 bytes
5d88c3c66893b950 a42d3672f3009a9f 15e674f248a1d1c4 35609440b91e4265 98d9505752c560b2 4ba6261f1b3c7e99 7941006c9ead7b03 78ca7c92c6551941 Witness component 1
83 Length of second component is 0x83 = 131 bytes
20117f692257b233 1233b5705ce9c682 be8719ff1b2b64cb ca290bd6faeb5442 3eac061b237bd587 01750063036f7264 010118746578742f 706c61696e3b6368 61727365743d7574 662d3800357b2270 223a226272632d32 30222c226f70223a 226d696e74222c22 7469636b223a2266 726565222c22616d 74223a2231303030 227d68 Witness component 2
21 Length of witness component 3 is 0x21 = 33 bytes
c0117f692257b233 1233b5705ce9c682 be8719ff1b2b64cb ca290bd6faeb5442 3e Witness component 3

Different input types (for output types P2WPKH, P2WSH, P2TR etc) have different things in the witness lists. This can be seen in answers to What are the scriptPubKey, scriptSig, redeem script and witness for the various output types?

Parsing the penultimate witness component (component 2)

The Ordinals Inscription documentation says

A text inscription containing the string "Hello, world!" is serialized as follows:

OP_FALSE 
OP_IF
   OP_PUSH "ord"
   OP_PUSH 1
   OP_PUSH "text/plain;charset=utf-8"
   OP_PUSH 0   
   OP_PUSH "Hello, world!"
OP_ENDIF

Here's what I came up with treating component 2 as bitcoin script:

Hexadecimal data Normal Meaning Commentary
20 Push the next 0x20 (32) bytes onto the stack
117f692257b23312 33b5705ce9c682be 8719ff1b2b64cbca 290bd6faeb54423e Pushed data
ac OP_CHECKSIG (Note that nothing after this ends up affecting the final stack value and so has no effect on normal Bitcoin nodes. For them, the following might as well not exist)
06 Push the next 0x06 (6) bytes onto the stack
1b237bd58701 Pushed data
75 OP_DROP (throws away data just pushed onto stack - presumably private data of inscriber?)
00 OP_FALSE (This is the start of the Ordinals Inscription serialization)
63 OP_IF (Since the previous operation added FALSE to the stack, script execution on normal bitcoin nodes will skip everything up to OP_ENDIF. The rest still has to look like valid script though.)
03 Push the next 0x03 (3) bytes onto the stack
6f7264 Pushed data = ASCII ord
01 Push the next 0x01 (1) byte onto the stack
01 Pushed data has value 1 (Ordinals indication that MIME type follows)
18 Push the next 0x18 (24) bytes onto the stack
746578742f706c61 696e3b6368617273 65743d7574662d38 Pushed data = ASCII text/plain; charset=utf-8 (I am surprised "application/json" wasn't used)
00 OP_0: Push integer 0 onto the stack (Ordinals indication that inscription data follows)
35 Push the next 0x35 (53) bytes onto the stack
7b2270223a226272 632d3230222c226f 70223a226d696e74 222c227469636b22 3a2266726565222c 22616d74223a2231 303030227d Pushed data = ASCII { "p":"brc-20", "op":"mint", "tick":"free", "amt":"1000" } (This is an inscription in JSON format (despite prior MIME type) that contains a BRC-20 token minting operation.)
68 OP_ENDIF (in this case, end of Ordinals Inscription)

Obviously you are looking for the script elements that are prescribed for Ordinals inscriptions. the last but one item above is the actual inscription. It can be parsed as JSON to give the BRC-20 data structure. Obviously p's value, brc-20, is what you are searching for in the JSON data.


Related

6
  • Thanks, you said it so well. I understand now. But what if there are more than one in the witness? Just like this: I see multiple strings in witness that are used, split : "inputs": [ { "sequence": 4294967293, "witness": "03405d88c3c03405d88c3c, 03405d88c3c,03405d88c3c", "script": "", "index": 0,
    – Mashaji
    Jul 21 at 13:15
  • "witness": "03405d88c3c03405d88c3c, 03405d88c3c,03405d88c3c", looks like a bug in whatever blockchain explorer you are using. I suggest you work with the raw binary data, or at least raw hex, rather than this, or any other, blockchain explorer's JSON interpretation Jul 21 at 14:44
  • Thanks, You're a genius. How to analyze ? Witness component 1 , Witness component 2, Witness component 3. If I want a complete analysis, what should I do. The input field here is too small, I added the case to the question.
    – Mashaji
    Aug 4 at 10:29
  • That's an interesting follow-on question but not one I have an answer to at the moment. It is something I will probably spend time on eventually. Aug 4 at 10:30
  • thank you very much.
    – Mashaji
    Aug 5 at 8:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.