Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to iterate through BIP44 addresses? #155

Open
shayanb opened this issue Jul 25, 2017 · 2 comments
Open

How to iterate through BIP44 addresses? #155

shayanb opened this issue Jul 25, 2017 · 2 comments

Comments

@shayanb
Copy link

shayanb commented Jul 25, 2017

I'm trying to use eth-lightwallet to generate BIP32/44 style addresses using custom paths, let's say:

BasePath = m'/0'/0''

Address 1= m'/0'/0'/1
Address 2= m'/0'/0'/2
Address 3= m'/0'/0'/3
...

The way eth-lightwallet seems to be working is by using ks.generateNewAddress(pwDerivedKey, 1); you'd get the next address but I couldn't find a way to get either the path for that address or input the custom path to generate the address in the path I want.

There's a way to iterate through the addresses which is a bit hacky, something like the following:

BasePath = m'/0'/0'/0'

Address 1= m'/0'/0'/1/1
Address 2= m'/0'/0'/2/1
Address 3= m'/0'/0'/3/1
...

Here is the source code for such iteration:

function generateNewAddress (seed, password, HdPathString, newAddressIdentifier, done) {
  // newAddressIdentifier is the incremental value for new address
  // the final path is basically HdPathString/newAddressIdentifier
  const finalHdPath = HdPathString + '/' + newAddressIdentifier.toString() + "'";
  console.log('finalHdPath', finalHdPath);

  lightwallet.keystore.deriveKeyFromPassword(password, function (err, pwDerivedKey) {
    var ks = new lightwallet.keystore(secretSeed, pwDerivedKey, finalHdPath);

    ks.generateNewAddress(pwDerivedKey, 1);
    var addr = ks.getAddresses()[0];
    console.log('addr', addr);
    var privKey = ks.exportPrivateKey(addr, pwDerivedKey, finalHdPath);
    const retObj = {address: addr,
      privateKey: privKey};
    done(null, retObj);
  });
}

The ^ solution is using the deprecated function which will be removed on next updates.

However using the new method KeyStore.createVault() even this hack is not possible as it would throw exception.

this works fine when the finalHdPath is m/0'/0'/0'. but fails as soon as we try to run it using any other default path:

function generateNewAddress (seed, password, HdPathString, newAddressIdentifier, done) {
  // newAddressIdentifier is the incremental value for new address
  // the final path is basically HdPathString/newAddressIdentifier
  const finalHdPath = HdPathString + '/' + newAddressIdentifier.toString() + "'";
  console.log('finalHdPath', finalHdPath);

  lightwallet.keystore.createVault({
    password: password,
    seedPhrase: secretSeed,
    HdPathString: finalHdPath
  }, function (err, ks) {
    if (err) done(err);
    ks.keyFromPassword(password, function (err, pwDerivedKey) {
      if (err) done(err);
      ks.generateNewAddress(pwDerivedKey, 1, finalHdPath); // generateNewAddress(pwDerivedKey, [num,] [hdPathString])
      console.log(ks.getAddresses());
      var addr = ks.getAddresses()[0];
      var privKey = ks.exportPrivateKey(addr, pwDerivedKey, finalHdPath);
      console.log(ks.defaultHdPathString);
      console.log('addr', addr);
      const retObj = {address: addr,
        privateKey: privKey};
      done(null, retObj);
    });
  });
}

for input m/0'/0'/0':

[ 'fff3a90735a619bd1a5780450b446d1515928b68' ]
m/0'/0'/0'
addr fff3a90735a619bd1a5780450b446d1515928b68
{ address: 'fff3a90735a619bd1a5780450b446d1515928b68',
  privateKey: 'fa746519af5b0bb64163d96bb13548e7e15410080e45ac8df388b9568f01042a' }

for input m/0'/0'/1':

hdPathString m/0'/0'/1'
this.ksData[hdPathString] undefined
/token_eth_sweeper/testFlow.js:43
  if (err) throw err;
           ^

TypeError: Cannot read property 'info' of undefined
    at KeyStore.generateNewAddress (/token_eth_sweeper/node_modules/eth-lightwallet/lib/keystore.js:443:32)
    at /token_eth_sweeper/testFlow.js:29:10
    at cb (/token_eth_sweeper/node_modules/eth-lightwallet/lib/keystore.js:524:7)
    at /token_eth_sweeper/node_modules/scrypt-async/scrypt-async.js:518:13
    at Immediate._onImmediate (/token_eth_sweeper/node_modules/scrypt-async/scrypt-async.js:481:11)
    at runCallback (timers.js:800:20)
    at tryOnImmediate (timers.js:762:5)
    at processImmediate [as _immediateCallback] (timers.js:733:5)
@coder5876
Copy link
Contributor

coder5876 commented Jul 28, 2017

@shayanb Right now we don't really support iterations beyond HdPathString/i where i is an integer 0, 1, 2, ....

You say you want to generate

Address 1= m'/0'/0'/1
Address 2= m'/0'/0'/2
Address 3= m'/0'/0'/3

and this is very easy to do by using m'/0'/0' as hdPathString and then you can do

ks.generateNewAddress(pwDerivedKey, 4)

to generate m'/0'/0'/0 as well as the 3 addresses in your example.

@shayanb
Copy link
Author

shayanb commented Jul 28, 2017

@christianlundkvist Thanks, the way ks.generateNewAddress(pwDerivedKey, 4) works is that if you generate 4 for now and later on you want to continue on the path using another instance of the app, you have to generate let's say 10 and don't use the first 4 that you've already used. This solution would not be really scalable.

I made a pull request to add this feature so you can derive any path you need: #156

keystore.generateNewAddressOnPath(pwDerivedKey, [hdPathString], [index])

Please take a look and merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants