All files / ethers.js/src.ts/_tests test-wallet-hd.ts

96.64% Statements 144/149
96.15% Branches 25/26
100% Functions 3/3
96.64% Lines 144/149

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 1501x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 800x 800x 800x 800x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 10800x 10800x 10800x 10800x 10800x 10800x 10800x 10800x 7200x 7200x 7200x 10800x 3600x 3600x 10800x 1x 1x 1x 1x 1x 400x 400x 400x 400x 400x 400x           400x 400x 400x 400x 2400x 2400x 2400x 2400x 2400x 2400x 400x 400x 400x 400x 1x 1x 1x 400x 400x 2400x 2400x 2400x 2400x 2400x 2400x 2400x 400x 400x 1x 1x 400x 400x 400x 2400x 2400x 2400x 2400x 2400x 2400x 400x 400x 1x 1x 400x 400x 2400x 2400x 2400x 2400x 2400x 400x 400x 1x 1x 400x 400x 400x 2400x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 1200x 2400x 400x 400x 1x 1x 400x 400x 2400x 2400x 2400x 2400x 400x 400x 1x  
 
import assert from "assert";
 
import { loadTests } from "./utils.js";
 
import {
    getBytes, wordlists,
    HDNodeWallet, HDNodeVoidWallet, Mnemonic
} from "../index.js";
 
import type { Wordlist } from "../wordlists/index.js";
 
import type { TestCaseMnemonic, TestCaseMnemonicNode } from "./types.js";
 
 
const decoder = new TextDecoder();
function fromHex(hex: string): string {
    const data = getBytes(hex);
    return decoder.decode(data);
}
 
type Test = {
    phrase: string;
    password: string;
    wordlist: Wordlist;
    mnemonic: Mnemonic;
    checkMnemonic: (a: Mnemonic) => void;
    test: TestCaseMnemonic;
};
 
describe("Test HDWallets", function() {
    function checkWallet(wallet: HDNodeWallet | HDNodeVoidWallet, test: TestCaseMnemonicNode): void {
        assert.equal(wallet.chainCode, test.chainCode, "chainCode");
        assert.equal(wallet.depth, test.depth, "depth");
        assert.equal(wallet.index, test.index, "index");
        assert.equal(wallet.fingerprint, test.fingerprint, "fingerprint");
        assert.equal(wallet.parentFingerprint, test.parentFingerprint, "parentFingerprint");
        assert.equal(wallet.publicKey, test.publicKey, "publicKey");
 
        if (wallet instanceof HDNodeWallet) {
            assert.equal(wallet.extendedKey, test.xpriv, "xpriv");
            assert.equal(wallet.privateKey, test.privateKey, "privateKey");
            assert.equal(wallet.neuter().extendedKey, test.xpub, "xpub");
        } else if (wallet instanceof HDNodeVoidWallet) {
            assert.equal(wallet.extendedKey, test.xpub, "xpub");
        }
    }
 
    const tests = loadTests<TestCaseMnemonic>("mnemonics");
 
    const checks: Array<Test> = [ ];
    tests.forEach((test) => {
        // The phrase and password are stored in the test as hex so they
        // are safe as ascii7 values for viewing, printing, etc.
        const phrase = fromHex(test.phrase);
        const password = fromHex(test.password);
        const wordlist = wordlists[test.locale];
        if (wordlist == null) {
            it(`tests ${ test.name }`, function() {
                this.skip();
            });
            return;
        }
 
        const mnemonic = Mnemonic.fromPhrase(phrase, password, wordlist);
 
        function checkMnemonic(actual: Mnemonic): void {
            assert.equal(actual.phrase, phrase, "phrase");
            assert.equal(actual.password, password, "password");
            assert.equal(actual.wordlist.locale, test.locale, "locale");
            assert.equal(actual.entropy, mnemonic.entropy, "entropy");
            assert.equal(actual.computeSeed(), mnemonic.computeSeed(), "seed");
        }
 
        checks.push({
            phrase, password, wordlist, mnemonic, checkMnemonic, test
        });
    });
 
    for (const { test, checkMnemonic, phrase, password, wordlist } of checks) {
        it(`computes the HD keys by mnemonic: ${ test.name }`, function() {
            for (const subtest of test.nodes) {
                const w = HDNodeWallet.fromPhrase(phrase, password, subtest.path, wordlist);
                assert.ok(w instanceof HDNodeWallet, "instanceof HDNodeWallet");
                assert.equal(w.path, subtest.path, "path")
                checkWallet(w, subtest);
                assert.ok(!!w.mnemonic, "has mnemonic");
                checkMnemonic(w.mnemonic as Mnemonic);
            }
        });
    }
 
    for (const { test } of checks) {
        it(`computes the HD keys by entropy: ${ test.name }`, function() {
            const seedRoot = HDNodeWallet.fromSeed(test.seed);
            for (const subtest of test.nodes) {
                const w = seedRoot.derivePath(subtest.path);
                assert.ok(w instanceof HDNodeWallet, "instanceof HDNodeWallet");
                assert.equal(w.path, subtest.path, "path")
                checkWallet(w, subtest);
                assert.equal(w.mnemonic, null);
            }
        });
    }
 
    for (const { test } of checks) {
        it(`computes the HD keys by enxtended private key: ${ test.name }`, function() {
            for (const subtest of test.nodes) {
                const w = HDNodeWallet.fromExtendedKey(subtest.xpriv);
                assert.ok(w instanceof HDNodeWallet, "instanceof HDNodeWallet");
                checkWallet(w, subtest);
                assert.equal(w.mnemonic, null);
            }
        });
    }
 
    for (const { test, phrase, password, wordlist } of checks) {
        it(`computes the neutered HD keys by paths: ${ test.name }`, function() {
            const root = HDNodeWallet.fromPhrase(phrase, password, "m", wordlist).neuter();
            for (const subtest of test.nodes) {
                if (subtest.path.indexOf("'") >= 0) {
                    assert.throws(() => {
                        const w = root.derivePath(subtest.path);
                        console.log(w);
                    }, (error: any) => {
                        return (error.code === "UNSUPPORTED_OPERATION" &&
                            error.message.match(/^cannot derive child of neutered node/) &&
                            error.operation === "deriveChild");
                    });
                } else {
                    const w = root.derivePath(subtest.path);
                    assert.ok(w instanceof HDNodeVoidWallet, "instanceof HDNodeVoidWallet");
                    assert.equal(w.path, subtest.path, "path")
                    checkWallet(w, subtest);
                }
            }
        });
    }
 
    for (const { test } of checks) {
        it(`computes the neutered HD keys by enxtended public key: ${ test.name }`, function() {
            for (const subtest of test.nodes) {
                const w = HDNodeWallet.fromExtendedKey(subtest.xpub);
                assert.ok(w instanceof HDNodeVoidWallet, "instanceof HDNodeVoidWallet");
                checkWallet(w, subtest);
            }
        });
    }
});