It becomes increasingly difficult to write something about particular fork, as they are getting indistinguishable. This time, we’ll dump BitcoinX (BCX). So in this article I will focus more on yet another method of claiming, which is mildly interesting, without commission and can be used for many forks.
As usual, go read the Safety notice in my initial post in this series), if you haven’t done so yet.
About BitcoinX
So BCX is yet another fork, with a pretty homepage listing all the same stuff all the other forks do. As far as I can tell, the only change they did is move the decimal point in balances, so for every 1 BTC you get 10000 BCX. The rest is pretty much the same, but then again, who cares anyway, am I right or am I right?
The important questions is: Can it be claimed and exchanged for Bitcoin? And the answer is: Yes, it can!
The fork occurred at block height 498888 on December 12th, 2017.
Claiming
As far as I know, there is no wallet with support for BitcoinX. As a claim target I used address generated by AEX.com exchange, which is probably the only exchange which trades BitcoinX at the moment. First you have to register on AEX (not a very pleasant experience, I might add) and generate a deposit address for BCX.
Trezor or Ledger do not support direct claiming, which is understandable.
If you do not want to mess with anything, you can use Walleting Services, who will do it for you for a 10% cut. That is the easiest way.
You can also download the official wallet software from BCX Github and run it yourself, the same we did for Bitcore in my previous post. It should technically work, though I haven’t tested it, but it has one drawback. Unlike Bitcore, BitcoinX did nothing to the transaction history, so you will have to fully synchronize the blockchain, which was around 150 GB back then. Expect it to take several days.
However, there is another way, which will save us from running the full node and we do not have to give our seed to anyone. We craft the claim transactions ourselves. Fortunately, we do not have to do it completely by hand. There is a script, which does most of the work for us.
You will need Python installation to run it and also the private keys for your addresses you want to claim from. Please checkout Step 2 in Claiming Bitcore to extract the list of addresses and private keys. If you follow the guide, you’ll end up with a file of following structure:
path,address,public key,private key
m/49'/0'/0'/0/0,3G7BkezwZ3ab7nj6gD4ruFxfqdGVvXKraX,02146b1edb8b1d1f391500232ec9390e9ab57de283f4b6c570e4f2846332599c9d,L5STX9yStBe7aoxWWpaMW2y7vcLyowtNgLRn3UyKisN9Crt4b3Rn
m/49'/0'/0'/0/1,3JxTnMuSaWg91x2x4radQUGyU5mxPaDgQv,027633e319683645e86dab767dd345cbb4a3f2ef4173231eb6632308fb95a099f8,KwqE8Hpk3cTod8MgPQruexRBtGchtt8A1nQStuHo7tSxXxyt2yia
...
Unfortunately, it’s not as simple as giving the claiming script a list of addresses and private keys. If you take a look at the documentation, for a successful claim from a single address, the script requires the following inputs:
- public address (check, that’s the second field in the list above)
- private key (check, the fourth field)
- destination address (check, we have the AEX deposit address)
- coin type (check, it’s BCX in this case, but the script can be used for many other forks, including the very exotic ones)
- source transaction ID (the what ID? where do we get that?)
OK, so we need to take a step back and understand a bit more about Bitcoin at this point. Usually, when we talk about spending, we say we are sending Bitcoin from an address. That is technically not true, because what you are actually doing, is spending a previous transaction output or outputs. Let’s say you have address A. Someone sends you 1 BTC to this address (you have rich friends) in transaction T1 and another person sends another 0.5 BTC in transaction T2. Now you want to spend 1.2 BTC from A. You need the private key for address A, that is correct. But the actual transaction T3, which sends 1.2 BTC from address A to address B, could look something like this (ignoring fees):
Take output of T1 and output of T2 and send 1.2 BTC to address B and the remaining 0.3 BTC back to address A (or different change address which you control).
That way, you spend the outputs of T1 and T2, and create a new unspent output T3. Under normal circumstances, this is what your wallet software does for you automatically, but we are digging really deep here, so we need to get our hands a bit dirty. To make things more complicated, the transaction usually has more than one output, so you need to identify not only the transaction you want to spend from, but also an output index. That is, whether you are spending the first, second, third etc. output from the transaction.
But how do you find out, which transactions and indices from your addresses are unspent? Or rather which were unspent at the time of the fork and are thus claimable? Well, if you have just one or two addresses, you can do that manually using any block explorer, such as Blockchain.info. Just search for your address and pick the output which was created before the fork time.
If you have more than few, like I did, we have to be smarter. I made use of Blockchain.info’s API and created a small script, which takes the CSV output of addresses and keys and creates a list of commands with proper parameters, that can be run directly.
Below you’ll find the whole PHP script I used. It’s a web form where you enter your data and it prints the commands. It’s very rough, but does the job. You supply it with the keys in the format shown above, the coin type (BCX), the fork height (498888), destination address (the AEX.com deposit address) and fee you want to pay (I suggest you leave the default minimum 1000 satoshi).
It’s important to state that the script actually does nothing directly. It only creates a set of commands, which you can run later on to create and post the transactions. What it does, is for all addresses represented as lines in the input it downloads the transaction history. From that history, it picks the transaction outputs that were unspent at the time of the fork and calculates the claimable balance. For each address, which holds some claimable balance, it outputs a prepared command with correct parameters, which you can copy/paste into a terminal and run.
If you are going to use it, make sure you run it locally or on a server you control and trust. You can also use it as an inspiration to write your own script, perhaps more elegant.
The drawback of using this method is, that it currently operates on each address separately, so it will create multiple transactions, resulting in multiple fees being paid. That is not usually a problem, as all the forks have only minimal fees, but it’s something you should consider if you have a lot of addresses with tiny amounts.
The full script
<!DOCTYPE html>
<meta charset="utf-8">
<title>Claimer script from keys</title>
# QR codes from keys
<form method="post"><textarea cols="80" rows="20" name="csv"><?=$_POST['csv'] ?></textarea><br>
Coin <input type="text" name="coin" value="<?=$_POST['coin']?>"><br>
Block height <input type="text" name="bh" value="<?=$_POST['bh']?$_POST['bh']:500000?>"><br>
Destination address <input size="50" type="text" name="dest" value="<?=$_POST['dest']?>"><br>
Fee <input type="fee" name="fee" value="<?=$_POST['fee']?$_POST['fee']:'1000'?>"><br>
<input type="submit"><br></form>
--------------------------------------------------------------------------------
<?php
if (!empty($_POST['csv'])) {
$bh = $_POST['bh'];
$coin = $_POST['coin'];
$fee = $_POST['fee'];
$dest = $_POST['dest'];
printf("Block height: %d\n", $bh);
$lines = explode("\n", $_POST['csv']);
foreach ($lines as $line) {
if (empty($line)) continue;
$fields = explode(',',$line);
$address = $fields[1];
$privkey = trim($fields[3]);
printf("Address: %s\n", $address);
$bc = json_decode(file_get_contents("<https://blockchain.info/rawaddr/{$address}>"));
if (empty($bc)) continue;
// filter transactions before the fork
$validtxn=[];
foreach (array_reverse($bc->txs) as $txn) {
// disregard transactions that happened after fork
if ($txn->block_height > $bh) {
printf("Transaction %s older than fork, removing\n", $txn->hash);
continue;
}
$validtxn[] = $txn;
}
printf("Found %d valid transactions\n", sizeof($validtxn));
// calculate balance
$balance = 0;
foreach ($validtxn as $txn) {
printf("Processing transaction %s\n", $txn->hash);
foreach ($txn->inputs as $input) {
if ($input->prev_out->addr == $address) {
printf("Transaction %s spends %d\n", $txn->hash, $input->prev_out->value);
$balance -= $input->prev_out->value;
unset($unspent[$address.$input->prev_out->tx_index]);
}
}
foreach ($txn->out as $outputindex => $output) {
if ($output->addr == $address) {
printf("Transaction %s creates spendable output of %d\n", $txn->hash, $output->value);
$balance += $output->value;
$unspent[$address.$output->tx_index] = [ 'txn' => $txn->hash, 'balance' => $output->value, 'index' => $outputindex, 'address' => $address, 'privkey' => $privkey];
}
}
}
}
printf('Generated script: --------------------------------------------------------------------------------');
foreach ($unspent as $row) {
printf("python claimer.py %s %s %s %s %s --txindex %d --satoshis %d --fee %d --force --noblock\n",
$coin, $row['txn'], $row['privkey'], $row['address'], $dest, $row['index'], $row['balance'], $fee);
$value += $row['balance'];
}
printf("--------------------------------------------------------------------------------
Total claimable balance: %1.6f\n", $value / 1000 / 1000 / 100);
}
?>
Dumping
So you have successfully created and sent the transactions and your AEX.com account is funded with BCX. At the time I did it, but also according to various posts on Reddit and elsewhere for a while already, AEX has BTC withdrawals suspended. I do not know if there is way to actually tell, unless you have some balance. I found out the hard way, when I tried to withdraw and was greeted with a notice that BTC withdrawals are suspended. So I had to do one more exchange and convert BTC to Litecoin. LTC withdrawal went thru OK, so I moved LTC to another exchange and finally converted to Bitcoin.
Final verdict
I was able to obtain 0.22% value from BitcoinX, which was slightly better than Bitcore, but worse than Bitcoin Cash, Gold or Diamond. It was comparable to Super Bitcoin.
The method used to claim BCX is however quite handy and I replicated it with minimal effort to get some of the most obscure forks. I also learned quite a bit about how Bitcoin transactions are built.
So, a win again, I guess.
Comments