Skip to content

Instantly share code, notes, and snippets.

Created Jan 3, 2020
What would you like to do?
Accept and forward Bitcoin Cash transactions
#!/usr/bin/env python3
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, \
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"
async def main():
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(
# Output a QR code for the address in the terminal
qr = qrcode.QRCode()
while True:
await forward_loop(cli, private_key, address)
import time
await cli.close()
async def forward_loop(cli, private_key, address):
# Get list of spendable coins in address
coins = await cli.RPC(
if not len(coins):
# Build our new transaction from scratch.
# * Use all the coins we've received as inputs
# * Create three outputs: One for EatBCH Venezuela,
# one for South Sudan and an OP_RETRUN greeting
# * Sign inputs with Schnorr
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,])
amounts.append(c['value']) # store for later
# 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())
# 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!'])))
total = sum(amounts)
fee = len(tx.serialize())
if total - fee < 2000:
# The amount is tiny, lets wait for more coins
# Now that we know the fee, we can:
# * Update output values
# * Hash and sign the inputs
# 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
# Hash and sign inputs
for i in range(0, len(
sighash = SignatureHash(
txTo = tx,
inIdx = i,
hashtype = flags,
amount = amounts[i])
signature = private_key.signSchnorr(sighash) + bytes([flags])[i].scriptSig = CScript([signature,])
# Optional, but useful for developers: Verify that the input is valid.
tx, i, amount = amounts[i])
# 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!\n"\
"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()))))
loop = asyncio.get_event_loop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment