|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Blocktrail\SDK; |
|
4
|
|
|
|
|
5
|
|
|
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKey; |
|
6
|
|
|
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKeyFactory; |
|
7
|
|
|
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator; |
|
8
|
|
|
use Blocktrail\SDK\Bitcoin\BIP32Key; |
|
9
|
|
|
use Blocktrail\SDK\Exceptions\NotImplementedException; |
|
10
|
|
|
|
|
11
|
|
|
class WalletV1 extends Wallet { |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* BIP39 Mnemonic for the master primary private key |
|
15
|
|
|
* |
|
16
|
|
|
* @var string |
|
17
|
|
|
*/ |
|
18
|
|
|
protected $primaryMnemonic; |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
21
|
|
|
* @param BlocktrailSDKInterface $sdk SDK instance used to do requests |
|
22
|
|
|
* @param string $identifier identifier of the wallet |
|
23
|
|
|
* @param string $primaryMnemonic |
|
24
|
|
|
* @param BIP32Key[] $primaryPublicKeys |
|
25
|
|
|
* @param BIP32Key $backupPublicKey should be BIP32 master public key M/ |
|
26
|
|
|
* @param BIP32Key[] $blocktrailPublicKeys |
|
27
|
|
|
* @param int $keyIndex |
|
28
|
|
|
* @param string $network |
|
29
|
|
|
* @param bool $testnet |
|
30
|
|
|
* @param string $checksum |
|
31
|
|
|
*/ |
|
32
|
9 |
|
public function __construct(BlocktrailSDKInterface $sdk, $identifier, $primaryMnemonic, array $primaryPublicKeys, $backupPublicKey, array $blocktrailPublicKeys, $keyIndex, $network, $testnet, $segwit, $checksum) { |
|
33
|
9 |
|
$this->primaryMnemonic = $primaryMnemonic; |
|
34
|
|
|
|
|
35
|
9 |
|
parent::__construct($sdk, $identifier, $primaryPublicKeys, $backupPublicKey, $blocktrailPublicKeys, $keyIndex, $network, $testnet, $segwit, $checksum); |
|
36
|
|
|
} |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* unlock wallet so it can be used for payments |
|
40
|
|
|
* |
|
41
|
|
|
* @param $options ['primary_private_key' => key] OR ['passphrase' => pass] |
|
42
|
|
|
* @param callable $fn |
|
43
|
|
|
* @return bool |
|
44
|
|
|
* @throws \Exception |
|
45
|
|
|
*/ |
|
46
|
|
|
public function unlock($options, callable $fn = null) { |
|
47
|
|
|
// explode the wallet data |
|
48
|
|
|
$password = isset($options['passphrase']) ? $options['passphrase'] : (isset($options['password']) ? $options['password'] : null); |
|
49
|
|
|
$primaryMnemonic = $this->primaryMnemonic; |
|
50
|
|
|
$primaryPrivateKey = isset($options['primary_private_key']) ? $options['primary_private_key'] : null; |
|
51
|
|
|
|
|
52
|
|
|
if ($primaryMnemonic && $primaryPrivateKey) { |
|
53
|
|
|
throw new \InvalidArgumentException("Can't specify Primary Mnemonic and Primary PrivateKey"); |
|
54
|
|
|
} |
|
55
|
|
|
|
|
56
|
|
|
if (!$primaryMnemonic && !$primaryPrivateKey) { |
|
57
|
|
|
throw new \InvalidArgumentException("Can't init wallet without Primary Mnemonic or Primary PrivateKey"); |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
if ($primaryMnemonic && !$password) { |
|
61
|
|
|
throw new \InvalidArgumentException("Can't init wallet with Primary Mnemonic without a passphrase"); |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
if ($primaryPrivateKey) { |
|
65
|
|
|
if (!($primaryPrivateKey instanceof HierarchicalKey)) { |
|
66
|
|
|
$primaryPrivateKey = HierarchicalKeyFactory::fromExtended($primaryPrivateKey); |
|
67
|
|
|
} |
|
68
|
|
|
} else { |
|
69
|
|
|
// convert the mnemonic to a seed using BIP39 standard |
|
70
|
|
|
$primarySeed = (new Bip39SeedGenerator())->getSeed($primaryMnemonic, $password); |
|
71
|
|
|
// create BIP32 private key from the seed |
|
72
|
|
|
$primaryPrivateKey = HierarchicalKeyFactory::fromEntropy($primarySeed); |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
$this->primaryPrivateKey = BIP32Key::create($primaryPrivateKey, "m"); |
|
76
|
|
|
|
|
77
|
|
|
// create checksum (address) of the primary privatekey to compare to the stored checksum |
|
78
|
|
|
$checksum = $this->primaryPrivateKey->key()->getPublicKey()->getAddress()->getAddress(); |
|
79
|
|
|
if ($checksum != $this->checksum) { |
|
80
|
|
|
throw new \Exception("Checksum [{$checksum}] does not match [{$this->checksum}], most likely due to incorrect password"); |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
$this->locked = false; |
|
84
|
|
|
|
|
85
|
|
|
// if the response suggests we should upgrade to a different blocktrail cosigning key then we should |
|
86
|
|
|
if (isset($data['upgrade_key_index'])) { |
|
|
|
|
|
|
87
|
|
|
$this->upgradeKeyIndex($data['upgrade_key_index']); |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
if ($fn) { |
|
91
|
|
|
$fn($this); |
|
92
|
|
|
$this->lock(); |
|
93
|
|
|
} |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
/** |
|
97
|
|
|
* lock the wallet (unsets primary private key) |
|
98
|
|
|
* |
|
99
|
|
|
* @return void |
|
100
|
|
|
*/ |
|
101
|
|
|
public function lock() { |
|
102
|
|
|
$this->primaryPrivateKey = null; |
|
103
|
|
|
$this->locked = true; |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* change password that is used to store data encrypted on server |
|
108
|
|
|
* |
|
109
|
|
|
* @param $newPassword |
|
110
|
|
|
* @return array backupInfo |
|
111
|
|
|
* @throws NotImplementedException |
|
112
|
|
|
*/ |
|
113
|
|
|
public function passwordChange($newPassword) { |
|
114
|
|
|
throw new NotImplementedException(); |
|
115
|
|
|
} |
|
116
|
|
|
} |
|
117
|
|
|
|
This check looks for calls to
isset(...)orempty()on variables that are yet undefined. These calls will always produce the same result and can be removed.This is most likely caused by the renaming of a variable or the removal of a function/method parameter.