This code snippet is a bit longer than what I usually write here. That is because this time, we're writing a fully working program.

This is a program that:

Listens and reacts to receiving coins in a brainwallet.

Creates a new transaction, forwarding all the received coins to two different donation addresses, splitting them 50/50

Broadcasts the new transaction to the network

And to do this, we'll be creating a transaction ground up using the raw Bitcoin data structures, signing the inputs with Schnorr signatures and communicating with the blockchain using the public Electrum network.

You'll also see a method for calculating the transaction fee for your transaction, achieving exactly 1 satoshi per byte every time.

We're using the bitcoincash Python library.

Disclamer: Use this guide at own risk. Remember that it's easy to mess up transactions in various ways, for example by spending all coins to miner fees.

TL;DR: Here is the full program. Below I'll cover it section by section.

Demo using insecure brainwallet! Don't do this at home. Any coins sent to the above QR code will get stolen.

Here is the transaction in a blockchain explorer

We start by importing all the stuff we'll use. Lets also define the two addresses we'll be forwarding to. These were fetched from EatBCH Venezuela and EatBCH South Sudans twitter profiles.

import hashlib import qrcode import asyncio from bitcoincash.core import b2x, lx, COutPoint, CMutableTxOut,\ CMutableTxIn, CMutableTransaction from bitcoincash.core.script import CScript, SignatureHash, OP_RETURN, \ SIGHASH_ALL, SIGHASH_FORKID from bitcoincash.core.scripteval import VerifyScript from bitcoincash.wallet import CBitcoinAddress, CBitcoinSecret, P2PKHBitcoinAddress from bitcoincash.electrum import Electrum EATBCH_VE = "bitcoincash:pp8skudq3x5hzw8ew7vzsw8tn4k8wxsqsv0lt0mf3g" EATBCH_SS = "bitcoincash:qrsrvtc95gg8rrag7dge3jlnfs4j9pe0ugrmeml950"

We create a private and public key with a super insecure brain wallet phrase, encode the public key in a cashaddr and print out the QR code. After that, we enter the never ending forwarding loop.

async def main(): # Connect to an Electrum server cli = Electrum() await cli.connect() # Create an insecure brainwallet h = hashlib.sha256(b'replace this please or get coins stolen').digest() private_key = CBitcoinSecret.from_secret_bytes(h) address = P2PKHBitcoinAddress.from_pubkey(private_key.pub) # Output a QR code for the address in the terminal qr = qrcode.QRCode() qr.add_data(str(address).upper()) qr.print_ascii() print(str(address)) try: while True: await forward_loop(cli, private_key, address) import time time.sleep(5) finally: await cli.close()

Notice that we upper case the cashaddr in the QR code. Upper case cashaddr are also valid, and by upper casing them, the data load can be encoded differently, making the QR code smaller, simpler and easier to scan.

This is where the magic happens. We'll be:

Checking if we've received coins

Creating a blank transaction Adding all received coins as inputs to the transaction Adding the EatBCH addresses at outputs Signing the inputs with Schnorr

Broadcasting the transaction

async def forward_loop(cli, private_key, address): # Get list of spendable coins in address coins = await cli.RPC( 'blockchain.scripthash.listunspent', address.to_scriptHash()) if not len(coins): return

By calling blockchain.scripthash.listunspent we're asking the electrum server if there are any coins sent to our address, that have yet to spend. If non, we just return to the mail loop.

Before we go forward, note that CTransaction , CTxIn , COutPoint , CTxOut and CScript are all basic building blocks of the Bitcoin protocol. You will find the same data structures in all full nodes. In any code derived from Satoshis code base, they'll even have the same name. When there is Mutable in the name, it just means they are not read only, we're allowed to modify them.

I believe its worthwhile to get familiar with these data structures, as you'll encounter them a lot when working with Bitcoin.

tx = CMutableTransaction() # Store input amounts for later amounts = [] # All coins received as inputs for c in coins: tx_input = CMutableTxIn(COutPoint(lx(c['tx_hash']), c['tx_pos'])) # This dummy scriptSig makes fee calculation simple. # We know that the Schnorr signature exactly 65 bytes. tx_input.scriptSig = CScript([b'0' * 65, private_key.pub]) tx.vin.append(tx_input) amounts.append(c['value']) # store for later

We create a blank transaction and append our coins as input. We don't need the coin amount yet.

Our scriptSig will proof that we can and want to send these coins, and we'll replace it later after building the full transaction. But for now, adding a dummy placeholder that is the same size as the final scriptSig will help us calculate the transaction fee.

# Dummy output amount (nValue). We need to calculate fee # before setting the actual amount. for addr in (CBitcoinAddress(EATBCH_VE), CBitcoinAddress(EATBCH_SS)): tx_output = CMutableTxOut(nValue = -1, scriptPubKey = addr.to_scriptPubKey()) tx.vout.append(tx_output) # For fun, let's add a small OP_RETURN greeting as well tx.vout.append(CMutableTxOut(nValue = 0, scriptPubKey = CScript( [OP_RETURN, b'Happy new year 2020!'])))

We add our outputs, which are the two EatBCH addresses. For fun, we can add a third dummy OP_RETURN output to encode a small greeting.

We can't add the amounts we're sending yet, because we've yet to calculate the transaction fees. Now that we've created the transaction, we can calculate the fee.

total = sum(amounts) fee = len(tx.serialize()) if total - fee < 2000: # The amount is tiny, lets wait for more coins return

Yep, that was easy. Find how many bytes the serialized transaction takes. Use that as fee. That makes it one satoshi per byte.

# Update output values total -= fee half = total // 2 # // is integer division tx.vout[0].nValue = half # EatBCH VE tx.vout[1].nValue = half # EatBCH SS

After subtracting the fee, we need to update the outputs. In this program, we choose to split them between the two outputs.

# Hash and sign inputs flags = SIGHASH_ALL | SIGHASH_FORKID for i in range(0, len(tx.vin)): sighash = SignatureHash( address.to_scriptPubKey(), txTo = tx, inIdx = i, hashtype = flags, amount = amounts[i]) signature = private_key.signSchnorr(sighash) + bytes([flags]) tx.vin[i].scriptSig = CScript([signature, private_key.pub]) # Optional, but useful for developers: Verify that the input is valid. VerifyScript( tx.vin[i].scriptSig, address.to_scriptPubKey(), tx, i, amount = amounts[i])

Now all that remains is to sign the inputs with Schnorr.

Hash the transaction

Sign the hash value

Update the scriptSigs with the signature

# We're playing with money here, so lets assert for safety. # + 1 off is OK because of the integer division above. assert sum(o.nValue for o in tx.vout) + 1 + fee >= sum(amounts) assert len(tx.serialize()) == fee # 1 sat/byte fee print("Received {} satoshis in {} coins!

"\ "Forwarding {} to EatBCH VE and {} to EatBCH SE. Tx fee {}.".format( sum(amounts), len(coins), tx.vout[0].nValue, tx.vout[1].nValue, fee)) # Done! Broadcast to the network. print("Broadcasting transaction...") print("Result: {}".format( await cli.RPC('blockchain.transaction.broadcast', b2x(tx.serialize()))))

Finally, we do some sanity checks and then broadcast our transaction to the Bitcoin Cash network.

Now that we've gone through this step-by-step, you should be able to understand the full program.

If you found this interesting, let me know. Subscribe and comment. Thanks!