mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-20 13:34:37 +01:00
Wallet file parsing: Add Wasabi test case and re-add Electrum distinction (#5694)
* Extend tests, add Wasabi file * Re-add Electrum distinction * Specter: Fix indentation * Cleanups
This commit is contained in:
parent
b03f8db06b
commit
f31aa43c6a
8 changed files with 33 additions and 27 deletions
|
@ -936,9 +936,10 @@ namespace BTCPayServer.Tests
|
|||
// xpub
|
||||
var tpub = "tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS";
|
||||
Assert.True(parsers.TryParseWalletFile(tpub, testnet, out var settings, out var error));
|
||||
Assert.Null(error);
|
||||
Assert.True(settings.AccountDerivation is DirectDerivationStrategy { Segwit: false });
|
||||
Assert.Equal($"{tpub}-[legacy]", ((DirectDerivationStrategy)settings.AccountDerivation).ToString());
|
||||
Assert.Equal("Generic", settings.Source);
|
||||
Assert.Null(error);
|
||||
|
||||
// xpub with fingerprint and account
|
||||
tpub = "tpubDCXK98mNrPWuoWweaoUkqwxQF5NMWpQLy7n7XJgDCpwYfoZRXGafPaVM7mYqD7UKhsbMxkN864JY2PniMkt1Uk4dNuAMnWFVqdquyvZNyca";
|
||||
|
@ -953,6 +954,8 @@ namespace BTCPayServer.Tests
|
|||
Assert.Equal(tpub, ((DirectDerivationStrategy)settings.AccountDerivation).ToString());
|
||||
Assert.Equal(HDFingerprint.TryParse(fingerprint, out var hd) ? hd : default, settings.AccountKeySettings[0].RootFingerprint);
|
||||
Assert.Equal(account, settings.AccountKeySettings[0].AccountKeyPath.ToString());
|
||||
Assert.Equal("Generic", settings.Source);
|
||||
Assert.Null(error);
|
||||
|
||||
// ColdCard
|
||||
Assert.True(parsers.TryParseWalletFile(
|
||||
|
@ -969,12 +972,15 @@ namespace BTCPayServer.Tests
|
|||
settings.AccountOriginal);
|
||||
Assert.Equal(root.Derive(new KeyPath("m/49'/0'/0'")).Neuter().PubKey.WitHash.ScriptPubKey.Hash.ScriptPubKey,
|
||||
settings.AccountDerivation.GetDerivation().ScriptPubKey);
|
||||
Assert.Equal("ElectrumFile", settings.Source);
|
||||
Assert.Null(error);
|
||||
|
||||
// Should be legacy
|
||||
Assert.True(parsers.TryParseWalletFile(
|
||||
"{\"keystore\": {\"ckcc_xpub\": \"tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS\", \"xpub\": \"tpubDDWYqT3P24znfsaGX7kZcQhNc5LAjnQiKQvUCHF2jS6dsgJBRtymopEU5uGpMaR5YChjuiExZG1X2aTbqXkp82KqH5qnqwWHp6EWis9ZvKr\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/44'/1'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}",
|
||||
testnet, out settings, out error));
|
||||
Assert.True(settings.AccountDerivation is DirectDerivationStrategy { Segwit: false });
|
||||
Assert.Equal("ElectrumFile", settings.Source);
|
||||
Assert.Null(error);
|
||||
|
||||
// Should be segwit p2sh
|
||||
|
@ -982,6 +988,7 @@ namespace BTCPayServer.Tests
|
|||
"{\"keystore\": {\"ckcc_xpub\": \"tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS\", \"xpub\": \"upub5DSddA9NoRUyJrQ4p86nsCiTSY7kLHrSxx3joEJXjHd4HPARhdXUATuk585FdWPVC2GdjsMePHb6BMDmf7c6KG4K4RPX6LVqBLtDcWpQJmh\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/1'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}",
|
||||
testnet, out settings, out error));
|
||||
Assert.True(settings.AccountDerivation is P2SHDerivationStrategy { Inner: DirectDerivationStrategy { Segwit: true } });
|
||||
Assert.Equal("ElectrumFile", settings.Source);
|
||||
Assert.Null(error);
|
||||
|
||||
// Should be segwit
|
||||
|
@ -989,6 +996,7 @@ namespace BTCPayServer.Tests
|
|||
"{\"keystore\": {\"ckcc_xpub\": \"tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS\", \"xpub\": \"vpub5YjYxTemJ39tFRnuAhwduyxG2tKGjoEpmvqVQRPqdYrqa6YGoeSzBtHXaJUYB19zDbXs3JjbEcVWERjQBPf9bEfUUMZNMv1QnMyHV8JPqyf\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/84'/1'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}",
|
||||
testnet, out settings, out error));
|
||||
Assert.True(settings.AccountDerivation is DirectDerivationStrategy { Segwit: true });
|
||||
Assert.Equal("ElectrumFile", settings.Source);
|
||||
Assert.Null(error);
|
||||
|
||||
// Specter
|
||||
|
@ -998,11 +1006,21 @@ namespace BTCPayServer.Tests
|
|||
Assert.Equal(root.GetPublicKey().GetHDFingerPrint(), specter.AccountKeySettings[0].RootFingerprint);
|
||||
Assert.Equal(specter.AccountKeySettings[0].RootFingerprint, hd);
|
||||
Assert.Equal("49'/0'/0'", specter.AccountKeySettings[0].AccountKeyPath.ToString());
|
||||
Assert.True(specter.AccountDerivation is DirectDerivationStrategy { Segwit: true });
|
||||
Assert.Equal("Specter", specter.Label);
|
||||
Assert.Null(error);
|
||||
|
||||
//BSMS BIP129, Nunchuk
|
||||
|
||||
|
||||
// Wasabi
|
||||
var wasabiJson = @"{""EncryptedSecret"": ""6PYNUAZZLS1ShkhHhm9ayiNwXPAPLN669fN5mY2WbGm1Hqc88tomqWXabU"",""ChainCode"": ""UoHIB+2mDbZSowo11TfDQbsYK6q1DrZ2H2yqQBxu6m8="",""MasterFingerprint"": ""0f215605"",""ExtPubKey"": ""xpub6DUXFa6fMrFpg7x4nEd8jBU6xDN3vkSXsVUrSbUB2dadbYaPE31czwVdv146JRStGsc2U6TywdKnGoVcP8Rtp2AZQyzXxQb7HrgmR9LrqLA"",""TaprootExtPubKey"": ""xpub6D2thLU5KwUk3axkJu1UT3yKFshCGU7TMuxhPgZMd91VvrcDwHdRwdzLk61cSHtZC6BkaipPgfFwjoDBY4m1WxyznxZLukYgM4dC6iRJVf8"",""SkipSynchronization"": true,""UseTurboSync"": true,""MinGapLimit"": 21,""AccountKeyPath"": ""84'/0'/0'"",""TaprootAccountKeyPath"": ""86'/0'/0'"",""BlockchainState"": {""Network"": ""Main"",""Height"": ""503723"",""TurboSyncHeight"": ""503723""},""PreferPsbtWorkflow"": false,""AutoCoinJoin"": true,""PlebStopThreshold"": ""0.01"",""AnonScoreTarget"": 5,""FeeRateMedianTimeFrameHours"": 0,""IsCoinjoinProfileSelected"": true,""RedCoinIsolation"": false,""ExcludedCoinsFromCoinJoin"": [],""HdPubKeys"": [{""PubKey"": ""03f88b9c3e16e40a5a9eaf8b36b9bcee7bbc93fd9eea640b541efb931ac55f7ff5"",""FullKeyPath"": ""84'/0'/0'/1/0"",""Label"": """",""KeyState"": 0},{""PubKey"": ""03e5241fc28aa556d7cb826b9a9f5ecee85287e7476746126263574a5e27fbf569"",""FullKeyPath"": ""84'/0'/0'/0/0"",""Label"": """",""KeyState"": 0}]}";
|
||||
Assert.True(parsers.TryParseWalletFile(wasabiJson, mainnet, out var wasabi, out error));
|
||||
Assert.Null(error);
|
||||
Assert.Equal("WasabiFile", wasabi.Source);
|
||||
Assert.Single(wasabi.AccountKeySettings);
|
||||
Assert.Equal("84'/0'/0'", wasabi.AccountKeySettings[0].AccountKeyPath.ToString());
|
||||
Assert.Equal("0f215605", wasabi.AccountKeySettings[0].RootFingerprint.ToString());
|
||||
Assert.True(wasabi.AccountDerivation is DirectDerivationStrategy { Segwit: true });
|
||||
|
||||
// BSMS BIP129, Nunchuk
|
||||
var bsms = @"BSMS 1.0
|
||||
wsh(sortedmulti(1,[5c9e228d/48'/0'/0'/2']xpub6EgGHjcvovyN3nK921zAGPfuB41cJXkYRdt3tLGmiMyvbgHpss4X1eRZwShbEBb1znz2e2bCkCED87QZpin3sSYKbmCzQ9Sc7LaV98ngdeX/**,[2b0e251e/48'/0'/0'/2']xpub6DrimHB8KUSkPvmJ8Pk8RE769EdDm2VEoZ8MBz76w9QupP8Py4wexs4Pa3aRB1LUEhc9GyY6ypDWEFFRCgqeDQePcyWQfjtmintrehq3JCL/**))
|
||||
/0/*,/1/*
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace BTCPayServer
|
|||
throw new ArgumentOutOfRangeException(nameof(outputDescriptor));
|
||||
}
|
||||
}
|
||||
public DerivationStrategyBase Parse(string str, bool ignorePrefix = false, bool ignoreBasePrefix = false, bool enforceNetworkPrefix = true)
|
||||
public DerivationStrategyBase Parse(string str, bool ignorePrefix = false, bool ignoreBasePrefix = false, bool enforceNetworkPrefix = true, bool electrum = true)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(str);
|
||||
str = str.Trim();
|
||||
|
@ -143,7 +143,7 @@ namespace BTCPayServer
|
|||
throw new FormatException(
|
||||
$"Invalid xpub. Is this really for {BtcPayNetwork.CryptoCode} {Network.ChainName}?");
|
||||
|
||||
if (!ignorePrefix && !hasLabel && BtcPayNetwork.ElectrumMapping.TryGetValue(prefix, out var type))
|
||||
if (!ignorePrefix && !hasLabel && electrum && BtcPayNetwork.ElectrumMapping.TryGetValue(prefix, out var type))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using BTCPayServer.Payments;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBXplorer.Client;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
|
@ -21,8 +16,7 @@ namespace BTCPayServer
|
|||
string error = null;
|
||||
ArgumentNullException.ThrowIfNull(network);
|
||||
ArgumentNullException.ThrowIfNull(derivationStrategy);
|
||||
var result = new DerivationSchemeSettings();
|
||||
result.Network = network;
|
||||
var result = new DerivationSchemeSettings { Network = network };
|
||||
var parser = network.GetDerivationSchemeParser();
|
||||
if (parser.TryParseXpub(derivationStrategy, ref result, out error))
|
||||
{
|
||||
|
|
|
@ -32,9 +32,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitcoin.Payment;
|
||||
using NBitcoin.Scripting;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using NBXplorer.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -50,7 +48,7 @@ namespace BTCPayServer
|
|||
}
|
||||
|
||||
public static bool TryParseXpub(this DerivationSchemeParser derivationSchemeParser, string xpub,
|
||||
ref DerivationSchemeSettings derivationSchemeSettings, out string error)
|
||||
ref DerivationSchemeSettings derivationSchemeSettings, out string error, bool electrum = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -72,7 +70,7 @@ namespace BTCPayServer
|
|||
|
||||
derivationSchemeSettings.AccountOriginal = xpub.Trim();
|
||||
derivationSchemeSettings.AccountDerivation =
|
||||
derivationSchemeParser.Parse(derivationSchemeSettings.AccountOriginal, false, false, false);
|
||||
derivationSchemeParser.Parse(derivationSchemeSettings.AccountOriginal, false, false, false, electrum);
|
||||
derivationSchemeSettings.AccountKeySettings = derivationSchemeSettings.AccountDerivation.GetExtPubKeys()
|
||||
.Select(key => new AccountKeySettings {AccountKey = key.GetWif(derivationSchemeParser.Network)})
|
||||
.ToArray();
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using BTCPayServer;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
namespace BTCPayServer.Services.WalletFileParsing;
|
||||
public class ElectrumWalletFileParser : IWalletFileParser
|
||||
{
|
||||
|
@ -28,7 +25,7 @@ public class ElectrumWalletFileParser : IWalletFileParser
|
|||
if (jobj?.keystore is null)
|
||||
return false;
|
||||
|
||||
var result = new BTCPayServer.DerivationSchemeSettings() { Network = network };
|
||||
var result = new DerivationSchemeSettings { Network = network };
|
||||
var derivationSchemeParser = network.GetDerivationSchemeParser();
|
||||
result.Source = "ElectrumFile";
|
||||
|
||||
|
@ -46,7 +43,6 @@ public class ElectrumWalletFileParser : IWalletFileParser
|
|||
result.AccountKeySettings[0].RootFingerprint = new HDFingerprint(jobj.keystore.ckcc_xfp.Value);
|
||||
result.AccountKeySettings[0].AccountKeyPath = new KeyPath(jobj.keystore.derivation);
|
||||
|
||||
|
||||
if (jobj.keystore.ColdCardFirmwareVersion is not null)
|
||||
{
|
||||
result.Source = "ColdCard";
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using BTCPayServer;
|
||||
namespace BTCPayServer.Services.WalletFileParsing;
|
||||
public class NBXDerivGenericWalletFileParser : IWalletFileParser
|
||||
{
|
||||
public bool TryParse(BTCPayNetwork network, string data, [MaybeNullWhen(false)] out DerivationSchemeSettings derivationSchemeSettings)
|
||||
{
|
||||
derivationSchemeSettings = BTCPayServer.DerivationSchemeSettings.Parse(data, network);
|
||||
derivationSchemeSettings = DerivationSchemeSettings.Parse(data, network);
|
||||
derivationSchemeSettings.Source = "Generic";
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -27,9 +27,11 @@ public class SpecterWalletFileParser : IWalletFileParser
|
|||
return false;
|
||||
if (!_outputDescriptorOnChainWalletParser.TryParse(network, jobj.descriptor, out derivationSchemeSettings))
|
||||
return false;
|
||||
|
||||
derivationSchemeSettings.Source = "Specter";
|
||||
if (jobj.label is not null)
|
||||
derivationSchemeSettings.Label = jobj.label;
|
||||
derivationSchemeSettings.Label = jobj.label;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public class WasabiWalletFileParser : IWalletFileParser
|
|||
Network = network
|
||||
};
|
||||
|
||||
if (jobj is null || !derivationSchemeParser.TryParseXpub(jobj.ExtPubKey, ref result, out var error))
|
||||
if (jobj is null || !derivationSchemeParser.TryParseXpub(jobj.ExtPubKey, ref result, out var error, false))
|
||||
return false;
|
||||
|
||||
if (jobj.MasterFingerprint is not null)
|
||||
|
|
Loading…
Add table
Reference in a new issue