Skip to content

Commit cdeed0f

Browse files
committed
v0.2.0, initial working version
1 parent 6e1bf09 commit cdeed0f

16 files changed

+2955
-5
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

LICENSE

+674
Large diffs are not rendered by default.

README.md

+241
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# bcash-instadump
2+
3+
**DUMP bcash 💩, HODL bitcoin 🚀**
4+
5+
CLI tools for insta-dumping bcash in exchange for bitcoins (`bcash-instadump`),
6+
creating bcash-compatible transactions (`bcash-tx`),
7+
listing unspent bcash outputs (`bcash-utxo`)
8+
and broadcasting raw bcash transactions (`bcash-broadcast`).
9+
10+
You can use these tools in a way that doesn't risk your bitcoins,
11+
by moving them out first. See "*Recommend Usage*" below.
12+
13+
Tips are welcome: *1HNDUy34hrqoTEChCZZjb6vWAU9APAKG78*
14+
15+
## Warning! here be dragons. :dragon: :dragon_face:
16+
17+
**This software could put your bitcoins, bcash and privacy at risk.**
18+
19+
These tools are meant for technically advanced users.
20+
Using them incorrectly (or even correctly!) could result in loss of funds and privacy.
21+
If you don't consider yourself a technical expert, please seek advice from someone who is.
22+
23+
Make sure to read *all* the instructions *carefully* before doing anything.
24+
25+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. USE AT YOUR OWK RISK.
26+
27+
## Install
28+
29+
The quick, unsafe way:
30+
31+
$ npm install -g bcash-instadump
32+
33+
The safer way: find a Git commit reference published by a third-party security auditor that you trust, then:
34+
35+
$ npm install -g git://github.com/shesek/bcash-instadump#[GIT-COMMIT-SHA256-HERE]
36+
37+
## CLI tools
38+
39+
### `bcash-instadump` - dump bcash on Changelly
40+
41+
$ bcash-instadump --input txid,vout,amount,key --payout 1BtcAddrGimmeRogersCoins --email zx@gmail.com
42+
43+
Use [Changelly](https://changelly.com/) to insta-dump bcash from the unspent output specified in `--input`
44+
(`amount` in whole bitcoins, `key` in base58/WIF)
45+
and send the converted BTC to the bitcoin address provided in `--payout`.
46+
47+
If you already have an account on Changelly, specify the account's password with `--password`.
48+
Otherwise, a new account will be created with the provided `--email`.
49+
50+
(*Changelly sends a randomly generated password to your email,
51+
but also provides a cookie (see `--cookie`) that gives immediate full access to the account.
52+
While you don't need the email to dump your bcash,
53+
you'll still need the password in order to troubleshot your account using a web browser,
54+
if you lose the cookie, or when the cookie is expired.*)
55+
56+
Specify `--feerate` to control the transaction fee (in `satoshis/byte`).
57+
Defaults to `rand(150,250)`.
58+
59+
You can specify `--input` multiple times, or specify a CSV file instead with `--inputs utxos.csv`.
60+
All the inputs will be joined together in a single transaction (see "*Privacy Concerns*" below).
61+
Only `p2pkh` scripts are currently supported.
62+
63+
`--cookie <file>` writes/reads the Changelly authentication cookie to/from `file`.
64+
*Highly recommended* if you're using this tool to create a new account,
65+
because otherwise you'll have to get the password from your email for the next `bcash-instadump` invocations.
66+
67+
Use `--whateverjustdump` to skip all confirmations (for exchange rates, miner fees, etc) and just dump.
68+
This is probably a terrible idea.
69+
70+
Changelly is used with a referrer code that tips the author of this tool.
71+
Use `--nogratuity` if you don't feel like doing that.
72+
73+
The `--(no)proxy`, `--tor` and `--electrum` options are the same as for `bcash-tx` (below).
74+
75+
See `bcash-instadump --help` for a full list of options.
76+
77+
**Note on rates:** Changelly does not commit to fixed rates and only provides estimates.
78+
The actual rate is determined when the exchange is fulfilled, after several on-chain confirmations.
79+
See [their FAQ](https://changelly.com/faq#why-not-fix-rates) for more details.
80+
81+
**The author of this tool is not affiliated with Changelly.**
82+
Do your research and use them at your own risk.
83+
84+
----
85+
86+
### `bcash-tx`- make bcash-compatible transactions
87+
88+
$ bcash-tx --input txid:vout:amount:key --output 1BcashAddr:ALL --feerate 250 --broadcast --tor
89+
90+
Create and sign a bcash-compatible transaction with the provided inputs and outputs.
91+
The transaction will be invalid on the Bitcoin network.
92+
93+
`--output addr:amount` can be used multiple times.
94+
Use `ALL` as the `amount` to send the maximum available amount minus tx fees, or specify the amount in whole bitcoins.
95+
`--feerate` is only relevant if `ALL` is used.
96+
97+
Specify `--inspect` to print the decoded transaction instead of its raw hex representation.
98+
99+
Use `--broadcast` to broadcast the transaction via an Electrum bcash server
100+
(also see `bcash-broadcast` if you already have a raw transaction ready).
101+
102+
Use `--proxy [socks4a|socks5h]://user:pass@host:port` or `--tor` to connect to the Electrum server over a proxy,
103+
or `--noproxy` to connect without one (see "*Privacy Concerns*" below).
104+
105+
You can configure a custom Electrum bcash server using `--electrum [tls|tcp]://host:port`.
106+
If not provided, one is chosen at random (from `electrum-servers.json`).
107+
108+
See `bcash-tx --help` for a full list of options.
109+
110+
----
111+
112+
### `bcash-utxo` - list unspent bcash outputs
113+
114+
$ bcash-utxo --tor 1myFirstAddr 1myOtherAddr ...
115+
116+
Get the unspent bcash outputs for the provided address(es) from the Electrum bcash servers,
117+
and print them as CSV (`txid,vout,amount,address` format).
118+
119+
This will leak information to the Electrum bcash servers (see "*Privacy Concerns*" below).
120+
121+
The `--(no)proxy`, `--tor` and `--electrum` options are the same as for `bcash-tx`.
122+
123+
See `bcash-utxo --help` for a full list of options.
124+
125+
----
126+
127+
### `bcash-broadcast` - broadcast raw bcash transactions
128+
129+
$ bcash-broadcast --tor <rawtx>
130+
131+
Broadcasts the provided `rawtx` (in hex) to the bcash network via an Electrum bcash server.
132+
133+
The `--(no)proxy`, `--tor` and `--electrum` options are the same as for `bcash-tx`.
134+
135+
See `bcash-broadcast --help` for a full list of options.
136+
137+
----
138+
139+
## Instructions & gotchas
140+
141+
### Recommend Usage (protect your BTC!)
142+
143+
1. Prepare a CSV file with a list of your UTXOs (`txid,vout,amount,key` format. `amount` in whole bitcoins, `key` in base58/WIF).
144+
145+
2. **Move your bitcoins!** To avoid risking your BTC, keys with a BTC balance should never be exposed to this tool.
146+
Make sure the keys provided to this software are *entirely emptied of BTC* and hold just the BCH tokens before doing anything with this tool.
147+
148+
3. Profit! `$ bcash-instadump --inputs utxos.csv --payout 1BtcAddrGimmeRogersCoins --email zx@gmail.com`
149+
150+
(WARNING: will merge the all the outputs together in a single transaction, see "*Privacy Concerns*" below)
151+
152+
**Example with Bitcoin Core:**
153+
154+
```bash
155+
$ sudo apt-get install jq
156+
157+
# 1. Generate the unspent outputs CSV file
158+
$ bitcoin-cli listunspent | jq -c '.[] | [.txid,.vout,.amount,.address]' | tr -d '[]"' \
159+
| awk -F, '{"bitcoin-cli dumpprivkey "$4 | getline key; print $1 FS $2 FS $3 FS key }' \
160+
> utxos.csv
161+
162+
# 2. MOVE THE BITCOINS TO NEW, UNUSED ADDRESSES
163+
$ bitcoin-cli sendtoaddress ...
164+
165+
# 3. Profit!
166+
$ bcash-instadump --inputs utxos.csv --payout `bitcoin-cli getnewaddress` --email zx@gmail.com
167+
168+
# (WARNING: will merge the all the outputs together in a single transaction, see "Privacy Concerns" below)
169+
170+
```
171+
172+
### Privacy Concerns
173+
174+
- **Leaking data to the public blockchain**
175+
176+
Merging your unspent outputs together (in a single multi-input transaction)
177+
will reveal the link between them (and their associated addresses)
178+
on the public bitcoin/bcash blockchains, *to the entire world*.
179+
180+
It is recommended to invoke `bcash-instadump` multiple times,
181+
once for each unspent output being sold (creating a separate 1-in,1-out tx each time)
182+
and with a different `--payout` address. Ideally, this should also be spread out over time.
183+
This could be accomplished using a bash script along the lines of:
184+
185+
$ cat utxos.csv | xargs -L 1 bash -c 'sleep $[ ( $RANDOM % 3600 ) ]s &&
186+
bcash-instadump --input $1 --payout `bitcoin-cli getnewaddress` \
187+
--email zx@gmail.com --cookie zx.cookie \
188+
--whateverjustdump'
189+
190+
- **Leaking data to Changelly**
191+
192+
Selling all of your unspent outputs via the same Changelly account and/or from the same IP address
193+
will reveal the link between your outputs (and their associated addresses) to the Changelly operators
194+
and to any attackers gaining access to Changelly's servers (via hacking, a legal warrant, or otherwise).
195+
196+
*Note:* Changelly appears to be blocking Tor users.
197+
198+
- **Leaking data to the Electrum bcash servers *when broadcasting transactions***
199+
200+
Transactions are broadcast to the bcash network using the Electrum bcash servers,
201+
giving them the ability to link your transactions/addresses/outputs to each-other and to your IP address.
202+
203+
It is recommended that you use `--proxy` or `--tor` to connect over a proxy.
204+
Preferably, use a proxy with a different public IP address for each request
205+
(otherwise the transactions would not be linked to your real IP address, but still linked to each-other).
206+
207+
Alternatively, you can get the raw transaction and broadcast it manually.
208+
Ideally, over a bcash full node under your full control, connected over Tor.
209+
210+
- **Leaking data to the Electrum bcash servers *when listing unspent outputs***
211+
212+
`bcash-utxo` uses Electrum servers to fetch the list of utxos,
213+
giving them the ability to link your addresses to each-other and to your IP address.
214+
215+
Using a proxy would help here too (with the same caveat regarding different public IP addresses),
216+
but ideally you should get this information from your own full node.
217+
218+
Note that `bcash-utxo` is the only tool that fetches unspent outputs,
219+
the other tools get them directly and don't attempt to fetch them on their own.
220+
221+
## Contributing
222+
223+
Pull requests are welcome! Some interesting next steps are:
224+
225+
- A tool to prepare the list of unspent outputs based on a list of private keys
226+
or the HD master seed.
227+
228+
- Creating a GUI frontend (packaged as a browser extension, an [Electron](https://electron.atom.io/) app, or something else?)
229+
230+
- Optimize input-merging behavior to improve privacy.
231+
232+
- Multi-signature support (currently only `p2pkh` scripts are supported)
233+
234+
- Tests (there aren't any! :scream::scream:)
235+
236+
- Have any other cool ideas? [Let me know!](https://github.com/shesek/bcash-instadump/issues/new)
237+
238+
## License
239+
240+
This software is released under the GPL v3 license.
241+
See LICENSE for more details.

cli/bcash-broadcast.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env node
2+
3+
const
4+
Electrum = require('../lib/electrum')
5+
, chalk = require('chalk')
6+
, { formatSat, initArgs, printErr } = require('./common')
7+
8+
const args = require('commander')
9+
.version(require('../package.json').version)
10+
.description('Broadcast raw transactions to the bcash network.')
11+
.usage('[options] <rawtx>')
12+
13+
.option('-e, --electrum <server>', 'electrum server, must be bcash-compatible [default: random server]')
14+
.option('-p, --proxy <proxy>', 'proxy for connecting to electrum server')
15+
.option('-t, --tor', 'shortcut for --proxy socks5h://127.0.0.1:9150')
16+
.option('-N, --noproxy', 'set if you\'re sure you don\'t want to use a proxy')
17+
18+
.on('--help', _ => console.log('\n README:', chalk.underline('https://github.com/shesek/bcash-instadump'), '(really, do!)\n'))
19+
20+
.parse(process.argv)
21+
22+
if (!args.args.length) args.help()
23+
initArgs(args)
24+
25+
Electrum(args.electrum, args.proxy).broadcast(args.args[0])
26+
.then(txid => console.log(chalk.green('(success)'), 'transaction broadcast to the bcash network:', chalk.yellowBright(txid)))
27+
.catch(printErr)

cli/bcash-instadump.js

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env node
2+
const
3+
chalk = require('chalk')
4+
, only = require('only')
5+
, util = require('util')
6+
, inquirer = require('inquirer')
7+
8+
, makeTx = require('../lib/make-tx')
9+
, Changelly = require('../lib/changelly')
10+
11+
, { collector, parseInput, formatSat, initArgs, checkFee, printErr } = require('./common')
12+
, { inspect } = require('util')
13+
14+
const DUMMYOUT = { address: '1BitcoinEaterAddressDontSendf59kuE', value: 'ALL' }
15+
16+
const formatNum = (num, asStr) => asStr ? (+num).toFixed(8) : +(+num).toFixed(8)
17+
18+
const args = require('commander')
19+
.version(require('../package.json').version)
20+
.description(`${chalk.red('DUMP bcash')} 💩 ${chalk.green('HODL bitcoins')} 🚀:`)
21+
22+
.option('-i, --input <input>', 'add input in txid:vout:amount:key format (amount in whole bitcoins, key in base58)', collector(parseInput), [])
23+
.option('-I, --inputs <file>', 'read inputs from CSV file')
24+
.option('-P, --payout <address>', 'send converted BTC to <address>')
25+
.option('-f, --feerate <rate>', 'set the feerate in satoshis/byte [default: rand(150,250)]', x => parseInt(x))
26+
27+
.option('-E, --email <email>', 'email for changelly account (a new account will be created if no <pass> is specified)')
28+
.option('-W, --password <pass>', 'password for changelly account (optional)')
29+
.option('-C, --cookie <file>', 'read/write the changelly auth cookie to/from <file>')
30+
31+
.option('-e, --electrum <server>', 'electrum server, must be bcash-compatible [default: random server]')
32+
.option('-p, --proxy <proxy>', 'proxy for connecting to electrum server and changelly')
33+
.option('-t, --tor', 'shortcut for --proxy socks5://127.0.0.1:9050')
34+
.option('-N, --noproxy', 'set if you\'re sure you don\'t want to use a proxy')
35+
36+
.option('--crazyfee', 'disable the crazy fee sanity check (allow feerate>1000)')
37+
.option('--nogratuity', 'don\'t use an affiliate code to tip the authors of this software')
38+
.option('--whateverjustdump', 'skip all confirmations (for exchange rates, miner fees, etc) and just dump. this is probably a terrible idea.')
39+
40+
.on('--help', _ => console.log('\n Example:\n\n $ bcash-instadump --input txid,vout,amount,key --payout 1BtcAddrGimmeRogersCoins --email zx@gmail.com'
41+
+ '\n\n README:', chalk.underline('https://github.com/shesek/bcash-instadump'), '(really, do!)\n'))
42+
43+
.parse(process.argv)
44+
45+
if (!(args.input.length && args.payout && args.email)) args.help()
46+
initArgs(args)
47+
48+
// @XXX builds and discards a dummy transaction to estimate the tx amounts and fees. somewhat wasteful.
49+
const bch_sent = formatSat(makeTx(args.input, [ DUMMYOUT ], args.feerate).outputs[0].value)
50+
51+
const client = Changelly(only(args, 'email password cookie proxy nogratuity'))
52+
53+
client.auth
54+
.then(u => console.error(chalk.yellow('(info)'), 'logged-in to changelly as', chalk.yellowBright(u.email)))
55+
.then(_ => client.estimate(bch_sent))
56+
.then(btc_out => client.trade(bch_sent, btc_out, args.payout))
57+
.then(trade => makeVerifyTx(trade))
58+
.then(tx => console.log(tx.inspect(),'\n\n\n',tx.toRaw().toString('hex')))
59+
.catch(err => Promise.reject(err == 'account-exists' ? accountExistsMsg : err))
60+
.catch(printErr)
61+
62+
const makeVerifyTx = trade => {
63+
const tx = makeTx(args.input, [ { address: trade.payinAddress, value: 'ALL' } ], args.feerate)
64+
, btc_out = trade.amountExpectedTo
65+
66+
if (!args.crazyfee) checkFee(tx)
67+
68+
console.log('\nOrder', chalk.yellowBright(trade.transId), 'via Changelly account', chalk.yellowBright(client.auth._user.email)+':')
69+
console.log(' Sending', chalk.yellowBright(formatNum(bch_sent, true), 'BCH'), 'to', chalk.yellowBright(trade.payinAddress), '(changelly\'s bcash address)')
70+
console.log(' Getting', chalk.yellowBright(formatNum(btc_out, true), 'BTC'), 'to', chalk.yellowBright(trade.payoutAddress), '(your bitcoin address)')
71+
console.log(' Exchange fee:', chalk.yellowBright(trade.fee + '%'))
72+
console.log('\nTransaction', chalk.yellowBright(tx.txid())+':')
73+
console.log(' In:', chalk.yellowBright(formatSat(tx.getInputValue()), 'BCH'), 'from', chalk.yellowBright(tx.inputs.length), 'inputs')
74+
console.log(' Out:', chalk.yellowBright(formatSat(tx.getOutputValue()), 'BCH'), 'to', chalk.yellowBright(tx.outputs.length), 'outputs')
75+
console.log(' Miner fee:', chalk.yellowBright(formatSat(tx.getFee()), 'BCH')+',', 'rate:', chalk.yellowBright(tx.getRate(tx.view)/1000), 'satoshis/byte')
76+
if (tx.inputs.length > 1) console.log(' ', chalk.red('(warn)'), chalk.gray('merging multiple inputs together could harm your privacy. See README.md for more details.'))
77+
//console.log('\n raw tx:', chalk.gray(tx.toRaw().toString('hex')))
78+
console.log('\nRates:')
79+
console.log(' ', chalk.red.bold('DUMP'), chalk.red(formatNum(bch_sent, true), 'BCH')+',', chalk.green.bold('GET'), chalk.green(formatNum(btc_out, true), 'BTC'))
80+
console.log(' ', '1 BTC', '=', chalk.yellowBright(formatNum(bch_sent/btc_out), 'BCH')+',', '1 BCH', '=', chalk.yellowBright(formatNum(btc_out/bch_sent), 'BTC'))
81+
console.log('\n ', chalk.red('(warn)'), 'Changelly does not commit to fixed rates, these are only their estimates.')
82+
console.log(' The actual rate is determined when the exchange is fulfilled, after several on-chain confirmations.')
83+
console.log(' See:', chalk.underline('https://changelly.com/faq#why-not-fix-rates'))
84+
85+
console.log('\nPlease ensure that everything checks out. Confirming will dump your bcash - THERE\'S NO UNDO!')
86+
console.log('Canceling will print the raw transaction without broadcasting it.')
87+
88+
return confirm('Dump?')
89+
.then(_ => tx)
90+
.catch(_ => {
91+
console.log('\n'+chalk.red('(canceled)'), 'not sending transaction:\n')
92+
console.log(util.inspect(tx.inspect(), { depth: 5, colors: true })+'\n')
93+
console.log(chalk.yellow('(rawtx)'), tx.toRaw().toString('hex')+'\n')
94+
console.log(chalk.yellow('(info)'), 'you may send this transaction manually with:\n $ bcash-broadcast <rawtx>\n')
95+
return Promise.reject('user aborted')
96+
})
97+
}
98+
99+
const confirm = message => args.whateverjustdump
100+
? (console.log(chalk.green('?'), chalk.bold(message), chalk.gray('--whateverjustdump, skipping')), Promise.resolve(true))
101+
: inquirer.prompt([ { name: 'ok', type: 'confirm', message, default: false } ])
102+
.then(r => r.ok || Promise.reject('user aborted'))
103+
104+
const accountExistsMsg = 'an account already exists with this email address. if its yours, please authenticate with '+chalk.yellowBright('--password')+' or ' + chalk.yellowBright('--cookie') + '.'

0 commit comments

Comments
 (0)