aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/index.html93
-rw-r--r--src/js/bitcoinjs-extensions.js4
-rw-r--r--src/js/index.js167
-rw-r--r--tests.js274
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
34bitcoin.networks.crown = { 34bitcoinjs.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
45bitcoin.networks.dash = { 45bitcoinjs.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 ]
diff --git a/tests.js b/tests.js
index ea29043..b6713b0 100644
--- a/tests.js
+++ b/tests.js
@@ -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
3731function() {
3732page.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
3762function() {
3763page.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
3787function() {
3788page.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
3812function() {
3813page.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
3837function() {
3838page.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
3869function() {
3870page.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
3901function() {
3902page.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
3927function() {
3928page.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)
3953function() {
3954page.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