Truffle: Support mnemonic passphrase

Created on 21 May 2020  路  17Comments  路  Source: trufflesuite/truffle

Most helpful comment

This is now supported in Truffle (as of version 5.1.45).

All 17 comments

Undocumented maybe, but it is supported. Set the provider to:
new HDWalletProvider(mnemonic, url, ...)

Undocumented maybe, but it is supported. Set the provider to:
new HDWalletProvider(mnemonic, url, ...)

Can you please elaborate? There's no password or passphrase in the constructor.

https://github.com/trufflesuite/truffle/blob/develop/packages/hdwallet-provider/src/index.ts#L34

  constructor(
    mnemonic: string | string[],
    provider: string | any,
    addressIndex: number = 0,
    numAddresses: number = 10,
    shareNonce: boolean = true,
    walletHdpath: string = `m/44'/60'/0'/0/`
  ) 

The mnemonic (which might be 12 common words) functions in the place of a password/passphrase: those 12 words are the mnemonic passphrase. It's all you need to reconstruct the private keys corresponding to a set of accounts.

Here are the docs where you can find how to enter in a mnemonic to generate accounts. https://github.com/trufflesuite/truffle/tree/develop/packages/hdwallet-provider

I hope this helps!

Closing this for issue maintenance because mnemonics are supported :) If you still think there is something that we should address get back to us and we'll be happy to re-open it and help you out!

Closing this for issue maintenance because mnemonics are supported :) If you still think there is something that we should address get back to us and we'll be happy to re-open it and help you out!

I mean the passphrase of the mnemonic, not the mnemonic itself.

image

https://iancoleman.io/bip39/

@kigawas I think the best, short term solution would be to provide the first private key from your salted mnemonic phrase in place of your mnemonic phrase, and then add include a waller_hd path variable when interacting with the wallet_hdprovider library.

But adding in the ability to the wallet_hdprovider library seems like a reasonable thing to do for medium/long term development. I'm going to dive into that

@kigawas I think the best, short term solution would be to provide the first private key from your salted mnemonic phrase in place of your mnemonic phrase, and then add include a waller_hd path variable when interacting with the wallet_hdprovider library.

But adding in the ability to the wallet_hdprovider library seems like a reasonable thing to do for medium/long term development. I'm going to dive into that

I understand there may be other priorities, but this addition imo is as trivial as it gets:
https://github.com/trufflesuite/truffle-hdwallet-provider/pull/17/files

@haltman-at, I see you added the help-wanted label. I think this "feature" could come in two stages... some simple additional documentation describing the process @josh-kean mentions above along with a code example using the bip39 module (super simple).

Then the feature could very easily be implemented (I saw a couple of old PRs before the migration to the mono-repo), it's just a matter of defining the API. I personally think the best backwards-compatible solution would be:

new HDWalletProvider({ mnemonic: /* ... */, password: /* ... */ }, /* other optional args */)

with

  const checkBIP39Mnemonic = (rawMnemonic = {}) => {
      const { mnemonic, password } = typeof rawMnemonic === 'string' 
        ? { mnemonic: rawMnemonic, password: '' }
        : rawMnemonic;  

      this.hdwallet = hdkey_1.default.fromMasterSeed(bip39.mnemonicToSeed(mnemonic, password));
      if (!bip39.validateMnemonic(mnemonic)) {
          throw new Error("Mnemonic invalid or undefined");
      }
      // crank the addresses out
      for (let i = addressIndex; i < addressIndex + numAddresses; i++) {
          const wallet = this.hdwallet
              .derivePath(this.walletHdpath + i)
              .getWallet();
          const addr = `0x${wallet.getAddress().toString("hex")}`;
          this.addresses.push(addr);
          this.wallets[addr] = wallet;
      }
  };

I know the "string or object" argument is kind of ugly, but there's not really any clean/backwards-compatible way around this since the function is right-variadic. I'm open to other suggestions and happy to PR, I would just like some guidance on the API before I spend any time writing code.

(Just realized the repo is written in typescript... still easy to do the same thing with union types)

This sounds like a good proposal and it seems your solution is good as well. So just to re-iterate, my understanding of this proposal is that we will be adding the capability to input an object containing mnemonic and password keys during instantiation which will be used to generate the seed and thus create the addresses.

Also, do you maybe have some old code that you copied from in your code sample? I'm not sure what the kdkey_1.default business is. :) This is the relevant code https://github.com/trufflesuite/truffle/blob/develop/packages/hdwallet-provider/src/index.ts#L73-L91.

Also I want to see if @gnidan has any objection to this.

No objection at all, of course! Thanks for offering @richardpringle, I like your polymorphic solution...

In fact, how do you feel about going a step further and defining a single options object argument in addition to the currently supported positional args. Something like:

const provider = new HDWalletProvider({
  mnemonic,
  password,
  url: "http://localhost:8545",
  addressIndex: 5,
  numberOfAddresses: 1,
  shareNonce: true,
  derivationPath: "m/44'/137'/0'/0/"
});

Of course, we'll need to maintain backwards compatibility, but it might be nice to nip the positionals in the bud here. Also seems reasonable to group that effort into this one. Thoughts?

@eggplantzzz, my code is copied from node_modules... it's the transpiled JS (and it's probably old).

@gnidan, makes sense! Would you go a little further and have

const provider = new HDWalletProvider({
  mnemonic, // the mnemonic can currently be a private key string, and array of private keys, or a mnemonic
  password,
  privateKeys, // we could add a privateKeys property that is `string | string[]`
  url: "http://localhost:8545",
  addressIndex: 5,
  numberOfAddresses: 1,
  shareNonce: true,
  derivationPath: "m/44'/137'/0'/0/"
});

The types get a little messy here but I don't think it's too bad:

type Mnemonic  = { mnemonic: string, password?: string } | string;
type PrivateKeys = string | string[];
type options = { addressIndex?: number, numberOfAddresses?: number, sharedNonce?: bool, derivationPath?: string };
type MnemonicArgs = { mnemonic: Mnemonic, privateKeys?: never } & options;
type PrivateKeyArgs = { privateKeys: PrivateKeys, mnemonic?: never } & options;

I'll post a PR for actual feedback on the API before I actually implement anything.

@gnidan #3209

Sweet @richardpringle, will get back to this after meetings today!

@richardpringle what do you think of something like this:

export interface MnemonicOptions {
  mnemonic: string;
  password?: string;
}

export interface PrivateKeysOptions {
  privateKeys: string | string[];
}

export interface CommonConstructorOptions {
  url: string;
  addressIndex?: number;
  numberOfAddresses?: number;
  sharedNonce?: bool;
  derivationPath?: string;
}

export type ConstructorOptions =
  | CommonConstructorOptions & MnemonicOptions
  | CommonConstructorOptions & PrivateKeyOptions;

This way, I don't _think_ we need those nevers, but I could be wrong. Might be useful to have them in my MnemonicOptions and PrivateKeyOptions.

(I can move these comments to the PR if you prefer)

This is now supported in Truffle (as of version 5.1.45).

Was this page helpful?
0 / 5 - 0 ratings