Open glethuillier opened 2 years ago
I don't know anything about ethereum, but:
Does ethereum have test vectors, or do you have any other "knowns", that you can force into the different steps in your script?
Try adding a debug mode that prints out forced-ascii (like bash cat -A) or hashes or lengths or similar of every input and output of every command line. (Could be something as dumb as unexpected whitespace hiding in a bad copy/paste of a the mnemonic.)
Does the order of the "import" statements matter?
Thank you @petjal.
mnemonic → xpub
, as far as Ethereum is concerned).myth like bonus scare over problem client lizard pioneer submit female collect
⇩
xpub6GkCbW4FDnz8k9zhroVhZefi9fXhFFuTmmcQqfQKPDBrQjtSu4pdLpQ1Tje1BAzUw6PbJ47MMtNZ4RYM42VzRNxwaYUFnm3R44Lejvh9nHE
(xpub generated by the script but not by the Mnemonic Code Converter)
⇩
0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1
(address derived by both script and Mnemonic Code Converter)
Source code of the script generating the xpub and the address from the mnemonic:
import * as ethers from "ethers";
import * as bip39 from "bip39";
import HDKey from "hdkey";
import { HDNode } from "@findeth/hdnode";
import Wallet from "ethereumjs-wallet";
import * as assert from "assert";
const mnemonic =
"myth like bonus scare over problem client lizard pioneer submit female collect";
const derivationPath = "m/44'/60'/0'/0/0";
// Generate xpub using two different libraries
const mnemonicToXpubMethod1 = (mnemonic: string, derivationPath: string) => {
const HDNode = ethers.utils.HDNode;
const masterNode = HDNode.fromMnemonic(mnemonic);
const standardEthereum = masterNode.derivePath(derivationPath);
const xpub = standardEthereum.neuter().extendedKey;
console.log("xpub generated using the `ethers` library:", xpub);
return xpub;
};
const mnemonicToXpubMethod2 = async (
mnemonic: string,
derivationPath: string
) => {
const seed = await bip39.mnemonicToSeed(mnemonic);
const master = HDKey.fromMasterSeed(seed);
const child = master.derive(derivationPath);
const xpub = child.publicExtendedKey;
console.log("xpub generated using the `bip39` library: ", xpub);
return xpub;
};
// Derive address from xpub using two different libraries
const deriveAddressMethod1 = (xpub: string) => {
const address = HDNode.fromExtendedKey(xpub).address;
console.log(
"Address derived using the `@findeth/hdnode` library:\t ",
address
);
return address;
};
const deriveAddressMethod2 = (xpub: string) => {
const address = Wallet.fromExtendedPublicKey(xpub).getAddressString();
console.log(
"Address derived using the `ethereumjs-wallet` library:\t ",
address
);
return address;
};
const run = async () => {
console.log("Mnemonic:", mnemonic);
console.log("Derivation path:", derivationPath);
const xpubA = mnemonicToXpubMethod1(mnemonic, derivationPath);
const xpubB = await mnemonicToXpubMethod2(mnemonic, derivationPath);
// both xpubs should be strictly identical
assert.strictEqual(xpubA, xpubB);
const addressA = deriveAddressMethod1(xpubA);
const addressB = deriveAddressMethod2(xpubB);
// both addresses should be identical (case insensitive)
assert.notStrictEqual(addressA, addressB);
};
run();
Output:
Mnemonic: myth like bonus scare over problem client lizard pioneer submit female collect
Derivation path: m/44'/60'/0'/0/0
xpub generated using the `ethers` library: xpub6GkCbW4FDnz8k9zhroVhZefi9fXhFFuTmmcQqfQKPDBrQjtSu4pdLpQ1Tje1BAzUw6PbJ47MMtNZ4RYM42VzRNxwaYUFnm3R44Lejvh9nHE
xpub generated using the `bip39` library: xpub6GkCbW4FDnz8k9zhroVhZefi9fXhFFuTmmcQqfQKPDBrQjtSu4pdLpQ1Tje1BAzUw6PbJ47MMtNZ4RYM42VzRNxwaYUFnm3R44Lejvh9nHE
Address derived using the `@findeth/hdnode` library: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
Address derived using the `ethereumjs-wallet` library: 0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1
From the following mnemonic, I have generated its corresponding Ethereum xpub using the current online version of the Mnemonic Code Converter (derivation path:
m/44'/60'/0'/0/0
).Mnemonic:
myth like bonus scare over problem client lizard pioneer submit female collect
(for testing purposes, generated by Ganache)Mnemonic Code Converter generates—using configuration:
ETH - Ethereum
, BIP44, default derivation path—the following data:xpub6DNro2eEZk9SreVWArMUamKzpa4oV7bJ9T8ffVKxbDPxrhToccxwCLg97v2ct8tk8TNsUEUj6XCUzQmb6LGzZTANdZDPC2KqLk4o3EnPfFi
xpub6EEDNF2mvRWBANmVjeB1n5ZMWszXnzXUL4u3VMq673qU9HNJ1zvXPLuxpUUmAVDom7Cg2iMDfQtoPL2MALL4qKB3RWsn5BAquLDd3US5XFU
In parallel, I have generated the xpub using the following script:
The xpub generated by this script (using two different libraries) is:
xpub6GkCbW4FDnz8k9zhroVhZefi9fXhFFuTmmcQqfQKPDBrQjtSu4pdLpQ1Tje1BAzUw6PbJ47MMtNZ4RYM42VzRNxwaYUFnm3R44Lejvh9nHE
. It differs from the xpubs generated by Mnemonic Code ConverterInterestingly, your tool correctly derives the expected addresses from the mnemonic (
0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
, etc.).Do you perhaps know why the xpubs generated by Mnemonic Code Converter and the one generated by my script differ?
Thank you in advance for your assistance.