mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-01-06 07:34:26 +01:00
Support wasabi file format input (#1671)
* Support wasabi file format input This adds support to importing the wasabi file format which seems to be used more for imports by Wasabi,ColdCard,BlueWallet & Cobo Vault (and way better than electrum anyway) * fixes * add test
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Payments;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -38,12 +40,12 @@ namespace BTCPayServer
|
||||
return strategy != null;
|
||||
}
|
||||
|
||||
private static bool TryParseXpub(string xpub, DerivationSchemeParser derivationSchemeParser, ref DerivationSchemeSettings derivationSchemeSettings)
|
||||
private static bool TryParseXpub(string xpub, DerivationSchemeParser derivationSchemeParser, ref DerivationSchemeSettings derivationSchemeSettings, bool electrum = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
derivationSchemeSettings.AccountOriginal = xpub.Trim();
|
||||
derivationSchemeSettings.AccountDerivation = derivationSchemeParser.ParseElectrum(derivationSchemeSettings.AccountOriginal);
|
||||
derivationSchemeSettings.AccountDerivation = electrum ? derivationSchemeParser.ParseElectrum(derivationSchemeSettings.AccountOriginal) : derivationSchemeParser.Parse(derivationSchemeSettings.AccountOriginal);
|
||||
derivationSchemeSettings.AccountKeySettings = new AccountKeySettings[1];
|
||||
derivationSchemeSettings.AccountKeySettings[0] = new AccountKeySettings();
|
||||
derivationSchemeSettings.AccountKeySettings[0].AccountKey = derivationSchemeSettings.AccountDerivation.GetExtPubKeys().Single().GetWif(derivationSchemeParser.Network);
|
||||
@@ -57,58 +59,122 @@ namespace BTCPayServer
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryParseFromElectrumWallet(string coldcardExport, BTCPayNetwork network, out DerivationSchemeSettings settings)
|
||||
public static bool TryParseFromWalletFile(string fileContents, BTCPayNetwork network, out DerivationSchemeSettings settings)
|
||||
{
|
||||
settings = null;
|
||||
if (coldcardExport == null)
|
||||
throw new ArgumentNullException(nameof(coldcardExport));
|
||||
if (fileContents == null)
|
||||
throw new ArgumentNullException(nameof(fileContents));
|
||||
if (network == null)
|
||||
throw new ArgumentNullException(nameof(network));
|
||||
var result = new DerivationSchemeSettings();
|
||||
result.Source = "Electrum/Airgap hardware wallet";
|
||||
var derivationSchemeParser = new DerivationSchemeParser(network);
|
||||
JObject jobj = null;
|
||||
try
|
||||
{
|
||||
jobj = JObject.Parse(coldcardExport);
|
||||
jobj = (JObject)jobj["keystore"];
|
||||
jobj = JObject.Parse(fileContents);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return TryParseXpub(coldcardExport, derivationSchemeParser, ref result);
|
||||
result.Source = "GenericFile";
|
||||
return TryParseXpub(fileContents, derivationSchemeParser, ref result);
|
||||
}
|
||||
|
||||
if (!jobj.ContainsKey("xpub") ||
|
||||
!TryParseXpub(jobj["xpub"].Value<string>(), derivationSchemeParser, ref result))
|
||||
//electrum
|
||||
if (jobj.ContainsKey("keystore"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (jobj.ContainsKey("label"))
|
||||
{
|
||||
try
|
||||
result.Source = "ElectrumFile";
|
||||
jobj = (JObject)jobj["keystore"];
|
||||
|
||||
if (!jobj.ContainsKey("xpub") ||
|
||||
!TryParseXpub(jobj["xpub"].Value<string>(), derivationSchemeParser, ref result))
|
||||
{
|
||||
result.Label = jobj["label"].Value<string>();
|
||||
return false;
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
if (jobj.ContainsKey("ckcc_xfp"))
|
||||
{
|
||||
try
|
||||
if (jobj.ContainsKey("label"))
|
||||
{
|
||||
result.AccountKeySettings[0].RootFingerprint = new HDFingerprint(jobj["ckcc_xfp"].Value<uint>());
|
||||
try
|
||||
{
|
||||
result.Label = jobj["label"].Value<string>();
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
if (jobj.ContainsKey("derivation"))
|
||||
{
|
||||
try
|
||||
if (jobj.ContainsKey("ckcc_xfp"))
|
||||
{
|
||||
result.AccountKeySettings[0].AccountKeyPath = new KeyPath(jobj["derivation"].Value<string>());
|
||||
try
|
||||
{
|
||||
result.AccountKeySettings[0].RootFingerprint = new HDFingerprint(jobj["ckcc_xfp"].Value<uint>());
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
if (jobj.ContainsKey("derivation"))
|
||||
{
|
||||
try
|
||||
{
|
||||
result.AccountKeySettings[0].AccountKeyPath = new KeyPath(jobj["derivation"].Value<string>());
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Source = "WasabiFile";
|
||||
//wasabi format
|
||||
if (!jobj.ContainsKey("ExtPubKey") ||
|
||||
!TryParseXpub(jobj["ExtPubKey"].Value<string>(), derivationSchemeParser, ref result, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (jobj.ContainsKey("MasterFingerprint"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var mfpString = jobj["MasterFingerprint"].ToString().Trim();
|
||||
// https://github.com/zkSNACKs/WalletWasabi/pull/1663#issuecomment-508073066
|
||||
|
||||
if(uint.TryParse(mfpString, out var fingerprint))
|
||||
{
|
||||
result.AccountKeySettings[0].RootFingerprint = new HDFingerprint(fingerprint);
|
||||
}
|
||||
else
|
||||
{
|
||||
var shouldReverseMfp = jobj.ContainsKey("ColdCardFirmwareVersion") &&
|
||||
jobj["ColdCardFirmwareVersion"].ToString() == "2.1.0";
|
||||
var bytes = Encoders.Hex.DecodeData(mfpString);
|
||||
result.AccountKeySettings[0].RootFingerprint = shouldReverseMfp ? new HDFingerprint(bytes.Reverse().ToArray()) : new HDFingerprint(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
catch { return false; }
|
||||
}
|
||||
if (jobj.ContainsKey("AccountKeyPath"))
|
||||
{
|
||||
try
|
||||
{
|
||||
result.AccountKeySettings[0].AccountKeyPath = new KeyPath(jobj["AccountKeyPath"].Value<string>());
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
if (jobj.ContainsKey("DerivationPath"))
|
||||
{
|
||||
try
|
||||
{
|
||||
result.AccountKeySettings[0].AccountKeyPath = new KeyPath(jobj["DerivationPath"].Value<string>().ToLowerInvariant());
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
if (jobj.ContainsKey("ColdCardFirmwareVersion"))
|
||||
{
|
||||
result.Source = "ColdCard";
|
||||
}
|
||||
|
||||
if (jobj.ContainsKey("CoboVaultFirmwareVersion"))
|
||||
{
|
||||
result.Source = "CoboVault";
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
settings = result;
|
||||
settings.Network = network;
|
||||
|
||||
Reference in New Issue
Block a user