In the third part of this series of articles about The WeiTch Protocol, we will explore some of the main actions that users can perform on Twetch and Weiblock. Those actions are instructions provided to Twetch and Weiblock applications by the application's front end code. I will detail for each action what is recorded on the Bitcoin blockchain and what is not. And I will do my best to enumerate the messaging protocol specs that those applications use for the messages recorded on-chain.


Before I begin, it is important to highlight once more that the results presented in this article are relevant to the date when this article was written. As you can imagine, the messaging protocols used by Twetch and Weiblock are likely to evolve. At the time of writing these lines, no documentation is provided by either platform, therefore a little investigation was required. Also, I do not claim my results to be 100% accurate, but I did my best to cover all protocol specifications as meticulously as possible from what I was able to reverse engineer and understand. My aim is to disclose what they do well as well as the flaws and weaknesses of the protocols they use. However, I will refrain from talking about security issues that relate to a lack of controls and validation (which is the case for both platforms) and will try to focus on protocol-specific issues only.

In the previous part of my series of articles, we have focused on the reverse engineering methodology of the front end. We have also briefly mentioned the next step to understanding the protocol specs for messages stored on-chain which will be through simulated Money Button raw transactions. This is what we will investigate here.

Let's explore some of the main actions users can perform on Twetch and on Weiblock.

Publishing content

On both platforms, user can post messages. Those messages that everyone can read are recorded on-chain.


On Twetch, the Money Button to post content appears whenever the user presses the POST button on the "/compose" page.

A Money Button simulated payment on Twetch

The simulated Money Button transaction displays the button ready to send an OP_RETURN* transaction with hexadecimal raw data that follows this opcode.

* I will explain why the use of OP_RETURN is not the best way of storing data on the blockchain in another article.

OP_RETURN 31394878696756345179427633744870515663554551797131707a5a56646f417574 48656c6c6f2c0a0a5468697320697320612054776574636820666f72206d79206e6578742061727469636c652e20f09f918b 746578742f706c61696e 74657874 7477657463685f7477746578745f313536383032383633373532332e747874 7c 3150755161374b36324d694b43747373534c4b79316b683536575755374d74555235 534554 7477646174615f6a736f6e 6e756c6c 75726c 6e756c6c 636f6d6d656e74 6e756c6c 6d625f75736572 34303730 74797065 706f7374 74696d657374616d70 333339353131393837303634323330 617070 747765746368 7c 313550636948473232534e4c514a584d6f5355615756693757537163376843667661 424954434f494e5f4543445341 31414b48566959674247626d78693871694a6b4e766f484e654475396d334d665045 2323636f6d70757465645f7369672323

One thing we notice is that the data is split and each section is separated with a white space, which is great for reverse engineering. Of course, it isn't a requirement for developers to split the data this way as Money Button plainly ignores those white spaces, but it makes it easier for us to understand what is going on.

We can decode this hexadecimal data with a hex editor. I personally like to use Hex Fiend, but many alternatives can be found online.

A Twetch raw OP_RETURN transaction decoded by Hex Fiend

The decoded data shows the plain OP_RETURN data that the transaction will store on the blockchain.


This is a Twetch for my next article. 👋text/plaintexttwetch_twtext_1568028637523.txt|1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5SETtwdata_jsonnullurlnullcommentnullmb_user4070typeposttimestamp339511987064230apptwetch|15PciHG22SNLQJXMoSUaWVi7WSqc7hCfvaBITCOIN_ECDSA1AKHViYgBGbmxi8qiJkNvoHNeDu9m3MfPE##computed_sig##

This data, which constitute the messaging protocol used by Twetch, is exactly what you will be able to see decoded on a blockchain explorer such as once your transaction gets included in a block or reaches their mempool. You can fetch the transaction ID through Money Button's main dashboard by clicking on the corresponding tile. Or you can fetch it directly from the Money Button network requests even before the transaction gets broadcasted (I will not detail this part here).

So, let's try to understand what's going on here with the messaging protocol used by Twetch...

First of all, there is this part: 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut, which corresponds to the protocol prefix and is used to advertise on the blockchain which protocol specifications the message follows. In our case, it corresponds to unwriter's B:// protocol (Bitcoin Simple Storage Protocol). The protocol specs are documented on Github.

B:// protocol specs by unwriter on Github

If we follow the specs, this is how our message breaks down.

  • Data:

This is a Twetch for my next article. 👋
  • Media Type:
  • Encoding:
  • Filename:

Wait... that's intriguing... the protocol specs state that the filename comes last. But from what we can tell that field appears to contain more than that...

The hint about what's going on comes after the pipe: 1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5, which is yet another Bitcoin address... and a quick Google Search reveals it is the prefix used by a protocol called MAP (Magic Attribute Protocol). Hum okay, so basically this crafted protocol reuses the B:// protocol declaration but hacks its own specs to it. I'm not sure this is how things were supposed to work, but hey... who am I to judge about hacking things.

This is the protocol specs published on its Github page.

MAP protocol specs on Github

Do you understand any of this? Me neither. Okay, let us have a look at some examples.

That's a bit better... We can break down our Twetch data (again) with these new specs.

  • B protocol declaration (prefix):
  • Data:

This is a Twetch for my next article. 👋
  • Media Type:
  • Encoding:
  • Filename:
  • MAP protocol declaration (second prefix):
  • Type:
  • twdata_json (sub-SET field):

This empty field consumes data storage space on-chain...

  • url (sub-SET field):

Empty again... why store it then?

  • comment (sub-SET field):

Twetch, you like wasting blockchain storage space, don't you? 😅

  • mb_user (sub-SET field):

This is my Money Button ID.

  • type (sub-SET field):

This is the type of Twetch message. In our case, we are creating a post on Twetch.

  • timestamp (sub-SET field):

This is the date and time when the message is generated. You will need to dig the front end source code to understand how this timestamp is generated as I don't believe it is standard (I couldn't find the RFC for it).

  • app (sub-SET field):

It looks like they intended to have a protocol that other apps could use (cf Part 1 of my articles). 😁

  • AIP declaration (third prefix):

Yet another protocol declaration. This time it is the Author Identity Protocol (AIP).

  • Signing algorithm:
  • Signing address:
  • Signature:

Wait... where is the signature? Does it mean that Twetch doesn't sign the messages and anyone can post unsigned messages on the blockchain using their protocol? Does it mean I can Twetch anything I want without them validating the messages? 🤯 So many questions... so little time.

unwriter about Twetch ##computed_sig##

Enough about Twetch.


Similarly, we can have a look at the simulated Money Button request that was generated by our UI after posting content on Weiblock.

A Money Button simulated payment on Weiblock

But that would be a bit repetitive. Let's have a look at the transaction that was broadcasted instead. As you can see on the screenshot above, it is easy to fetch the transaction ID, since it is contained within the URL:

We can find it on WhatsOnChain!

A transaction decoded on WhatsOnChain

Perfect, this is all we need. The transaction is properly decoded by the blockchain explorer. Less work for us then.

Similarly to Twetch, we have an OP_FALSE OP_RETURN data (thumbs up to Weiblock for this) that uses the B protocol:

19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut{"weiblock":"3.3.3","content_type":"post","create_time":"1568024485359","moneybutton_id":"4070","weiblock_content":"Hello Weiblock, this is a message for my next article. 👋","img_list":[]}application/jsonUTF-8weiblock_4070_post.json

This time, no MAP or AIP protocols used. Thus, quite straightforward to break down:

  • B protocol declaration (prefix):
  • Data:
{"weiblock":"3.3.3","content_type":"post","create_time":"1568024485359","moneybutton_id":"4070","weiblock_content":"Hello Weiblock, this is a message for my next article. 👋","img_list":[]}
  • Media Type:
  • Encoding:
  • Filename:

Marvellous. This is a no brainer, everything follows the B protocol specs properly. What we are interested in now is the data content which uses Weiblock's own messaging protocol.

{"weiblock":"3.3.3","content_type":"post","create_time":"1568024485359","moneybutton_id":"4070","weiblock_content":"Hello Weiblock, this is a message for my next article. 👋","img_list":[]}

It is a classic JSON structure and easy to understand.

  • weiblock (protocol version):
  • content_type:
  • create_time:

UNIX Timestamp with milliseconds which decodes to "GMT: Monday 9 September 2019 10:21:25.359".

  • moneybutton_id:

This is my Money Button ID.

  • weiblock_content:
Hello Weiblock, this is a message for my next article. 👋
  • img_list (the list of transaction IDs for the images associated to my post):

And that's it!

But wait... where is the message signature? Does it mean anyone can post anything using the Weiblock messaging protocol and it will be displayed on Weiblock? The answer is: not necessarily. What I haven't told you is that signing messages is not something that is necessarily required, it all depends on the application's business model and on the purpose. An application can decide to let anyone use its protocol with no signing from its behalf required. Which can also be secure – the application would still need to validate the message and check that it complies with all its requirements (fees paid, protocol used properly, no illegal content, etc.). I will explain this in another article, but for now all I want you to know is that application signatures are not a requirement.

Liking content

Liking content is used to show your appreciation for other people's content. This appreciation is sent in the form of a tip paid to the author(s)' content. How do our applications handle it?


I decided to like one of Elon Moist's publication on Twetch. The simulated Money Button looked like this:

Liking content on Twetch - Money Button simulated payment

Wait a minute... where is the OP_RETURN data? Where does it mention which specific content I liked? Well... it doesn't. Likes on Twetch are not tracked on-chain, but rather in their internal database. The payment is still on-chain, so anyone can see you have liked something, but nobody but Twetch can tell what was liked exactly. Which is quite problematic if Twetch ever loses its internal database, and needs to restore it from scratch using the blockchain.

Liking content on Twetch - graphql request

After users like a specific Twetch the front end submits a "like" request instructing Twetch's back end to update its database. This request mentions you have liked a specific post.

{"operationName":"createLike","variables":{"payload":{"userId":"100","postId":"97540","transaction":"ea2859d162571347e12744564f6f4cc701b88cf3b8bcfad1a48af3ce6839df27"}},"query":"mutation createLike($payload: LikeInput!) {\n  createLike(input: {like: $payload}) {\n    clientMutationId\n    like {\n      nodeId\n      id\n      postId\n      userId\n      postByPostId {\n        id\n        likesByPostId {\n          totalCount\n          __typename\n        }\n        __typename\n      }\n      __typename\n    }\n    __typename\n  }\n}\n"}

The above shows the request my client sent to their back end after I swiped a like. It instructed that my Twetch user ID (specific to Twetch and not tracked on-chain) liked a post ID (specific to Twetch and not tracked on-chain) and that the corresponding transaction ID to the payment was ea2859d162571347e12744564f6f4cc701b88cf3b8bcfad1a48af3ce6839df27 (ID that cannot be entirely validated).



Weiblock on the other hand appears to be more consistent and uses its protocol for likes.

Liking content on Weiblock - Money Button simulated payment

The decoded OP_RETURN data below:


We notice the conten_type attribute is set to favorite which tells us the mentioned content was a "like".

After swiping Money Button, the front end instructs the back end it has liked some content.

Liking content on Weiblock - add-favorite API call

The decrypted request payload reads:


Here you can see the payment transaction ID along with the parent transaction ID which corresponds to the content liked. This specific transaction instructs the back end to read the transaction I just swiped from the mempool (or from the blockchain, if included in a block). This transaction contains all the information required to insert a new entry in the Weiblock internal database to add a post to my favourites. Which is exactly what happens.

I believe relying more on the blockchain and on the Bitcoin network and less on the data stored internally (until this data is cached in the application's internal database) is a good way to fetch content. This has the benefits of developing an application that does not require any complex and additional restore procedures from the blockchain data, as it does it already by design. If a disaster were to happen, the data can easily be recovered from the blockchain to the internal "cache" database.

Posting images and replying to posts

We'll try two in one.


Posting an image on Twetch - Money Button simulated payment

The OP_RETURN data of our simulated Money Button transaction is as follows:

19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAutu«ZŠf {úg¶¬{®"T‘ÃB†‚€��RR€��@���@�@À��¯‰@���Ômt4Áº€��ÒQU {p@C@��0¨=ÓÛCè��������/ƒH@��f˜8u@���QS‘+˜ €���image/jpegbinarytwetch_twembed1568072524506.jpg|1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5SETtwdata_jsonnullurlnullcommentHello,

This is a Twetch for my next article. 👋mb_user4070typeposttimestamp810906917677237apptwetch|15PciHG22SNLQJXMoSUaWVi7WSqc7hCfvaBITCOIN_ECDSA1AKHViYgBGbmxi8qiJkNvoHNeDu9m3MfPE##computed_sig##

What is different from a classic post is our B data which changes from text to image and the Twetch text content now appears at a different location. However, this time it is located within MAP. Why not use this location in the first place to post normal Twetch? 🤷‍♂️

The data, instead of being our text, is our image in the B protocol structure. It has the correct corresponding "Media Type", "Encoding" and "Filename".

The MAP protocol contains our comment.

  • comment (sub-SET field):

This is a Twetch for my next article. 👋

This is OK so far.

Twetch also offers posting screen captures of Tweets.

Posting a Tweet capture on Twetch - Money Button simulated payment

The application makes a few API calls to the back end and provides to the front end the screen capture to be posted by the user. Then the simulated Money Button appears and contains the following:

19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAutÿØÿà�JFIF[...]a�!@ÿÙ�image/jpegbinarytwetch_twembed1568073610593.jpg|1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5SETtwdata_json{"created_at":"Fri Aug 23 01:17:24 +0000 2019","twt_id":"1164708182515695621","text":"","user":{"name":"Klimenos - Breaking Twetch since 2019","screen_name":"klimenos","created_at":"Fri Dec 15 23:23:09 +0000 2017","twt_id":"941810893364563968"}}url,

This is a Tweet!|15PciHG22SNLQJXMoSUaWVi7WSqc7hCfvaBITCOIN_ECDSA1AKHViYgBGbmxi8qiJkNvoHNeDu9m3MfPE##computed_sig##

This time, the twdata_json and url fields are not empty and contain information about our Tweet.

  • twdata_json (sub-SET field):
{"created_at":"Fri Aug 23 01:17:24 +0000 2019","twt_id":"1164708182515695621","text":"","user":{"name":"Klimenos - Breaking Twetch since 2019","screen_name":"klimenos","created_at":"Fri Dec 15 23:23:09 +0000 2017","twt_id":"941810893364563968"}}

Twetch finally decided it was a good idea to use their own sub-protocol to achieve more. This JSON data shows a description of our Tweet. Some of those fields are displayed by the application in the /activity detail of our Twetch.

  • url (sub-SET field):
  • comment (sub-SET field):

This is a Tweet!

Our conclusion so far would be that this seems quite inconsistent with what we've seen with the format used to post a simple message when it doesn't contain images. I would speculate it is likely there is more than one developer working on the protocol or that whoever was involved with designing the protocol didn't think long-term.


Unfortunately, Weiblock does not currently support posting images in replies. We will post an image and reply to a post with two separate actions.

Users can create a post with a picture. When the user clicks on the "Publish" button, the application renders a Money Button and asks the user to publish the image on the blockchain first.

Posting image on Weiblock - Money Button simulated payment

The associated OP_RETURN data content is as follows:


��� ÷Om7 ��������¾

As you might have guessed already, this message is following the standard B protocol. Just like Twetch images, the images are displayed by However, they are not displayed on Bitstagram yet as Bitstagram doesn't support OP_FALSE OP_RETURN at the time of writing this article (it will be updated soon).

Bitstagram 0.0.5 supports for OP_RETURN opcode only as seen on Planaria

From what you can also read, the developer tried to embed some information in the filename to identify who posted the image and when. Which highlights that the B protocol, as it is used by his/her application, is not really adapted for it.

After the image is broadcasted, another Money Button appears, this time asking to publish our post.

Posting content with images on Weiblock - Money Button simulated payment

Below the content of the OP_RETURN data.

19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut{"weiblock":"3.3.3","content_type":"post","create_time":"1568070605186","moneybutton_id":"4070","weiblock_content":"This message is for Part 3 of my series of articles about The WeiTch Protocol.","img_list":["dea22531feb1c2285d49bacf40d3e3b4cc43f797ad9d827748aeef5f45215c68"]}application/jsonUTF-8weiblock_4070_post.json

We've seen the format above before in the publishing content part of the article. You can immediately notice that img_list is no longer an empty list but now contains one transaction ID: our image's transaction ID.

However, using this design leads to the back end being unable to tell directly if the images listed are images we have just uploaded or something else. It would need to fetch the transactions provided and try to identify the images: maybe by using the "Filename" which holds the money button id and timestamp... but this isn't a guarantee that it corresponds to the image we posted as this information can be crafted by anyone posting images.

Replying to posts on Weiblock works a bit differently.

Commenting on Weiblock - Money Button simulated payment
19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut{"weiblock":"3.3.3","content_type":"comment","create_time":"1568071483614","weiblock_content":"Let's go!","from":{"moneybutton_id":"4070"},"to":{"moneybutton_id":"7420","tx":"7670d3520f910499c94edd24d213e313c96c45fd197abebd8d7173d8bfc7b684","type":"post"}}application/jsonUTF-8weiblock_4070_comment.json

The OP_RETURN data format is similar to a like (content_type: favorite) within which two new fields have appeared:

  • type:
  • weiblock_content(my comment):
Let's go!

That should make you wonder why the dev didn't decide to format comments the same way posts are formatted, and just add the extra to and tx fields. Which would have allowed users to reply with images... 🙃

Following and un-following users


Twetch "follows" are partially recorded on-chain.

Following users on Twetch - Money Button simulated payment

To my knowledge, the formatting does not match any protocol specifications. I could, however, find that the 168qkFkCWCxc6xqG1SCdgxuLDPbhbPoktJ address corresponds to a bterm useradd call. But I have little clue about the meaning of it (I might update the article if I find out).


This message does not record who the follower is. The only thing we know from it is that the Twetch user ID 1198 received a follow by someone. Of course, it is always possible to investigate which Bitcoin address paid for this OP_RETURN data and maybe figure out who this came from. But it is not a straightforward process and cannot be handled by the application in order to reconstruct its internal database.

The action of unfollowing Twetch users also uses the same structure, but with a different following parameter value: unfollows, used instead of follows.


The above also shows a lack of consistency by Twetch.


At the time of writing this article, there is no such feature available to users on Weiblock.

Unlocking additional features


Similarly to likes, purchasing Twetch features ("DarkMode" & "Tweet from Twetch") is not an action that is stored on the blockchain. It is a direct payment to Twetch without on-chain traceability of the action that was performed.

Purchasing DarkMode and Tweet from Twetch on Twetch - Money Button simulated payments

The simulated Money Button data shows:


Once again, no OP_RETURN data. Therefore, it is a non-recoverable action in case the Twetch internal database cannot be rebuilt.


At the time of writing this article, there are no paid features available to purchase on Weiblock.

Notifications, profile and authentication

Both Twetch and Weiblock do not handle on-chain processing for those specific actions: all notifications, profile edits and application logon/logout are purely handled by the back end and stored by their internal database.

This means the front end instructs the back end of changes, but there is nothing stored on-chain. Therefore, none of this information is recoverable in case those platforms need to restore their internal database from the blockchain.

Some of those actions could be handled on-chain, which would not only add security but also traceability and recovery capabilities. But that's a topic for my next article on the WeiTch protocol.


If you've read Part 1 of this series of articles, you understood the reasons why I believe it is important we all work together on creating a standardised messaging protocol to benefit us all. Or at least, publish our draft protocol specs and make them open-source so that people can review, reuse and help improve them.

Throughout this Part 3 of The WeiTch Protocol article series, I have tried to highlight the current state of the messaging protocol that Twetch and Weiblock use. I have shown you the methodology I used to reverse the applications' protocols which helped understand their strengths and weaknesses. As you've noticed, there is some good but there is also some bad and ugly.

I believe building successful and lasting Bitcoin SV applications should be a collaborative work, particularly at this very early rebirth of Bitcoin. Especially if we want our applications to utilise the full capabilities of Bitcoin in terms of security, availability and redundancy offered by the decentralised public ledger.

Until then, here is a non-exhaustive list of recommendations I would like to share:

  • Applications need consistency.
  • Follow the protocol specifications.
  • If the business allows it, document and publish the protocol specs.
  • The blockchain is your application's write-once-read-many (WORM) database.
  • Internal databases must serve as temporary databases and cache databases only.
  • Everything must be recoverable using the blockchain.
  • Use the same messaging protocol to store data on-chain and to construct your internal database.
  • Implement controls where they are needed.
  • Do not implement unnecessary pseudo-protections where they are not needed or where they can easily be broken.
  • Do not release application features that are missing important code implementations (ie. leaving TODO sections in the code).
  • Assume any front end data received by the back end to be malicious and implement adequate data filtering, data validation and data sanitisation.
  • Assume any blockchain data stored to be malicious and implement adequate data filtering, data validation and data sanitisation.
  • Allow for application protocol upgrades.
  • Design your protocol first, implement it for your application later.
  • Collaborate with each other.

If you don't follow a rigorous and well thought out process, you might inevitably get stuck at some stage during the development and evolution of your application. That means, for example: ending up with an application that cannot scale or cannot add new features due to broken fundaments. You might also end up with critical blockers for your business if your application has a large user base and if you need to flush part of your users' data to upgrade your application. For instance, I am not sure how Twetch will be able to refocus its development and migrate the data that is not on-chain on the blockchain. The decisions that will be made will be quite interesting to witness, and it will certainly be a good example and proof of concept to all existing applications that wish to transit towards using the blockchain for application data storage.

In Part 4 of this series of articles I hope to draft the requirements for a secure messaging protocol. I would like it to be a collaborative work instead of a single man's work. I invite Twetch and Weiblock developers as well as anyone who wishes to contribute to reach out and work together on this project.