diff options
-rw-r--r-- | src/index.html | 93 | ||||
-rw-r--r-- | src/js/bitcoinjs-extensions.js | 4 | ||||
-rw-r--r-- | src/js/index.js | 167 | ||||
-rw-r--r-- | tests.js | 274 |
4 files changed, 512 insertions, 26 deletions
diff --git a/src/index.html b/src/index.html index 6a5e644..31e8a2e 100644 --- a/src/index.html +++ b/src/index.html | |||
@@ -282,6 +282,9 @@ | |||
282 | <li id="bip44-tab" class="active"> | 282 | <li id="bip44-tab" class="active"> |
283 | <a href="#bip44" role="tab" data-toggle="tab">BIP44</a> | 283 | <a href="#bip44" role="tab" data-toggle="tab">BIP44</a> |
284 | </li> | 284 | </li> |
285 | <li id="bip49-tab"> | ||
286 | <a href="#bip49" role="tab" data-toggle="tab">BIP49</a> | ||
287 | </li> | ||
285 | </ul> | 288 | </ul> |
286 | <div class="derivation-type tab-content"> | 289 | <div class="derivation-type tab-content"> |
287 | <div id="bip44" class="tab-pane active"> | 290 | <div id="bip44" class="tab-pane active"> |
@@ -435,6 +438,96 @@ | |||
435 | </div> | 438 | </div> |
436 | </form> | 439 | </form> |
437 | </div> | 440 | </div> |
441 | <div id="bip49" class="tab-pane"> | ||
442 | <form class="form-horizontal" role="form"> | ||
443 | <br> | ||
444 | <div class="unavailable hidden"> | ||
445 | <div class="form-group"> | ||
446 | <div class="col-sm-2"></div> | ||
447 | <div class="col-sm-10"> | ||
448 | <p data-translate>BIP49 is unavailable for this coin.</p> | ||
449 | </div> | ||
450 | </div> | ||
451 | </div> | ||
452 | <div class="available"> | ||
453 | <div class="col-sm-2"></div> | ||
454 | <div class="col-sm-10"> | ||
455 | <p data-translate-html> | ||
456 | For more info see the | ||
457 | <a href="https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki" target="_blank">BIP49 spec</a>. | ||
458 | </p> | ||
459 | </div> | ||
460 | <div class="form-group"> | ||
461 | <label for="purpose" class="col-sm-2 control-label"> | ||
462 | <a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#purpose" target="_blank" data-translate>Purpose</a> | ||
463 | </label> | ||
464 | <div class="col-sm-10"> | ||
465 | <input id="purpose" type="text" class="purpose form-control" value="49" readonly> | ||
466 | </div> | ||
467 | </div> | ||
468 | <div class="form-group"> | ||
469 | <label for="coin" class="col-sm-2 control-label"> | ||
470 | <a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#registered-coin-types" target="_blank" data-translate>Coin</a> | ||
471 | </label> | ||
472 | <div class="col-sm-10"> | ||
473 | <input id="coin" type="text" class="coin form-control" value="0" readonly> | ||
474 | </div> | ||
475 | </div> | ||
476 | <div class="form-group"> | ||
477 | <label for="account" class="col-sm-2 control-label"> | ||
478 | <a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account" target="_blank" data-translate>Account</a> | ||
479 | </label> | ||
480 | <div class="col-sm-10"> | ||
481 | <input id="account" type="text" class="account form-control" value="0"> | ||
482 | </div> | ||
483 | </div> | ||
484 | <div class="form-group"> | ||
485 | <label for="change" class="col-sm-2 control-label"> | ||
486 | <a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#change" target="_blank" data-translate>External / Internal</a> | ||
487 | </label> | ||
488 | <div class="col-sm-10"> | ||
489 | <input id="change" type="text" class="change form-control" value="0"> | ||
490 | </div> | ||
491 | </div> | ||
492 | <div class="form-group"> | ||
493 | <label class="col-sm-2 control-label"> | ||
494 | </label> | ||
495 | <div class="col-sm-10"> | ||
496 | <p data-translate>The account extended keys can be used for importing to most BIP49 compatible wallets.</p> | ||
497 | </div> | ||
498 | </div> | ||
499 | <div class="form-group"> | ||
500 | <label for="account-xprv" class="col-sm-2 control-label"> | ||
501 | <span data-translate>Account Extended Private Key</span> | ||
502 | </label> | ||
503 | <div class="col-sm-10"> | ||
504 | <textarea id="account-xprv" type="text" class="account-xprv form-control" readonly data-show-qr></textarea> | ||
505 | </div> | ||
506 | </div> | ||
507 | <div class="form-group"> | ||
508 | <label for="account-xpub" class="col-sm-2 control-label"> | ||
509 | <span data-translate>Account Extended Public Key</span> | ||
510 | </label> | ||
511 | <div class="col-sm-10"> | ||
512 | <textarea id="account-xpub" type="text" class="account-xpub form-control" readonly data-show-qr></textarea> | ||
513 | </div> | ||
514 | </div> | ||
515 | <div class="form-group"> | ||
516 | <label class="col-sm-2 control-label"> | ||
517 | </label> | ||
518 | <div class="col-sm-10"> | ||
519 | <p data-translate>The BIP32 derivation path and extended keys are the basis for the derived addresses.</p> | ||
520 | </div> | ||
521 | </div> | ||
522 | <div class="form-group"> | ||
523 | <label for="bip49-path" class="col-sm-2 control-label" data-translate>BIP32 Derivation Path</label> | ||
524 | <div class="col-sm-10"> | ||
525 | <input id="bip49-path" type="text" class="path form-control" value="m/49'/0'/0'/0" readonly="readonly"> | ||
526 | </div> | ||
527 | </div> | ||
528 | </div> | ||
529 | </form> | ||
530 | </div> | ||
438 | </div> | 531 | </div> |
439 | <form class="form-horizontal" role="form"> | 532 | <form class="form-horizontal" role="form"> |
440 | <div class="form-group"> | 533 | <div class="form-group"> |
diff --git a/src/js/bitcoinjs-extensions.js b/src/js/bitcoinjs-extensions.js index ac2123c..1b40135 100644 --- a/src/js/bitcoinjs-extensions.js +++ b/src/js/bitcoinjs-extensions.js | |||
@@ -31,7 +31,7 @@ bitcoinjs.bitcoin.networks.clam = { | |||
31 | wif: 0x85, | 31 | wif: 0x85, |
32 | }; | 32 | }; |
33 | 33 | ||
34 | bitcoin.networks.crown = { | 34 | bitcoinjs.bitcoin.networks.crown = { |
35 | messagePrefix: "unused", | 35 | messagePrefix: "unused", |
36 | bip32: { | 36 | bip32: { |
37 | public: 0x0488b21e, | 37 | public: 0x0488b21e, |
@@ -42,7 +42,7 @@ bitcoin.networks.crown = { | |||
42 | wif: 0x80, | 42 | wif: 0x80, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | bitcoin.networks.dash = { | 45 | bitcoinjs.bitcoin.networks.dash = { |
46 | messagePrefix: "unused", | 46 | messagePrefix: "unused", |
47 | bip32: { | 47 | bip32: { |
48 | public: 0x0488b21e, | 48 | public: 0x0488b21e, |
diff --git a/src/js/index.js b/src/js/index.js index 763967c..0129808 100644 --- a/src/js/index.js +++ b/src/js/index.js | |||
@@ -47,8 +47,10 @@ | |||
47 | DOM.extendedPubKey = $(".extended-pub-key"); | 47 | DOM.extendedPubKey = $(".extended-pub-key"); |
48 | DOM.bip32tab = $("#bip32-tab"); | 48 | DOM.bip32tab = $("#bip32-tab"); |
49 | DOM.bip44tab = $("#bip44-tab"); | 49 | DOM.bip44tab = $("#bip44-tab"); |
50 | DOM.bip49tab = $("#bip49-tab"); | ||
50 | DOM.bip32panel = $("#bip32"); | 51 | DOM.bip32panel = $("#bip32"); |
51 | DOM.bip44panel = $("#bip44"); | 52 | DOM.bip44panel = $("#bip44"); |
53 | DOM.bip49panel = $("#bip49"); | ||
52 | DOM.bip32path = $("#bip32-path"); | 54 | DOM.bip32path = $("#bip32-path"); |
53 | DOM.bip44path = $("#bip44-path"); | 55 | DOM.bip44path = $("#bip44-path"); |
54 | DOM.bip44purpose = $("#bip44 .purpose"); | 56 | DOM.bip44purpose = $("#bip44 .purpose"); |
@@ -57,6 +59,15 @@ | |||
57 | DOM.bip44accountXprv = $("#bip44 .account-xprv"); | 59 | DOM.bip44accountXprv = $("#bip44 .account-xprv"); |
58 | DOM.bip44accountXpub = $("#bip44 .account-xpub"); | 60 | DOM.bip44accountXpub = $("#bip44 .account-xpub"); |
59 | DOM.bip44change = $("#bip44 .change"); | 61 | DOM.bip44change = $("#bip44 .change"); |
62 | DOM.bip49unavailable = $("#bip49 .unavailable"); | ||
63 | DOM.bip49available = $("#bip49 .available"); | ||
64 | DOM.bip49path = $("#bip49-path"); | ||
65 | DOM.bip49purpose = $("#bip49 .purpose"); | ||
66 | DOM.bip49coin = $("#bip49 .coin"); | ||
67 | DOM.bip49account = $("#bip49 .account"); | ||
68 | DOM.bip49accountXprv = $("#bip49 .account-xprv"); | ||
69 | DOM.bip49accountXpub = $("#bip49 .account-xpub"); | ||
70 | DOM.bip49change = $("#bip49 .change"); | ||
60 | DOM.generatedStrength = $(".generate-container .strength"); | 71 | DOM.generatedStrength = $(".generate-container .strength"); |
61 | DOM.hardenedAddresses = $(".hardened-addresses"); | 72 | DOM.hardenedAddresses = $(".hardened-addresses"); |
62 | DOM.addresses = $(".addresses"); | 73 | DOM.addresses = $(".addresses"); |
@@ -90,6 +101,8 @@ | |||
90 | DOM.bip32path.on("input", calcForDerivationPath); | 101 | DOM.bip32path.on("input", calcForDerivationPath); |
91 | DOM.bip44account.on("input", calcForDerivationPath); | 102 | DOM.bip44account.on("input", calcForDerivationPath); |
92 | DOM.bip44change.on("input", calcForDerivationPath); | 103 | DOM.bip44change.on("input", calcForDerivationPath); |
104 | DOM.bip49account.on("input", calcForDerivationPath); | ||
105 | DOM.bip49change.on("input", calcForDerivationPath); | ||
93 | DOM.tab.on("shown.bs.tab", calcForDerivationPath); | 106 | DOM.tab.on("shown.bs.tab", calcForDerivationPath); |
94 | DOM.hardenedAddresses.on("change", calcForDerivationPath); | 107 | DOM.hardenedAddresses.on("change", calcForDerivationPath); |
95 | DOM.indexToggle.on("click", toggleIndexes); | 108 | DOM.indexToggle.on("click", toggleIndexes); |
@@ -108,8 +121,17 @@ | |||
108 | // Event handlers | 121 | // Event handlers |
109 | 122 | ||
110 | function networkChanged(e) { | 123 | function networkChanged(e) { |
124 | clearDerivedKeys(); | ||
125 | clearAddressesList(); | ||
111 | var networkIndex = e.target.value; | 126 | var networkIndex = e.target.value; |
112 | networks[networkIndex].onSelect(); | 127 | var network = networks[networkIndex]; |
128 | network.onSelect(); | ||
129 | if (network.bip49available) { | ||
130 | showBip49(); | ||
131 | } | ||
132 | else { | ||
133 | hideBip49(); | ||
134 | } | ||
113 | if (seed != null) { | 135 | if (seed != null) { |
114 | phraseChanged(); | 136 | phraseChanged(); |
115 | } | 137 | } |
@@ -252,8 +274,13 @@ | |||
252 | 274 | ||
253 | function calcForDerivationPath() { | 275 | function calcForDerivationPath() { |
254 | showPending(); | 276 | showPending(); |
277 | clearDerivedKeys(); | ||
255 | clearAddressesList(); | 278 | clearAddressesList(); |
256 | hideValidationError(); | 279 | hideValidationError(); |
280 | // Don't show bip49 if it's selected but network doesn't support it | ||
281 | if (bip49TabSelected() && !networkHasBip49()) { | ||
282 | return; | ||
283 | } | ||
257 | // Get the derivation path | 284 | // Get the derivation path |
258 | var derivationPath = getDerivationPath(); | 285 | var derivationPath = getDerivationPath(); |
259 | var errorText = findDerivationPathErrors(derivationPath); | 286 | var errorText = findDerivationPathErrors(derivationPath); |
@@ -265,6 +292,9 @@ | |||
265 | if (bip44TabSelected()) { | 292 | if (bip44TabSelected()) { |
266 | displayBip44Info(); | 293 | displayBip44Info(); |
267 | } | 294 | } |
295 | if (bip49TabSelected()) { | ||
296 | displayBip49Info(); | ||
297 | } | ||
268 | displayBip32Info(); | 298 | displayBip32Info(); |
269 | hidePending(); | 299 | hidePending(); |
270 | } | 300 | } |
@@ -438,6 +468,21 @@ | |||
438 | console.log("Using derivation path from BIP44 tab: " + derivationPath); | 468 | console.log("Using derivation path from BIP44 tab: " + derivationPath); |
439 | return derivationPath; | 469 | return derivationPath; |
440 | } | 470 | } |
471 | if (bip49TabSelected()) { | ||
472 | var purpose = parseIntNoNaN(DOM.bip49purpose.val(), 49); | ||
473 | var coin = parseIntNoNaN(DOM.bip49coin.val(), 0); | ||
474 | var account = parseIntNoNaN(DOM.bip49account.val(), 0); | ||
475 | var change = parseIntNoNaN(DOM.bip49change.val(), 0); | ||
476 | var path = "m/"; | ||
477 | path += purpose + "'/"; | ||
478 | path += coin + "'/"; | ||
479 | path += account + "'/"; | ||
480 | path += change; | ||
481 | DOM.bip49path.val(path); | ||
482 | var derivationPath = DOM.bip49path.val(); | ||
483 | console.log("Using derivation path from BIP49 tab: " + derivationPath); | ||
484 | return derivationPath; | ||
485 | } | ||
441 | else if (bip32TabSelected()) { | 486 | else if (bip32TabSelected()) { |
442 | var derivationPath = DOM.bip32path.val(); | 487 | var derivationPath = DOM.bip32path.val(); |
443 | console.log("Using derivation path from BIP32 tab: " + derivationPath); | 488 | console.log("Using derivation path from BIP32 tab: " + derivationPath); |
@@ -513,6 +558,24 @@ | |||
513 | DOM.bip44accountXpub.val(accountXpub); | 558 | DOM.bip44accountXpub.val(accountXpub); |
514 | } | 559 | } |
515 | 560 | ||
561 | function displayBip49Info() { | ||
562 | // Get the derivation path for the account | ||
563 | var purpose = parseIntNoNaN(DOM.bip49purpose.val(), 49); | ||
564 | var coin = parseIntNoNaN(DOM.bip49coin.val(), 0); | ||
565 | var account = parseIntNoNaN(DOM.bip49account.val(), 0); | ||
566 | var path = "m/"; | ||
567 | path += purpose + "'/"; | ||
568 | path += coin + "'/"; | ||
569 | path += account + "'/"; | ||
570 | // Calculate the account extended keys | ||
571 | var accountExtendedKey = calcBip32ExtendedKey(path); | ||
572 | var accountXprv = accountExtendedKey.toBase58(); | ||
573 | var accountXpub = accountExtendedKey.neutered().toBase58(); | ||
574 | // Display the extended keys | ||
575 | DOM.bip49accountXprv.val(accountXprv); | ||
576 | DOM.bip49accountXpub.val(accountXpub); | ||
577 | } | ||
578 | |||
516 | function displayBip32Info() { | 579 | function displayBip32Info() { |
517 | // Display the key | 580 | // Display the key |
518 | DOM.seed.val(seed); | 581 | DOM.seed.val(seed); |
@@ -555,6 +618,8 @@ | |||
555 | var self = this; | 618 | var self = this; |
556 | this.shouldGenerate = true; | 619 | this.shouldGenerate = true; |
557 | var useHardenedAddresses = DOM.hardenedAddresses.prop("checked"); | 620 | var useHardenedAddresses = DOM.hardenedAddresses.prop("checked"); |
621 | var isBip49 = bip49TabSelected(); | ||
622 | var bip49available = networkHasBip49(); | ||
558 | 623 | ||
559 | function init() { | 624 | function init() { |
560 | calculateValues(); | 625 | calculateValues(); |
@@ -598,6 +663,17 @@ | |||
598 | privkey = convertRipplePriv(privkey); | 663 | privkey = convertRipplePriv(privkey); |
599 | address = convertRippleAdrr(address); | 664 | address = convertRippleAdrr(address); |
600 | } | 665 | } |
666 | // BIP49 addresses are different | ||
667 | if (isBip49) { | ||
668 | if (!bip49available) { | ||
669 | return; | ||
670 | } | ||
671 | var keyhash = bitcoinjs.bitcoin.crypto.hash160(key.getPublicKeyBuffer()); | ||
672 | var scriptsig = bitcoinjs.bitcoin.script.witnessPubKeyHash.output.encode(keyhash); | ||
673 | var addressbytes = bitcoinjs.bitcoin.crypto.hash160(scriptsig); | ||
674 | var scriptpubkey = bitcoinjs.bitcoin.script.scriptHash.output.encode(addressbytes); | ||
675 | address = bitcoinjs.bitcoin.address.fromOutputScript(scriptpubkey, network) | ||
676 | } | ||
601 | addAddressToList(indexText, address, pubkey, privkey); | 677 | addAddressToList(indexText, address, pubkey, privkey); |
602 | }, 50) | 678 | }, 50) |
603 | } | 679 | } |
@@ -1063,145 +1139,188 @@ | |||
1063 | return DOM.bip32tab.hasClass("active"); | 1139 | return DOM.bip32tab.hasClass("active"); |
1064 | } | 1140 | } |
1065 | 1141 | ||
1142 | function networkHasBip49() { | ||
1143 | return networks[DOM.network.val()].bip49available; | ||
1144 | } | ||
1145 | |||
1146 | function bip49TabSelected() { | ||
1147 | return DOM.bip49tab.hasClass("active"); | ||
1148 | } | ||
1149 | |||
1150 | function setHdCoin(coinValue) { | ||
1151 | DOM.bip44coin.val(coinValue); | ||
1152 | DOM.bip49coin.val(coinValue); | ||
1153 | } | ||
1154 | |||
1155 | function showBip49() { | ||
1156 | DOM.bip49unavailable.addClass("hidden"); | ||
1157 | DOM.bip49available.removeClass("hidden"); | ||
1158 | } | ||
1159 | |||
1160 | function hideBip49() { | ||
1161 | DOM.bip49available.addClass("hidden"); | ||
1162 | DOM.bip49unavailable.removeClass("hidden"); | ||
1163 | } | ||
1164 | |||
1066 | var networks = [ | 1165 | var networks = [ |
1067 | { | 1166 | { |
1068 | name: "BTC - Bitcoin", | 1167 | name: "BTC - Bitcoin", |
1168 | bip49available: true, | ||
1069 | onSelect: function() { | 1169 | onSelect: function() { |
1070 | network = bitcoinjs.bitcoin.networks.bitcoin; | 1170 | network = bitcoinjs.bitcoin.networks.bitcoin; |
1071 | DOM.bip44coin.val(0); | 1171 | setHdCoin(0); |
1072 | }, | 1172 | }, |
1073 | }, | 1173 | }, |
1074 | { | 1174 | { |
1075 | name: "BTC - Bitcoin Testnet", | 1175 | name: "BTC - Bitcoin Testnet", |
1176 | bip49available: true, | ||
1076 | onSelect: function() { | 1177 | onSelect: function() { |
1077 | network = bitcoinjs.bitcoin.networks.testnet; | 1178 | network = bitcoinjs.bitcoin.networks.testnet; |
1078 | DOM.bip44coin.val(1); | 1179 | setHdCoin(1); |
1079 | }, | 1180 | }, |
1080 | }, | 1181 | }, |
1081 | { | 1182 | { |
1082 | name: "CLAM - Clams", | 1183 | name: "CLAM - Clams", |
1184 | bip49available: false, | ||
1083 | onSelect: function() { | 1185 | onSelect: function() { |
1084 | network = bitcoinjs.bitcoin.networks.clam; | 1186 | network = bitcoinjs.bitcoin.networks.clam; |
1085 | DOM.bip44coin.val(23); | 1187 | setHdCoin(23); |
1086 | }, | 1188 | }, |
1087 | }, | 1189 | }, |
1088 | { | 1190 | { |
1089 | name: "CRW - Crown", | 1191 | name: "CRW - Crown", |
1192 | bip49available: false, | ||
1090 | onSelect: function() { | 1193 | onSelect: function() { |
1091 | network = bitcoin.networks.crown; | 1194 | network = bitcoinjs.bitcoin.networks.crown; |
1092 | DOM.bip44coin.val(72); | 1195 | setHdCoin(72); |
1093 | }, | 1196 | }, |
1094 | }, | 1197 | }, |
1095 | { | 1198 | { |
1096 | name: "DASH - Dash", | 1199 | name: "DASH - Dash", |
1200 | bip49available: false, | ||
1097 | onSelect: function() { | 1201 | onSelect: function() { |
1098 | network = bitcoinjs.bitcoin.networks.dash; | 1202 | network = bitcoinjs.bitcoin.networks.dash; |
1099 | DOM.bip44coin.val(5); | 1203 | setHdCoin(5); |
1100 | }, | 1204 | }, |
1101 | }, | 1205 | }, |
1102 | { | 1206 | { |
1103 | name: "DASH - Dash Testnet", | 1207 | name: "DASH - Dash Testnet", |
1208 | bip49available: false, | ||
1104 | onSelect: function() { | 1209 | onSelect: function() { |
1105 | network = bitcoinjs.bitcoin.networks.dashtn; | 1210 | network = bitcoinjs.bitcoin.networks.dashtn; |
1106 | DOM.bip44coin.val(1); | 1211 | setHdCoin(1); |
1107 | }, | 1212 | }, |
1108 | }, | 1213 | }, |
1109 | { | 1214 | { |
1110 | name: "DOGE - Dogecoin", | 1215 | name: "DOGE - Dogecoin", |
1216 | bip49available: false, | ||
1111 | onSelect: function() { | 1217 | onSelect: function() { |
1112 | network = bitcoin.networks.dogecoin; | 1218 | network = bitcoinjs.bitcoin.networks.dogecoin; |
1113 | DOM.bip44coin.val(3); | 1219 | setHdCoin(3); |
1114 | }, | 1220 | }, |
1115 | }, | 1221 | }, |
1116 | { | 1222 | { |
1117 | name: "ETH - Ethereum", | 1223 | name: "ETH - Ethereum", |
1224 | bip49available: false, | ||
1118 | onSelect: function() { | 1225 | onSelect: function() { |
1119 | network = bitcoinjs.bitcoin.networks.bitcoin; | 1226 | network = bitcoinjs.bitcoin.networks.bitcoin; |
1120 | DOM.bip44coin.val(60); | 1227 | setHdCoin(60); |
1121 | }, | 1228 | }, |
1122 | }, | 1229 | }, |
1123 | { | 1230 | { |
1124 | name: "GAME - GameCredits", | 1231 | name: "GAME - GameCredits", |
1232 | bip49available: false, | ||
1125 | onSelect: function() { | 1233 | onSelect: function() { |
1126 | network = bitcoinjs.bitcoin.networks.game; | 1234 | network = bitcoinjs.bitcoin.networks.game; |
1127 | DOM.bip44coin.val(101); | 1235 | setHdCoin(101); |
1128 | }, | 1236 | }, |
1129 | }, | 1237 | }, |
1130 | { | 1238 | { |
1131 | name: "JBS - Jumbucks", | 1239 | name: "JBS - Jumbucks", |
1240 | bip49available: false, | ||
1132 | onSelect: function() { | 1241 | onSelect: function() { |
1133 | network = bitcoinjs.bitcoin.networks.jumbucks; | 1242 | network = bitcoinjs.bitcoin.networks.jumbucks; |
1134 | DOM.bip44coin.val(26); | 1243 | setHdCoin(26); |
1135 | }, | 1244 | }, |
1136 | }, | 1245 | }, |
1137 | { | 1246 | { |
1138 | name: "LTC - Litecoin", | 1247 | name: "LTC - Litecoin", |
1248 | bip49available: false, | ||
1139 | onSelect: function() { | 1249 | onSelect: function() { |
1140 | network = bitcoinjs.bitcoin.networks.litecoin; | 1250 | network = bitcoinjs.bitcoin.networks.litecoin; |
1141 | DOM.bip44coin.val(2); | 1251 | setHdCoin(2); |
1142 | }, | 1252 | }, |
1143 | }, | 1253 | }, |
1144 | { | 1254 | { |
1145 | name: "NMC - Namecoin", | 1255 | name: "NMC - Namecoin", |
1256 | bip49available: false, | ||
1146 | onSelect: function() { | 1257 | onSelect: function() { |
1147 | network = bitcoinjs.bitcoin.networks.namecoin; | 1258 | network = bitcoinjs.bitcoin.networks.namecoin; |
1148 | DOM.bip44coin.val(7); | 1259 | setHdCoin(7); |
1149 | }, | 1260 | }, |
1150 | }, | 1261 | }, |
1151 | { | 1262 | { |
1152 | name: "PPC - Peercoin", | 1263 | name: "PPC - Peercoin", |
1264 | bip49available: false, | ||
1153 | onSelect: function() { | 1265 | onSelect: function() { |
1154 | network = bitcoinjs.bitcoin.networks.peercoin; | 1266 | network = bitcoinjs.bitcoin.networks.peercoin; |
1155 | DOM.bip44coin.val(6); | 1267 | setHdCoin(6); |
1156 | }, | 1268 | }, |
1157 | }, | 1269 | }, |
1158 | { | 1270 | { |
1159 | name: "SDC - ShadowCash", | 1271 | name: "SDC - ShadowCash", |
1272 | bip49available: false, | ||
1160 | onSelect: function() { | 1273 | onSelect: function() { |
1161 | network = bitcoinjs.bitcoin.networks.shadow; | 1274 | network = bitcoinjs.bitcoin.networks.shadow; |
1162 | DOM.bip44coin.val(35); | 1275 | setHdCoin(35); |
1163 | }, | 1276 | }, |
1164 | }, | 1277 | }, |
1165 | { | 1278 | { |
1166 | name: "SDC - ShadowCash Testnet", | 1279 | name: "SDC - ShadowCash Testnet", |
1280 | bip49available: false, | ||
1167 | onSelect: function() { | 1281 | onSelect: function() { |
1168 | network = bitcoinjs.bitcoin.networks.shadowtn; | 1282 | network = bitcoinjs.bitcoin.networks.shadowtn; |
1169 | DOM.bip44coin.val(1); | 1283 | setHdCoin(1); |
1170 | }, | 1284 | }, |
1171 | }, | 1285 | }, |
1172 | { | 1286 | { |
1173 | name: "SLM - Slimcoin", | 1287 | name: "SLM - Slimcoin", |
1288 | bip49available: false, | ||
1174 | onSelect: function() { | 1289 | onSelect: function() { |
1175 | network = bitcoinjs.bitcoin.networks.slimcoin; | 1290 | network = bitcoinjs.bitcoin.networks.slimcoin; |
1176 | DOM.bip44coin.val(63); | 1291 | setHdCoin(63); |
1177 | }, | 1292 | }, |
1178 | }, | 1293 | }, |
1179 | { | 1294 | { |
1180 | name: "SLM - Slimcoin Testnet", | 1295 | name: "SLM - Slimcoin Testnet", |
1296 | bip49available: false, | ||
1181 | onSelect: function() { | 1297 | onSelect: function() { |
1182 | network = bitcoinjs.bitcoin.networks.slimcointn; | 1298 | network = bitcoinjs.bitcoin.networks.slimcointn; |
1183 | DOM.bip44coin.val(111); | 1299 | setHdCoin(111); |
1184 | }, | 1300 | }, |
1185 | }, | 1301 | }, |
1186 | { | 1302 | { |
1187 | name: "VIA - Viacoin", | 1303 | name: "VIA - Viacoin", |
1304 | bip49available: false, | ||
1188 | onSelect: function() { | 1305 | onSelect: function() { |
1189 | network = bitcoinjs.bitcoin.networks.viacoin; | 1306 | network = bitcoinjs.bitcoin.networks.viacoin; |
1190 | DOM.bip44coin.val(14); | 1307 | setHdCoin(14); |
1191 | }, | 1308 | }, |
1192 | }, | 1309 | }, |
1193 | { | 1310 | { |
1194 | name: "VIA - Viacoin Testnet", | 1311 | name: "VIA - Viacoin Testnet", |
1312 | bip49available: false, | ||
1195 | onSelect: function() { | 1313 | onSelect: function() { |
1196 | network = bitcoinjs.bitcoin.networks.viacointestnet; | 1314 | network = bitcoinjs.bitcoin.networks.viacointestnet; |
1197 | DOM.bip44coin.val(1); | 1315 | setHdCoin(1); |
1198 | }, | 1316 | }, |
1199 | }, | 1317 | }, |
1200 | { | 1318 | { |
1201 | name: "XRP - Ripple", | 1319 | name: "XRP - Ripple", |
1320 | bip49available: false, | ||
1202 | onSelect: function() { | 1321 | onSelect: function() { |
1203 | network = bitcoin.networks.bitcoin; | 1322 | network = bitcoinjs.bitcoin.networks.bitcoin; |
1204 | DOM.bip44coin.val(144); | 1323 | setHdCoin(144); |
1205 | }, | 1324 | }, |
1206 | } | 1325 | } |
1207 | ] | 1326 | ] |
@@ -3726,6 +3726,280 @@ page.open(url, function(status) { | |||
3726 | }); | 3726 | }); |
3727 | }, | 3727 | }, |
3728 | 3728 | ||
3729 | // BIP49 official test vectors | ||
3730 | // https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki#test-vectors | ||
3731 | function() { | ||
3732 | page.open(url, function(status) { | ||
3733 | // set the phrase and select bitcoin testnet | ||
3734 | var expected = "2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2"; | ||
3735 | page.evaluate(function() { | ||
3736 | $("#bip49-tab a").click(); | ||
3737 | $(".phrase").val("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"); | ||
3738 | $(".network option[selected]").removeAttr("selected"); | ||
3739 | $(".network option").filter(function() { | ||
3740 | return $(this).html() == "BTC - Bitcoin Testnet"; | ||
3741 | }).prop("selected", true); | ||
3742 | $(".network").trigger("change"); | ||
3743 | $(".phrase").trigger("input"); | ||
3744 | }); | ||
3745 | // check the first address | ||
3746 | waitForGenerate(function() { | ||
3747 | var actual = page.evaluate(function() { | ||
3748 | return $(".address:first").text(); | ||
3749 | }); | ||
3750 | if (actual != expected) { | ||
3751 | console.log("BIP49 address is incorrect"); | ||
3752 | console.log("Expected: " + expected); | ||
3753 | console.log("Actual: " + actual); | ||
3754 | fail(); | ||
3755 | } | ||
3756 | next(); | ||
3757 | }); | ||
3758 | }); | ||
3759 | }, | ||
3760 | |||
3761 | // BIP49 derivation path is shown | ||
3762 | function() { | ||
3763 | page.open(url, function(status) { | ||
3764 | // set the phrase | ||
3765 | var expected = "m/49'/0'/0'/0"; | ||
3766 | page.evaluate(function() { | ||
3767 | $("#bip49-tab a").click(); | ||
3768 | $(".phrase").val("abandon abandon ability").trigger("input"); | ||
3769 | }); | ||
3770 | // check the derivation path of the first address | ||
3771 | waitForGenerate(function() { | ||
3772 | var actual = page.evaluate(function() { | ||
3773 | return $("#bip49 .path").val(); | ||
3774 | }); | ||
3775 | if (actual != expected) { | ||
3776 | console.log("BIP49 derivation path is incorrect"); | ||
3777 | console.log("Expected: " + expected); | ||
3778 | console.log("Actual: " + actual); | ||
3779 | fail(); | ||
3780 | } | ||
3781 | next(); | ||
3782 | }); | ||
3783 | }); | ||
3784 | }, | ||
3785 | |||
3786 | // BIP49 extended private key is shown | ||
3787 | function() { | ||
3788 | page.open(url, function(status) { | ||
3789 | // set the phrase | ||
3790 | var expected = "xprvA1hukYsW7QfX9CVsaDAKde4eryajKa4DKWb6m9YjSnqkiZHrahFwwTJfEQTwBQ5kptWT5pZMkkusT1oK8dc1efQ8VFfq4SLSPAWd7Cpt423"; | ||
3791 | page.evaluate(function() { | ||
3792 | $("#bip49-tab a").click(); | ||
3793 | $(".phrase").val("abandon abandon ability").trigger("input"); | ||
3794 | }); | ||
3795 | // check the BIP49 extended private key | ||
3796 | waitForGenerate(function() { | ||
3797 | var actual = page.evaluate(function() { | ||
3798 | return $(".extended-priv-key").val(); | ||
3799 | }); | ||
3800 | if (actual != expected) { | ||
3801 | console.log("BIP49 extended private key is incorrect"); | ||
3802 | console.log("Expected: " + expected); | ||
3803 | console.log("Actual: " + actual); | ||
3804 | fail(); | ||
3805 | } | ||
3806 | next(); | ||
3807 | }); | ||
3808 | }); | ||
3809 | }, | ||
3810 | |||
3811 | // BIP49 extended public key is shown | ||
3812 | function() { | ||
3813 | page.open(url, function(status) { | ||
3814 | // set the phrase | ||
3815 | var expected = "xpub6EhGA4QPwnDpMgaLgEhKzn1PR1RDj2n4gjWhZXxM18NjbMd18EaCVFd95gkLARJaBD2rXAYJED2gdkUbGn1KkrSzCKR554AdABUELoainnt"; | ||
3816 | page.evaluate(function() { | ||
3817 | $("#bip49-tab a").click(); | ||
3818 | $(".phrase").val("abandon abandon ability").trigger("input"); | ||
3819 | }); | ||
3820 | // check the BIP49 extended public key | ||
3821 | waitForGenerate(function() { | ||
3822 | var actual = page.evaluate(function() { | ||
3823 | return $(".extended-pub-key").val(); | ||
3824 | }); | ||
3825 | if (actual != expected) { | ||
3826 | console.log("BIP49 extended public key is incorrect"); | ||
3827 | console.log("Expected: " + expected); | ||
3828 | console.log("Actual: " + actual); | ||
3829 | fail(); | ||
3830 | } | ||
3831 | next(); | ||
3832 | }); | ||
3833 | }); | ||
3834 | }, | ||
3835 | |||
3836 | // BIP49 account field changes address list | ||
3837 | function() { | ||
3838 | page.open(url, function(status) { | ||
3839 | // set the phrase | ||
3840 | var expected = "381wg1GGN4rP88rNC9v7QWsiww63yLVPsn"; | ||
3841 | page.evaluate(function() { | ||
3842 | $("#bip49-tab a").click(); | ||
3843 | $(".phrase").val("abandon abandon ability").trigger("input"); | ||
3844 | }); | ||
3845 | waitForGenerate(function() { | ||
3846 | // change the bip49 account field to 1 | ||
3847 | page.evaluate(function() { | ||
3848 | $("#bip49 .account").val("1"); | ||
3849 | $("#bip49 .account").trigger("input"); | ||
3850 | }); | ||
3851 | waitForGenerate(function() { | ||
3852 | // check the address for the new derivation path | ||
3853 | var actual = page.evaluate(function() { | ||
3854 | return $(".address:first").text(); | ||
3855 | }); | ||
3856 | if (actual != expected) { | ||
3857 | console.log("BIP49 account field generates incorrect address"); | ||
3858 | console.log("Expected: " + expected); | ||
3859 | console.log("Actual: " + actual); | ||
3860 | fail(); | ||
3861 | } | ||
3862 | next(); | ||
3863 | }); | ||
3864 | }); | ||
3865 | }); | ||
3866 | }, | ||
3867 | |||
3868 | // BIP49 change field changes address list | ||
3869 | function() { | ||
3870 | page.open(url, function(status) { | ||
3871 | // set the phrase | ||
3872 | var expected = "3PEM7MiKed5konBoN66PQhK8r3hjGhy9dT"; | ||
3873 | page.evaluate(function() { | ||
3874 | $("#bip49-tab a").click(); | ||
3875 | $(".phrase").val("abandon abandon ability").trigger("input"); | ||
3876 | }); | ||
3877 | waitForGenerate(function() { | ||
3878 | // change the bip49 change field to 1 | ||
3879 | page.evaluate(function() { | ||
3880 | $("#bip49 .change").val("1"); | ||
3881 | $("#bip49 .change").trigger("input"); | ||
3882 | }); | ||
3883 | waitForGenerate(function() { | ||
3884 | // check the address for the new derivation path | ||
3885 | var actual = page.evaluate(function() { | ||
3886 | return $(".address:first").text(); | ||
3887 | }); | ||
3888 | if (actual != expected) { | ||
3889 | console.log("BIP49 change field generates incorrect address"); | ||
3890 | console.log("Expected: " + expected); | ||
3891 | console.log("Actual: " + actual); | ||
3892 | fail(); | ||
3893 | } | ||
3894 | next(); | ||
3895 | }); | ||
3896 | }); | ||
3897 | }); | ||
3898 | }, | ||
3899 | |||
3900 | // BIP49 account extendend private key is shown | ||
3901 | function() { | ||
3902 | page.open(url, function(status) { | ||
3903 | // set the phrase | ||
3904 | var expected = "xprv9y3uhgQbfQZbj3o98nfgLDwGGuCJjUn7GKArSAZXjKgMjSdYHjQmTyf78s22g6jsGrxXvHB6HJeFyvFSPkuYZajeTGMZVXV6aNLWw2fagCn"; | ||
3905 | page.evaluate(function() { | ||
3906 | $("#bip49-tab a").click(); | ||
3907 | $(".phrase").val("abandon abandon ability"); | ||
3908 | $(".phrase").trigger("input"); | ||
3909 | }); | ||
3910 | // check the BIP49 account extended private key | ||
3911 | waitForGenerate(function() { | ||
3912 | var actual = page.evaluate(function() { | ||
3913 | return $("#bip49 .account-xprv").val(); | ||
3914 | }); | ||
3915 | if (actual != expected) { | ||
3916 | console.log("BIP49 account extended private key is incorrect"); | ||
3917 | console.log("Expected: " + expected); | ||
3918 | console.log("Actual: " + actual); | ||
3919 | fail(); | ||
3920 | } | ||
3921 | next(); | ||
3922 | }); | ||
3923 | }); | ||
3924 | }, | ||
3925 | |||
3926 | // BIP49 account extendend public key is shown | ||
3927 | function() { | ||
3928 | page.open(url, function(status) { | ||
3929 | // set the phrase | ||
3930 | var expected = "xpub6C3G7BwVVn7twXscEpCghMszpw2o8wVxdY6TEYy9HfDLcExgqGj21myazAiq6HSmW2F1cBiFqJa3D1cqcDpSh8pbZF5x4iqpd4PyJvd3gjB"; | ||
3931 | page.evaluate(function() { | ||
3932 | $("#bip49-tab a").click(); | ||
3933 | $(".phrase").val("abandon abandon ability"); | ||
3934 | $(".phrase").trigger("input"); | ||
3935 | }); | ||
3936 | // check the BIP49 account extended public key | ||
3937 | waitForGenerate(function() { | ||
3938 | var actual = page.evaluate(function() { | ||
3939 | return $("#bip49 .account-xpub").val(); | ||
3940 | }); | ||
3941 | if (actual != expected) { | ||
3942 | console.log("BIP49 account extended public key is incorrect"); | ||
3943 | console.log("Expected: " + expected); | ||
3944 | console.log("Actual: " + actual); | ||
3945 | fail(); | ||
3946 | } | ||
3947 | next(); | ||
3948 | }); | ||
3949 | }); | ||
3950 | }, | ||
3951 | |||
3952 | // Test selecting coin where bip49 is unavailable (eg CLAM) | ||
3953 | function() { | ||
3954 | page.open(url, function(status) { | ||
3955 | // set the phrase | ||
3956 | page.evaluate(function() { | ||
3957 | $("#bip49-tab a").click(); | ||
3958 | $(".phrase").val("abandon abandon ability"); | ||
3959 | $(".phrase").trigger("input"); | ||
3960 | }); | ||
3961 | waitForGenerate(function() { | ||
3962 | // select non-bip49 network, ie CLAM network | ||
3963 | page.evaluate(function() { | ||
3964 | $(".network option[selected]").removeAttr("selected"); | ||
3965 | $(".network option").filter(function() { | ||
3966 | return $(this).html() == "CLAM - Clams"; | ||
3967 | }).prop("selected", true); | ||
3968 | $(".network").trigger("change"); | ||
3969 | }); | ||
3970 | // check the BIP49 error is shown | ||
3971 | var bip49ErrorShown = page.evaluate(function() { | ||
3972 | var bip49hidden = $("#bip49 .available").hasClass("hidden"); | ||
3973 | bip49hidden = bip49hidden && !($("#bip49 .unavailable").hasClass("hidden")); | ||
3974 | return bip49hidden; | ||
3975 | }); | ||
3976 | if (!bip49ErrorShown) { | ||
3977 | console.log("BIP49 error not shown for non-bip49 network"); | ||
3978 | fail(); | ||
3979 | } | ||
3980 | // check there are no addresses shown | ||
3981 | var addressCount = page.evaluate(function() { | ||
3982 | return $(".address").length; | ||
3983 | }); | ||
3984 | if (addressCount != 0) { | ||
3985 | console.log("BIP49 address count for non-bip49 network is " + addressCount); | ||
3986 | fail(); | ||
3987 | } | ||
3988 | // check the derived keys are blank | ||
3989 | var areBlank = page.evaluate(function() { | ||
3990 | var prvKeyIsBlank = $(".extended-priv-key").val().length == 0; | ||
3991 | var pubKeyIsBlank = $(".extended-pub-key").val().length == 0; | ||
3992 | return prvKeyIsBlank && pubKeyIsBlank; | ||
3993 | }); | ||
3994 | if (!areBlank) { | ||
3995 | console.log("BIP49 extended keys for non-bip49 network are not blank "); | ||
3996 | fail(); | ||
3997 | } | ||
3998 | next(); | ||
3999 | }); | ||
4000 | }); | ||
4001 | }, | ||
4002 | |||
3729 | // If you wish to add more tests, do so here... | 4003 | // If you wish to add more tests, do so here... |
3730 | 4004 | ||
3731 | // Here is a blank test template | 4005 | // Here is a blank test template |