LedgerHQ / ledger-dotnet-api

.NET API for Ledger
MIT License
48 stars 30 forks source link

Obtain keypath of latest ledger receive address? #5

Closed danielcrenna closed 6 years ago

danielcrenna commented 6 years ago

Is it possible to determine the keypath needed to get the same segwit pubkey 3address as the ledger client itself displays in its own app when receiving funds?

NicolasDorier commented 6 years ago

Yes, get the xpub of the ledger using GetMasterPubKey of path 0'. Then derive 0/x using masterKey.Derive(new KeyPath("0/x")) and generate the segwit addresses extPubkey.PubKey.WitHash.ScriptPubKey.Hash.GetAddress(Network.Main) until you find the same one.

danielcrenna commented 6 years ago

That's basically what I have now, but I was intending to run it headless without the other app online. I think what you're basically saying is we don't know the index of the last generation without running it multiple times. I think that's OK, I just have to take steps to ensure that it's not a used address and then spin it. Thanks!

NicolasDorier commented 6 years ago

@danielcrenna the code generating addresses for the user should always track of the KeyPath used for a particular address in a database at address generation time.

Enumerating the addresses like that might be computationally intense.

Another solution is enumerating addresses like that on your offline app and indexing the KeyPath by ScriptPubkey so you don't have to run that again everytimes.

danielcrenna commented 6 years ago

Closing as I can get this to work with a workaround of using ExtPubKey.Parse(xpub) using the Ledger account tools to export the pubkey, as I don't think GetMasterPubKey is implemented.

NicolasDorier commented 6 years ago

GetMasterPubKey is implemented.

danielcrenna commented 6 years ago

https://github.com/LedgerHQ/ledger-dotnet-api/search?utf8=%E2%9C%93&q=GetMasterPubKey&type=

NicolasDorier commented 6 years ago

https://github.com/LedgerHQ/ledger-dotnet-api/blob/master/LedgerWallet/LedgerClient.cs#L40

NicolasDorier commented 6 years ago

Ledger wallet show you the path 0'

danielcrenna commented 6 years ago

I figured it was that; there is no method in LedgerClient called GetMasterPubKey that you've pasted, but if there was you're saying it should be equivalent to ledger.GetWalletPubKey(new KeyPath("0'"), I just can't locate an API to convert the PubKey or BitcoinAddress in that response object into an ExtPubKey.

GetWalletPubKeyResponse masterKey = ledger.GetWalletPubKey(new KeyPath("0'")); ExtPubKey.Parse(masterKey...);

NicolasDorier commented 6 years ago
var a = ledger.GetWalletPubKey(new KeyPath("1'"));
var hdKey = new ExtPubKey(a.UncompressedPublicKey.Compress(), a.ChainCode);
danielcrenna commented 6 years ago

6 thanks for sticking with me. i made a PR for methods that others might find useful, the methods I was looking for before the education.

NicolasDorier commented 6 years ago

should we close this?

vflame commented 2 years ago

For anyone stumbling upon this, I'm finding that this does not actually give you the correct derivation. You have to build the masterPubKey with the parentPubKey like so:

            var derivationPath = new KeyPath("m/84'/0'/0'"); 
            var parentPath = new KeyPath("m/84'/0'");
            var parentPub = await ledger.GetWalletPubKeyAsync(parentPath);
            var derivationPub = await ledger.GetWalletPubKeyAsync(derivationPath);            
            var parentFP = parentPub.UncompressedPublicKey.Compress().GetHDFingerPrint();
            var masterDerivationPubKey = new ExtPubKey(derivationPub.ExtendedPublicKey.PubKey, derivationPub.ChainCode, Convert.ToByte(derivationPath.Length), parentFP, derivationPath.Indexes.Last());