コード例 #1
0
        public static DerivationSchemeSettings Parse(string derivationStrategy, BTCPayNetwork network)
        {
            ArgumentNullException.ThrowIfNull(network);
            ArgumentNullException.ThrowIfNull(derivationStrategy);
            var result = new DerivationSchemeSettings();

            result.Network = network;
            var parser = new DerivationSchemeParser(network);

            if (TryParseXpub(derivationStrategy, parser, ref result, false) || TryParseXpub(derivationStrategy, parser, ref result, true))
            {
                return(result);
            }

            throw new FormatException("Invalid Derivation Scheme");
        }
コード例 #2
0
 private static bool TryParseXpub(string xpub, DerivationSchemeParser derivationSchemeParser, ref DerivationSchemeSettings derivationSchemeSettings, bool electrum = true)
 {
     if (!electrum)
     {
         try
         {
             var result = derivationSchemeParser.ParseOutputDescriptor(xpub);
             derivationSchemeSettings.AccountOriginal    = xpub.Trim();
             derivationSchemeSettings.AccountDerivation  = result.Item1;
             derivationSchemeSettings.AccountKeySettings = result.Item2.Select((path, i) => new AccountKeySettings()
             {
                 RootFingerprint = path?.MasterFingerprint,
                 AccountKeyPath  = path?.KeyPath,
                 AccountKey      = result.Item1.GetExtPubKeys().ElementAt(i).GetWif(derivationSchemeParser.Network)
             }).ToArray();
             return(true);
         }
         catch (Exception)
         {
             // ignored
         }
     }
     try
     {
         derivationSchemeSettings.AccountOriginal    = xpub.Trim();
         derivationSchemeSettings.AccountDerivation  = electrum ? derivationSchemeParser.ParseElectrum(derivationSchemeSettings.AccountOriginal) : derivationSchemeParser.Parse(derivationSchemeSettings.AccountOriginal);
         derivationSchemeSettings.AccountKeySettings = derivationSchemeSettings.AccountDerivation.GetExtPubKeys()
                                                       .Select(key => new AccountKeySettings()
         {
             AccountKey = key.GetWif(derivationSchemeParser.Network)
         }).ToArray();
         if (derivationSchemeSettings.AccountDerivation is DirectDerivationStrategy direct && !direct.Segwit)
         {
             derivationSchemeSettings.AccountOriginal = null; // Saving this would be confusing for user, as xpub of electrum is legacy derivation, but for btcpay, it is segwit derivation
         }
         return(true);
     }
     catch (Exception)
     {
         return(false);
     }
 }
コード例 #3
0
 private static bool TryParseXpub(string xpub, DerivationSchemeParser derivationSchemeParser, ref DerivationSchemeSettings derivationSchemeSettings)
 {
     try
     {
         derivationSchemeSettings.AccountOriginal                  = xpub.Trim();
         derivationSchemeSettings.AccountDerivation                = derivationSchemeParser.ParseElectrum(derivationSchemeSettings.AccountOriginal);
         derivationSchemeSettings.AccountKeySettings               = new AccountKeySettings[1];
         derivationSchemeSettings.AccountKeySettings[0]            = new AccountKeySettings();
         derivationSchemeSettings.AccountKeySettings[0].AccountKey = derivationSchemeSettings.AccountDerivation.GetExtPubKeys().Single().GetWif(derivationSchemeParser.Network);
         if (derivationSchemeSettings.AccountDerivation is DirectDerivationStrategy direct && !direct.Segwit)
         {
             derivationSchemeSettings.AccountOriginal = null; // Saving this would be confusing for user, as xpub of electrum is legacy derivation, but for btcpay, it is segwit derivation
         }
         return(true);
     }
     catch (Exception e)
     {
         return(false);
     }
 }
コード例 #4
0
        public static bool TryParseFromElectrumWallet(string coldcardExport, BTCPayNetwork network, out DerivationSchemeSettings settings)
        {
            settings = null;
            if (coldcardExport == null)
            {
                throw new ArgumentNullException(nameof(coldcardExport));
            }
            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"];
            }
            catch
            {
                return(TryParseXpub(coldcardExport, derivationSchemeParser, ref result));
            }

            if (!jobj.ContainsKey("xpub") ||
                !TryParseXpub(jobj["xpub"].Value <string>(), derivationSchemeParser, ref result))
            {
                return(false);
            }

            if (jobj.ContainsKey("label"))
            {
                try
                {
                    result.Label = jobj["label"].Value <string>();
                }
                catch { return(false); }
            }

            if (jobj.ContainsKey("ckcc_xfp"))
            {
                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); }
            }
            settings         = result;
            settings.Network = network;
            return(true);
        }
コード例 #5
0
        public static bool TryParseFromWalletFile(string fileContents, BTCPayNetwork network, out DerivationSchemeSettings settings)
        {
            settings = null;
            if (fileContents == null)
            {
                throw new ArgumentNullException(nameof(fileContents));
            }
            if (network == null)
            {
                throw new ArgumentNullException(nameof(network));
            }
            var     result = new DerivationSchemeSettings();
            var     derivationSchemeParser = new DerivationSchemeParser(network);
            JObject jobj = null;

            try
            {
                if (HexEncoder.IsWellFormed(fileContents))
                {
                    fileContents = Encoding.UTF8.GetString(Encoders.Hex.DecodeData(fileContents));
                }
                jobj = JObject.Parse(fileContents);
            }
            catch
            {
                result.Source = "GenericFile";
                if (TryParseXpub(fileContents, derivationSchemeParser, ref result) ||
                    TryParseXpub(fileContents, derivationSchemeParser, ref result, false))
                {
                    settings         = result;
                    settings.Network = network;
                    return(true);
                }

                return(false);
            }

            // Electrum
            if (jobj.ContainsKey("keystore"))
            {
                result.Source = "ElectrumFile";
                jobj          = (JObject)jobj["keystore"];

                if (!jobj.ContainsKey("xpub") ||
                    !TryParseXpub(jobj["xpub"].Value <string>(), derivationSchemeParser, ref result))
                {
                    return(false);
                }

                if (jobj.ContainsKey("label"))
                {
                    try
                    {
                        result.Label = jobj["label"].Value <string>();
                    }
                    catch { return(false); }
                }

                if (jobj.ContainsKey("ckcc_xfp"))
                {
                    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); }
                }
            }
            // Specter
            else if (jobj.ContainsKey("descriptor") && jobj.ContainsKey("blockheight"))
            {
                result.Source = "SpecterFile";

                if (!TryParseXpub(jobj["descriptor"].Value <string>(), derivationSchemeParser, ref result, false))
                {
                    return(false);
                }

                if (jobj.ContainsKey("label"))
                {
                    try
                    {
                        result.Label = jobj["label"].Value <string>();
                    }
                    catch { return(false); }
                }
            }
            // Wasabi
            else
            {
                result.Source = "WasabiFile";
                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";
                }
            }
            settings         = result;
            settings.Network = network;
            return(true);
        }
コード例 #6
0
        public static bool TryParseFromColdcard(string coldcardExport, BTCPayNetwork network, out DerivationSchemeSettings settings)
        {
            settings = null;
            if (coldcardExport == null)
            {
                throw new ArgumentNullException(nameof(coldcardExport));
            }
            if (network == null)
            {
                throw new ArgumentNullException(nameof(network));
            }
            var result = new DerivationSchemeSettings();

            result.Source = "Coldcard";
            var     derivationSchemeParser = new DerivationSchemeParser(network);
            JObject jobj = null;

            try
            {
                jobj = JObject.Parse(coldcardExport);
                jobj = (JObject)jobj["keystore"];
            }
            catch
            {
                return(false);
            }

            if (jobj.ContainsKey("xpub"))
            {
                try
                {
                    result.AccountOriginal                  = jobj["xpub"].Value <string>().Trim();
                    result.AccountDerivation                = derivationSchemeParser.ParseElectrum(result.AccountOriginal);
                    result.AccountKeySettings               = new AccountKeySettings[1];
                    result.AccountKeySettings[0]            = new AccountKeySettings();
                    result.AccountKeySettings[0].AccountKey = result.AccountDerivation.GetExtPubKeys().Single().GetWif(network.NBitcoinNetwork);
                    if (result.AccountDerivation is DirectDerivationStrategy direct && !direct.Segwit)
                    {
                        result.AccountOriginal = null; // Saving this would be confusing for user, as xpub of electrum is legacy derivation, but for btcpay, it is segwit derivation
                    }
                }
                catch
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }

            if (jobj.ContainsKey("label"))
            {
                try
                {
                    result.Label = jobj["label"].Value <string>();
                }
                catch { return(false); }
            }

            if (jobj.ContainsKey("ckcc_xfp"))
            {
                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); }
            }
            settings         = result;
            settings.Network = network;
            return(true);
        }