+ if (entropyText.indexOf("dice") == -1) {
+ console.log("Dice entropy is not detected and presented to user");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Base 10 entropy can be entered
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("789").trigger("input");
+ });
+ // check the entropy is shown to be the correct type
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("base 10") == -1) {
+ console.log("Base 10 entropy is not detected and presented to user");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Hexadecimal entropy can be entered
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("abcdef").trigger("input");
+ });
+ // check the entropy is shown to be the correct type
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("hexadecimal") == -1) {
+ console.log("Hexadecimal entropy is not detected and presented to user");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Dice entropy value is shown as the converted base 6 value
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("123456").trigger("input");
+ });
+ // check the entropy is shown as base 6, not as the original dice value
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("123450") == -1) {
+ console.log("Dice entropy is not shown to user as base 6 value");
+ fail();
+ }
+ if (entropyText.indexOf("123456") > -1) {
+ console.log("Dice entropy value is shown instead of true base 6 value");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// The number of bits of entropy accumulated is shown
+function() {
+page.open(url, function(status) {
+ //[ entropy, bits ]
+ var tests = [
+ [ "0000 0000 0000 0000 0000", "20" ],
+ [ "0", "1" ],
+ [ "0000", "4" ],
+ [ "6", "2" ], // 6 in card is 0 in base 6, 0 in base 6 is 2.6 bits (rounded down to 2 bits)
+ [ "7", "3" ], // 7 in base 10 is 111 in base 2, no leading zeros
+ [ "8", "4" ],
+ [ "F", "4" ],
+ [ "29", "6" ],
+ [ "0A", "8" ],
+ [ "1A", "8" ], // hex is always multiple of 4 bits of entropy
+ [ "2A", "8" ],
+ [ "4A", "8" ],
+ [ "8A", "8" ],
+ [ "FA", "8" ],
+ [ "000A", "16" ],
+ [ "5555", "11" ],
+ [ "6666", "10" ], // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of 2.58 bits, which is 10.32 bits (rounded down to 10 bits)
+ [ "2227", "13" ], // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded down to 13)
+ [ "222F", "16" ],
+ [ "FFFF", "16" ],
+ [ "0000101017", "33" ], // 10 events at 3.32 bits per event
+ [ "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "225" ], // cards are not replaced, so a full deck is not 52^52 entropy which is 296 bits, it's 52!, which is 225 bits
+ ]
+ // use entropy
+ page.evaluate(function(e) {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ });
+ // Run each test
+ var nextTest = function runNextTest(i) {
+ var entropy = tests[i][0];
+ var expected = tests[i][1];
+ // set entropy
+ page.evaluate(function(e) {
+ $(".entropy").val(e).trigger("input");
+ }, entropy);
+ // check the number of bits of entropy is shown
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.replace(/\s/g,"").indexOf("Bits" + expected) == -1) {
+ console.log("Accumulated entropy is not shown correctly for " + entropy);
+ fail();
+ }
+ var isLastTest = i == tests.length - 1;
+ if (isLastTest) {
+ next();
+ }
+ else {
+ runNextTest(i+1);
+ }
+ });
+ }
+ nextTest(0);
+});
+},
+
+// There is feedback provided about the supplied entropy
+function() {
+page.open(url, function(status) {
+ var tests = [
+ {
+ entropy: "A",
+ filtered: "A",
+ type: "hexadecimal",
+ events: 1,
+ bits: 4,
+ words: 0,
+ strength: "less than a second",
+ },
+ {
+ entropy: "AAAAAAAA",
+ filtered: "AAAAAAAA",
+ type: "hexadecimal",
+ events: 8,
+ bits: 32,
+ words: 3,
+ strength: "less than a second - Repeats like \"aaa\" are easy to guess",
+ },
+ {
+ entropy: "AAAAAAAA B",
+ filtered: "AAAAAAAAB",
+ type: "hexadecimal",
+ events: 9,
+ bits: 36,
+ words: 3,
+ strength: "less than a second - Repeats like \"aaa\" are easy to guess",
+ },
+ {
+ entropy: "AAAAAAAA BBBBBBBB",
+ filtered: "AAAAAAAABBBBBBBB",
+ type: "hexadecimal",
+ events: 16,
+ bits: 64,
+ words: 6,
+ strength: "less than a second - Repeats like \"aaa\" are easy to guess",
+ },
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCC",
+ type: "hexadecimal",
+ events: 24,
+ bits: 96,
+ words: 9,
+ strength: "less than a second",
+ },
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD",
+ type: "hexadecimal",
+ events: 32,
+ bits: 128,
+ words: 12,
+ strength: "2 minutes",
+ },
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDA",
+ type: "hexadecimal",
+ events: 32,
+ bits: 128,
+ words: 12,
+ strength: "2 days",
+ },
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEE",
+ type: "hexadecimal",
+ events: 40,
+ bits: 160,
+ words: 15,
+ strength: "3 years",
+ },
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE FFFFFFFF",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEEFFFFFFFF",
+ type: "hexadecimal",
+ events: 48,
+ bits: 192,
+ words: 18,
+ strength: "centuries",
+ },
+ {
+ entropy: "7d",
+ type: "card",
+ events: 1,
+ bits: 5,
+ words: 0,
+ strength: "less than a second",
+ },
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (full deck)",
+ events: 52,
+ bits: 225,
+ words: 21,
+ strength: "centuries",
+ },
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d",
+ type: "card (full deck, 1 duplicate: 3d)",
+ events: 53,
+ bits: 254,
+ words: 21,
+ strength: "centuries",
+ },
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d",
+ type: "card (2 duplicates: 3d 4d, 1 missing: KS)",
+ events: 53,
+ bits: 254,
+ words: 21,
+ strength: "centuries",
+ },
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d",
+ type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)",
+ events: 53,
+ bits: 264,
+ words: 24,
+ strength: "centuries",
+ },
+ // Next test was throwing uncaught error in zxcvbn
+ // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (full deck, 52 duplicates: ac 2c 3c...)",
+ events: 104,
+ bits: 499,
+ words: 45,
+ strength: "centuries",
+ },
+ // Case insensitivity to duplicate cards
+ {
+ entropy: "asAS",
+ type: "card (1 duplicate: AS)",
+ events: 2,
+ bits: 9,
+ words: 0,
+ strength: "less than a second",
+ },
+ {
+ entropy: "ASas",
+ type: "card (1 duplicate: as)",
+ events: 2,
+ bits: 9,
+ words: 0,
+ strength: "less than a second",
+ },
+ // Missing cards are detected
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (1 missing: 9C)",
+ events: 51,
+ bits: 221,
+ words: 18,
+ strength: "centuries",
+ },
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (2 missing: 9C 5D)",
+ events: 50,
+ bits: 216,
+ words: 18,
+ strength: "centuries",
+ },
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (4 missing: 9C 5D QD...)",
+ events: 48,
+ bits: 208,
+ words: 18,
+ strength: "centuries",
+ },
+ // More than six missing cards does not show message
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card",
+ events: 45,
+ bits: 195,
+ words: 18,
+ strength: "centuries",
+ },
+ // Multiple decks of cards increases bits per event
+ {
+ entropy: "3d",
+ events: 1,
+ bits: 4,
+ bitsPerEvent: 4.34,
+ },
+ {
+ entropy: "3d3d",
+ events: 2,
+ bits: 9,
+ bitsPerEvent: 4.80,
+ },
+ {
+ entropy: "3d3d3d",
+ events: 3,
+ bits: 15,
+ bitsPerEvent: 5.01,
+ },
+ {
+ entropy: "3d3d3d3d",
+ events: 4,
+ bits: 20,
+ bitsPerEvent: 5.14,
+ },
+ {
+ entropy: "3d3d3d3d3d",
+ events: 5,
+ bits: 26,
+ bitsPerEvent: 5.22,
+ },
+ {
+ entropy: "3d3d3d3d3d3d",
+ events: 6,
+ bits: 31,
+ bitsPerEvent: 5.28,
+ },
+ {
+ entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d",
+ events: 33,
+ bits: 184,
+ bitsPerEvent: 5.59,
+ strength: 'less than a second - Repeats like "abcabcabc" are only slightly harder to guess than "abc"',
+ },
+ ];
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ });
+ var nextTest = function runNextTest(i) {
+ function getFeedbackError(expected, actual) {
+ if ("filtered" in expected && actual.indexOf(expected.filtered) == -1) {
+ return "Filtered value not in feedback";
+ }
+ if ("type" in expected && actual.indexOf(expected.type) == -1) {
+ return "Entropy type not in feedback";
+ }
+ if ("events" in expected && actual.indexOf(expected.events) == -1) {
+ return "Event count not in feedback";
+ }
+ if ("bits" in expected && actual.indexOf(expected.bits) == -1) {
+ return "Bit count not in feedback";
+ }
+ if ("strength" in expected && actual.indexOf(expected.strength) == -1) {
+ return "Strength not in feedback";
+ }
+ if ("bitsPerEvent" in expected && actual.indexOf(expected.bitsPerEvent) == -1) {
+ return "bitsPerEvent not in feedback";
+ }
+ return false;
+ }
+ test = tests[i];
+ page.evaluate(function(e) {
+ $(".addresses").empty();
+ $(".phrase").val("");
+ $(".entropy").val(e).trigger("input");
+ }, test.entropy);
+ waitForEntropyFeedback(function() {
+ var mnemonic = page.evaluate(function() {
+ return $(".phrase").val();
+ });
+ // Check mnemonic length
+ if ("words" in test && test.words == 0) {
+ if (mnemonic.length > 0) {
+ console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
+ console.log("Entropy: " + test.entropy);
+ console.log("Mnemonic: " + mnemonic);
+ fail();
+ }
+ }
+ else if ("words" in test) {
+ if (mnemonic.split(" ").length != test.words) {
+ console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
+ console.log("Entropy: " + test.entropy);
+ console.log("Mnemonic: " + mnemonic);
+ fail();
+ }
+ }
+ // check feedback
+ var feedback = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ var feedbackError = getFeedbackError(test, feedback);
+ if (feedbackError) {
+ console.log("Entropy feedback for " + test.entropy + " returned error");
+ console.log(feedbackError);
+ fail();
+ }
+ // Run next test
+ var isLastTest = i == tests.length - 1;
+ if (isLastTest) {
+ next();
+ }
+ else {
+ runNextTest(i+1);
+ }
+ });
+ }
+ nextTest(0);
+});
+},
+
+// Entropy is truncated from the left
+function() {
+page.open(url, function(status) {
+ var expected = "avocado zoo zone";
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ var entropy = "00000000 00000000 00000000 00000000";
+ entropy += "11111111 11111111 11111111 1111"; // Missing last byte
+ $(".entropy").val(entropy).trigger("input");
+ });
+ // check the entropy is truncated from the right
+ waitForGenerate(function() {
+ var actual = page.evaluate(function() {
+ return $(".phrase").val();
+ });
+ if (actual != expected) {
+ console.log("Entropy is not truncated from the right");
+ console.log("Expected: " + expected);
+ console.log("Got: " + actual);
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Very large entropy results in very long mnemonics
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ var entropy = "";
+ // Generate a very long entropy string
+ for (var i=0; i<33; i++) {
+ entropy += "AAAAAAAA"; // 3 words * 33 iterations = 99 words
+ }
+ $(".entropy").val(entropy).trigger("input");
+ });
+ // check the mnemonic is very long
+ waitForGenerate(function() {
+ var wordCount = page.evaluate(function() {
+ return $(".phrase").val().split(" ").length;
+ });
+ if (wordCount != 99) {
+ console.log("Large entropy does not generate long mnemonic");
+ console.log("Expected 99 words, got " + wordCount);
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Is compatible with bip32jp entropy
+// https://bip32jp.github.io/english/index.html
+// NOTES:
+// Is incompatible with:
+// base 20
+function() {
+page.open(url, function(status) {
+ var expected = "train then jungle barely whip fiber purpose puppy eagle cloud clump hospital robot brave balcony utility detect estate old green desk skill multiply virus";
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ var entropy = "543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543";
+ $(".entropy").val(entropy).trigger("input");
+ });
+ // check the mnemonic matches the expected value from bip32jp
+ waitForGenerate(function() {
+ var actual = page.evaluate(function() {
+ return $(".phrase").val();
+ });
+ if (actual != expected) {
+ console.log("Mnemonic does not match bip32jp for base 6 entropy");
+ console.log("Expected: " + expected);
+ console.log("Got: " + actual);
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Blank entropy does not generate mnemonic or addresses
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("").trigger("input");
+ });
+ waitForFeedback(function() {
+ // check there is no mnemonic
+ var phrase = page.evaluate(function() {
+ return $(".phrase").val();
+ });
+ if (phrase != "") {
+ console.log("Blank entropy does not result in blank mnemonic");
+ console.log("Got: " + phrase);
+ fail();
+ }
+ // check there are no addresses displayed
+ var addresses = page.evaluate(function() {
+ return $(".address").length;
+ });
+ if (addresses != 0) {
+ console.log("Blank entropy does not result in zero addresses");
+ fail();
+ }
+ // Check the feedback says 'blank entropy'
+ var feedback = page.evaluate(function() {
+ return $(".feedback").text();
+ });
+ if (feedback != "Blank entropy") {
+ console.log("Blank entropy does not show feedback message");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Mnemonic length can be selected even for weak entropy
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("012345");
+ $(".mnemonic-length").val("18").trigger("change");
+ });
+ // check the mnemonic is the correct length
+ waitForGenerate(function() {
+ var phrase = page.evaluate(function() {
+ return $(".phrase").val();
+ });
+ var numberOfWords = phrase.split(/\s/g).length;
+ if (numberOfWords != 18) {
+ console.log("Weak entropy cannot be overridden to give 18 word mnemonic");
+ console.log(phrase);
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Github issue 33
+// https://github.com/iancoleman/bip39/issues/33
+// Final cards should contribute entropy
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-6C TS TH 4H KC 5H 2H AH 2C 8D 3H 5D").trigger("input");
+ });
+ // get the mnemonic
+ waitForGenerate(function() {
+ var originalPhrase = page.evaluate(function() {
+ return $(".phrase").val();
+ });
+ // Set the last 12 cards to be AS
+ page.evaluate(function() {
+ $(".addresses").empty();
+ $(".entropy").val("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-AS AS AS AS AS AS AS AS AS AS AS AS").trigger("input");
+ });
+ // get the new mnemonic
+ waitForGenerate(function() {
+ var newPhrase = page.evaluate(function() {
+ return $(".phrase").val();
+ });
+ // check the phrase has changed
+ if (newPhrase == originalPhrase) {
+ console.log("Changing last 12 cards does not change mnemonic");
+ console.log("Original:");
+ console.log(originalPhrase);
+ console.log("New:");
+ console.log(newPhrase);
+ fail();
+ }
+ next();
+ });
+ });
+});
+},
+
+// Github issue 35
+// https://github.com/iancoleman/bip39/issues/35
+// QR Code support
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".generate").click();
+ });
+ waitForGenerate(function() {
+ var p = page.evaluate(function() {
+ // get position of mnemonic element
+ return $(".phrase").offset();
+ });
+ p.top = Math.ceil(p.top);
+ p.left = Math.ceil(p.left);
+ // check the qr code shows
+ page.sendEvent("mousemove", p.left+4, p.top+4);
+ var qrShowing = page.evaluate(function() {
+ return $(".qr-container").find("canvas").length > 0;
+ });
+ if (!qrShowing) {
+ console.log("QR Code does not show");
+ fail();
+ }
+ // check the qr code hides
+ page.sendEvent("mousemove", p.left-4, p.top-4);
+ var qrHidden = page.evaluate(function() {
+ return $(".qr-container").find("canvas").length == 0;
+ });
+ if (!qrHidden) {
+ console.log("QR Code does not hide");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// BIP44 account extendend private key is shown
+// github issue 37 - compatibility with electrum
+function() {
+page.open(url, function(status) {
+ // set the phrase
+ var expected = "xprv9yzrnt4zWVJUr1k2VxSPy9ettKz5PpeDMgaVG7UKedhqnw1tDkxP2UyYNhuNSumk2sLE5ctwKZs9vwjsq3e1vo9egCK6CzP87H2cVYXpfwQ";
+ page.evaluate(function() {
+ $(".phrase").val("abandon abandon ability");
+ $(".phrase").trigger("input");
+ });
+ // check the BIP44 account extended private key
+ waitForGenerate(function() {
+ var actual = page.evaluate(function() {
+ return $("#bip44 .account-xprv").val();
+ });
+ if (actual != expected) {
+ console.log("BIP44 account extended private key is incorrect");
+ console.log("Expected: " + expected);
+ console.log("Actual: " + actual);
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// BIP44 account extendend public key is shown
+// github issue 37 - compatibility with electrum
+function() {
+page.open(url, function(status) {
+ // set the phrase
+ var expected = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
+ page.evaluate(function() {
+ $(".phrase").val("abandon abandon ability");
+ $(".phrase").trigger("input");
+ });
+ // check the BIP44 account extended public key
+ waitForGenerate(function() {
+ var actual = page.evaluate(function() {
+ return $("#bip44 .account-xpub").val();
+ });
+ if (actual != expected) {
+ console.log("BIP44 account extended public key is incorrect");
+ console.log("Expected: " + expected);
+ console.log("Actual: " + actual);
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// github issue 40
+// BIP32 root key can be set as an xpub
+function() {
+page.open(url, function(status) {
+ // set the phrase
+ page.evaluate(function() {
+ // set xpub for account 0 of bip44 for 'abandon abandon ability'
+ var bip44AccountXpub = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
+ $("#root-key").val(bip44AccountXpub);
+ $("#root-key").trigger("input");
+ });
+ waitForFeedback(function() {
+ page.evaluate(function() {
+ // Use bip32 tab
+ $("#bip32-tab a").click();
+ });
+ waitForGenerate(function() {
+ page.evaluate(function() {
+ // derive external addresses for this xpub
+ var firstAccountDerivationPath = "m/0";
+ $("#bip32-path").val(firstAccountDerivationPath);
+ $("#bip32-path").trigger("input");
+ });
+ waitForGenerate(function() {
+ // check the addresses are generated
+ var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
+ var actual = page.evaluate(function() {
+ return $(".address:first").text();
+ });
+ if (actual != expected) {
+ console.log("xpub key does not generate addresses in table");
+ console.log("Expected: " + expected);
+ console.log("Actual: " + actual);
+ fail();
+ }
+ // check the xprv key is not set
+ var expected = "NA";
+ var actual = page.evaluate(function() {
+ return $(".extended-priv-key").val();
+ });
+ if (actual != expected) {
+ console.log("xpub key as root shows derived bip32 xprv key");
+ console.log("Expected: " + expected);
+ console.log("Actual: " + actual);
+ fail();
+ }
+ // check the private key is not set
+ var expected = "NA";
+ var actual = page.evaluate(function() {
+ return $(".privkey:first").text();
+ });
+ if (actual != expected) {
+ console.log("xpub key generates private key in addresses table");
+ console.log("Expected: " + expected);
+ console.log("Actual: " + actual);
+ fail();
+ }
+ next();
+ });
+ });