How to make post on BitClout using BItClout API
Tags: bitclout, python, api, crypto
Published: 2021-06-25 07:24:32

Creating a BitClot post isn't that straightforward. If you have ever used Twitter API (aka Tweepy) you might recall that tweeting through the API was really easy and convenient. All you needed to do was to call the predefined functions of the twitter API. This isn't the case with BItClout. If you have to make post or any transaction (since post is also a transaction) you will have to go through 3 major steps:

**Step 1**: Get the post transaction Hex

**Step 2**: Sign the transaction Hex

**Step 3**: Submit the transaction.

While the step 1 and step 3 is fairly easy, the step 2 is where a lot of people find it difficult to get through. This is where this article can come handy for those people! You must note that this article is only for creating post from YOUR account only. You must not try to create any service (like schedule post or something) which will make post on other user's behalf. It is also recommended to use a test account  to follow this tutorial because you will be using the **seedHex** of your account in your code. The **seedHex** in other language is as powerful as your BitClout seed phrase. If someone have access to your **seedHex** they can do ANYTHING with your account. If you are in crypto world from long time, you might know the **risk** of storing seed phrase (or seed Hex) on a computer or anywhere online. That's why you must use a test account to follow this tutorial (I repeat).

Before we get started, I want to let you know that this complete tutorial is in Python and it is must that you should be comfortable with the basics of python atleast.

1. **Getting the post transaction Hex**:  
This step is fairly simple enough. All you need is to collect the transactionHex of the required post from the `https://bitclout.com/api/v0/submit-post` endpoint. Below is a python function that returns the transactionHex for a post

```python
import json
import requests

def getPostTransaction(publicKey, body, imageUrl): 

  header = {
        "content-type": "application/json"
    }

  payload= {"UpdaterPublicKeyBase58Check": publicKey,
    "PostHashHexToModify": "",
    "ParentStakeID": "",
    "Title": "",
    "BodyObj": {"Body": body, "ImageURLs": imageUrl},
    "RecloutedPostHashHex": "",
    "PostExtraData": {},
    "Sub": "",
    "IsHidden":  False,
    "MinFeeRateNanosPerKB": 1000}

  res = requests.post(
        "https://bitclout.com/api/v0/submit-post", json=payload, headers=header)

  resJson = res.json()
  transactionHex = resJson["TransactionHex"]
  return transactionHex
```
In the above code snippet, `publicKey` refers to the public key of the account through which you want to make the post, `body` is a string referring to the post content and `imageURL` is a list type variable that stores the image URLs which you want to post on BitClout. You can pass `imageURL` to `[]` if you don't want top post image in your clout ( clout is to BitClout as tweet is to twitter ) 


2. **Signing the TransactionHex**:
The next and most important step is to sign the transaction. But wait, what does signing a transaction means ? Well, you are doing a transaction from an account so you can relate it as a bank account transaction where there must be a signature of the bank account owner. Does that makes sense ?
The signature part is to make sure that the transaction is being done from the account owner himself and not from any *thief**. BitClout has developed their own Identity service which is used to sign the transaction.

There are third party transaction signing APIs like [this](https://github.com/trevormil/bitclout-sign-transaction-api) but as the author of the API himself says that the API could have vulnerabilities which can be a breach to your account security, you must NOT use the above mentioned API to sign the transaction. But don't worry, there are other ways to sign the transaction!

The TransactionHex can be signed without using Identity service as well. Below is a python script that can sign the TransactionHex in few milliseconds! Create a new python file `sign.py` which contains the following script:

```python
import hashlib
import hmac

def get_hmac(key, data):
	return hmac.new(key, data, hashlib.sha256).digest()

def hmac_drbg(entropy, string):
	material = entropy + string
	K = b"\x00" * 32
	V = b"\x01" * 32

	K = get_hmac(K, V + b"\x00" + material)
	V = get_hmac(K, V)
	K = get_hmac(K, V + b"\x01" + material)
	V = get_hmac(K, V)

	temp = b""
	while len(temp) < 32:
		V = get_hmac(K, V)
		temp += V

	return temp[:32]

#######

g=(0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
	0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)
p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141

def point_add(point1, point2):
	# Returns the result of point1 + point2 according to the group law.
    if point1 is None:
        return point2
    if point2 is None:
        return point1

    x1, y1 = point1
    x2, y2 = point2

    if x1 == x2 and y1 != y2:
        return None

    if x1 == x2:
        m = (3 * x1 * x1) * pow(2 * y1, -1, p)
    else:
        m = (y1 - y2) * pow(x1 - x2, -1, p)

    x3 = m * m - x1 - x2
    y3 = y1 + m * (x3 - x1)
    result = (x3 % p, -y3 % p)

    return result

def scalar_mult(k, point):
	# Returns k * point computed using the double and point_add algorithm.
    result = None
    addend = point

    while k:
        if k & 1:
            # Add.
            result = point_add(result, addend)
        # Double.
        addend = point_add(addend, addend)
        k >>= 1

    return result

#######

def to_DER(r, s): # Signature to DER format
	r = bytes.fromhex(r)
	s = bytes.fromhex(s)
	if r[0] > 0x80:
		r = bytes.fromhex("00")+r
	if s[0] > 0x80:
		s = bytes.fromhex("00")+s
	res = bytes.fromhex("02"+hex(len(r))[2:]) + r + bytes.fromhex("02"+hex(len(s))[2:]) + s
	res = bytes.fromhex("30"+hex(len(res))[2:]) + res

	return res.hex()



def Sign_Transaction(seedHex, TransactionHex):
	s256 = hashlib.sha256(hashlib.sha256(bytes.fromhex(TransactionHex)).digest()).digest()
	drbg = hmac_drbg(entropy=bytes.fromhex(seedHex), string=s256)
	k = int.from_bytes(drbg, 'big')
	kp = scalar_mult(k, g)
	kpX = kp[0]
	r = kpX % n
	s = pow(k, -1, n) * (r * int(seedHex, 16)+int(s256.hex(), 16))
	s = s % n
	signature = to_DER(hex(r)[2:].zfill(64), hex(s)[2:].zfill(64))
	signed_transaction = TransactionHex[:-2] + hex(len(bytearray.fromhex(signature)))[2:] + signature
  
	return signed_transaction
```
The method `Sign_Transaction(seedHex, TransactionHex)` takes seedHex and TransactionHex as two argument. You can find the seedHex of your account in your browser storage. 
Just open `https://bitclout.com/` > Dev tools > Application > Storage > Local Storage > `https://identity.bitclout.com` > users > Select the public key with which you want to post > `seedHex`

Note: Never share your seedHex with anyone. sharing seedHex is equivalent of sharing seed phrase
 
The second argument `TransactionHex` is the transaction which you want to sign.

On a side note, [I](https://bitclout.com/u/ItsAditya) didn't create the above code but I can make sure that the above code is secure! You can check the repo [here](https://github.com/MiniGlome/BitClout-Sign-Transaction). 
**Note**: You must use the code of this article ONLY and NOT from any other repo mentioned in this article. The code in this article is secure and none of your private info like *seedHex* is being shared with any third party. Being on the safe side, you must review the code of `sign.py` on your own.


3. **Submitting the signed post transaction**:
The third and last step is to submit the signed post TransactionHex. Below is a python code that submits the transaction using `https://bitclout.com/api/v0/submit-transaction`


```python
import requests

def submitTransaction(signedTransactionHex):
    payload= {
        "TransactionHex": signedTransactionHex
    }
    response = requests.post(
        "https://bitclout.com/api/v0/submit-transaction", json=payload)

    return response.status_code
```

the `submitTransaction` method only takes `signedTransactionHex` as argument.

This is what the 3 required steps are to make post on BitClout. Summing up the above 3 steps, below is a 100% working code.

```python

import os
import requests
import json
import hashlib
import hmac


def getPostTransaction(publicKey, body, imageUrl): 

  header = {
        "content-type": "application/json"
    }

  payload= {"UpdaterPublicKeyBase58Check": publicKey,
    "PostHashHexToModify": "",
    "ParentStakeID": "",
    "Title": "",
    "BodyObj": {"Body": body, "ImageURLs": imageUrl},
    "RecloutedPostHashHex": "",
    "PostExtraData": {},
    "Sub": "",
    "IsHidden":  False,
    "MinFeeRateNanosPerKB": 1000}

  res = requests.post(
        "https://bitclout.com/api/v0/submit-post", json=payload, headers=header)

  resJson = res.json()
  transactionHex = resJson["TransactionHex"]
  return transactionHex


def get_hmac(key, data):
	return hmac.new(key, data, hashlib.sha256).digest()

def hmac_drbg(entropy, string):
	material = entropy + string
	K = b"\x00" * 32
	V = b"\x01" * 32

	K = get_hmac(K, V + b"\x00" + material)
	V = get_hmac(K, V)
	K = get_hmac(K, V + b"\x01" + material)
	V = get_hmac(K, V)

	temp = b""
	while len(temp) < 32:
		V = get_hmac(K, V)
		temp += V

	return temp[:32]

#######

g=(0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
	0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)
p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141

def point_add(point1, point2):
	# Returns the result of point1 + point2 according to the group law.
    if point1 is None:
        return point2
    if point2 is None:
        return point1

    x1, y1 = point1
    x2, y2 = point2

    if x1 == x2 and y1 != y2:
        return None

    if x1 == x2:
        m = (3 * x1 * x1) * pow(2 * y1, -1, p)
    else:
        m = (y1 - y2) * pow(x1 - x2, -1, p)

    x3 = m * m - x1 - x2
    y3 = y1 + m * (x3 - x1)
    result = (x3 % p, -y3 % p)

    return result

def scalar_mult(k, point):
	# Returns k * point computed using the double and point_add algorithm.
    result = None
    addend = point

    while k:
        if k & 1:
            # Add.
            result = point_add(result, addend)
        # Double.
        addend = point_add(addend, addend)
        k >>= 1

    return result

#######

def to_DER(r, s): # Signature to DER format
	r = bytes.fromhex(r)
	s = bytes.fromhex(s)
	if r[0] > 0x80:
		r = bytes.fromhex("00")+r
	if s[0] > 0x80:
		s = bytes.fromhex("00")+s
	res = bytes.fromhex("02"+hex(len(r))[2:]) + r + bytes.fromhex("02"+hex(len(s))[2:]) + s
	res = bytes.fromhex("30"+hex(len(res))[2:]) + res

	return res.hex()



def Sign_Transaction(seedHex, TransactionHex):
	s256 = hashlib.sha256(hashlib.sha256(bytes.fromhex(TransactionHex)).digest()).digest()
	drbg = hmac_drbg(entropy=bytes.fromhex(seedHex), string=s256)
	k = int.from_bytes(drbg, 'big')
	kp = scalar_mult(k, g)
	kpX = kp[0]
	r = kpX % n
	s = pow(k, -1, n) * (r * int(seedHex, 16)+int(s256.hex(), 16))
	s = s % n
	signature = to_DER(hex(r)[2:].zfill(64), hex(s)[2:].zfill(64))
	signed_transaction = TransactionHex[:-2] + hex(len(bytearray.fromhex(signature)))[2:] + signature
  
	return signed_transaction


def submitTransaction(signedTransactionHex):
    payload= {
        "TransactionHex": signedTransactionHex
    }
    response = requests.post(
        "https://bitclout.com/api/v0/submit-transaction", json=payload)

    return response.status_code



if __name__ == "__main__":
  postBody = "In retrospect, it was inevitable 💎🤲 " #don't dare change this body, Diamondhands won't like you
  imageURL = []
  seedHex = "YOUR_SEED_HEX"  # It is recommended to store your seedHex as environment variable
  publicKey = "YOUR_PUBLIC_KEY" 

  postTxn = getPostTransaction(publicKey, postBody, imageURL)
  signedTxn = Sign_Transaction(seedHex,postTxn)
  status = submitTransaction(signedTxn)

  if status == 200:
    print("Post done!")
  else:
    print("Error " + str(status))
```

Below is the result of the above code:

![Screenshot from 2021-06-25 12-06-23.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1624603006973/wtqOLoaPQ.png)

Congrats! You made a post on BitClout through your code.

If you like the article don't forget to let us know in the comments or maybe give a shout to [DevsClout](https://bitclout.com/u/DevsClout) ? You can also join DevsClout [discord server](https://discord.gg/4tCW2C8WhQ) to chat with more devs who are building awesome projects on BitClout! We would love to hear back from you!