trufflesuite / truffle

:warning: The Truffle Suite is being sunset. For information on ongoing support, migration options and FAQs, visit the Consensys blog. Thank you for all the support over the years.
https://consensys.io/blog/consensys-announces-the-sunset-of-truffle-and-ganache-and-new-hardhat?utm_source=github&utm_medium=referral&utm_campaign=2023_Sep_truffle-sunset-2023_announcement_
MIT License
14.02k stars 2.31k forks source link

Retrieving the private/ public key for a specific path with web3js: different outputs for same mnemonic/path passed as provider #112 #4104

Closed Jdodo45 closed 3 years ago

Jdodo45 commented 3 years ago

I am trying to create an ethereum wallet based  on a mnemonic phrase and I would like to retrieve private/public keys for several specific paths from this wallet.

Steps to Reproduce

This is my code which I run several time in different node console in a cmd.

Before starting the node console, I start a cmd with geth --rpc --rpcport 8545 while internet is turned off so that I don't have to download/sync the blockchain


const mnemonicPhrase = 'some words ... '

const HDWalletProvider = require("@truffle/hdwallet-provider");
Web3 = require('web3');

provider = new HDWalletProvider({
  mnemonic: mnemonicPhrase,
  providerOrUrl: "http://localhost:8545",
  numberOfAddresses: 1,
  shareNonce: true,
  derivationPath: "m/44'/0'/0'/0/"
});

const web3 = new Web3(provider);
web3.eth.accounts.create() 

Actual Results

When I run this code several time with the same mnemonic phrase and the same path, the private/public key given by web3.eth.accounts.create() is different, which it very confusing. I am new to the Ethereum world so I am probably missing something here but to have different private/public keys generated from the same mnemonic phrase and the same path doesn't sound right to me. It is as if the variable provider is not used by web3js .

Expected Behavior

Each time I am run this code in a new console wit the same mnemonic phrase and the same path, I should (at least as I understood it), get the same private/public key.

Thanks for your help!

Environment

eggplantzzz commented 3 years ago

When you pass web3 a provider like that, the accounts should already be initialized. Maybe the create method is creating an arbitrary new account without looking at the accounts that are already "unlocked". After you instantiate web3, you should be able to see which accounts you have access to just by inspecting web3.eth.accounts. You should get the same accounts that way. Let me know how it goes.

Jdodo45 commented 3 years ago

Thanks for your help @eggplantzzz! Yes this is on the right track as I get a similar address in web3js as the one given when I create the provider variable (which to me is the master key of the wallet) but I am not getting the private/public key for the path, just a single key. I am probably misunderstanding how this whole thing is working.

Jdodo45 commented 3 years ago

@eggplantzzz, I tried again and again with different options, I have also look at the docs, but I am still not able to get the private key, the public key and possibly the public address from the HDWalletProvider. Any idea how to do this? Thanks

kevinbluer commented 3 years ago

hey @Jdodo45, just to chime in with another approach which may be of use (depending on your needs for getting at the keys). If you install Ganache UI (https://www.trufflesuite.com/ganache) you can provide a mnemonic under the Accounts & Keys within workspace settings:

Screen Shot 2021-06-15 at 3.52.26 PM.png

Save and exit this and you'll now be able to view both the associated public and private keys from the Accounts tab. For the latter, click on the key icon to the right of a given account (see below).

Screen Shot 2021-06-15 at 3.52.43 PM.png

kevinbluer commented 3 years ago

alternatively and assuming the mnemonic is for DEVELOPMENT PURPOSES ONLY (apologies for the caps but just wanted to be sure), you could use https://iancoleman.io/bip39. note that you'll need to paste the mnemonic into "BIP39 Mnemonic" and select Ethereum as the "Coin"...scroll down and you'll see the list of addresses, keys, etc. essentially just doing the same thing as ganache without the need to install the desktop app.

Jdodo45 commented 3 years ago

Thanks for you answer @kevinbluer but I wanted to stay with simple command line code and will use it for production purposes so I can't use https://iancoleman.io/bip39.

I finally gave up using truffle and web3js and use ethereumjs-util instead.

Here is the code mainly from Harsha Goli

bip39 = require('bip39');
ethUtil = require('ethereumjs-util');
hdkey = require('hdkey');

const mnemonic = bip39.generateMnemonic(256); // if you already have a mnemonic you can put it here
const seed = bip39.mnemonicToSeedSync(mnemonic);
const root = hdkey.fromMasterSeed(seed);
const masterPrivateKey = root.privateKey.toString('hex');

var path = "m/44'/60'/0'/0/0"  // change path 
var addrNode = root.derive(path); 
var pubKey = ethUtil.privateToPublic(addrNode._privateKey);
var addr =  '0x' +  ethUtil.publicToAddress(pubKey).toString('hex');
var address = ethUtil.toChecksumAddress(addr);

console.log( "\n", "\n", "\n","ACCOUNT ", path, "\n", "private key : 0x", addrNode._privateKey.toString('hex'), "\n", "public key : ",pubKey.toString('hex'), "\n", "address : ", address)
DeivyPereira commented 2 years ago

Hello, surely it is late but if someone serves you I got the form like this: ` provider = new HDWalletProvider({ mnemonic: mnemonicPhrase, providerOrUrl: "http://localhost:8545", numberOfAddresses: 1, shareNonce: true, derivationPath: "m/44'/0'/0'/0/" });

let address = provider.wallets[provider.addresses[0]] let privateKey = "0x" + address.privateKey.toString('hex')

`