Пример #1
0
        public async Task <StoresController> CreateStoreAsync()
        {
            ExtKey = new ExtKey().GetWif(parent.Network);
            var store = parent.PayTester.GetController <StoresController>(UserId);
            await store.CreateStore(new CreateStoreViewModel()
            {
                Name = "Test Store"
            });

            StoreId          = store.CreatedStoreId;
            DerivationScheme = new DerivationStrategyFactory(parent.Network).Parse(ExtKey.Neuter().ToString() + "-[legacy]");
            await store.UpdateStore(StoreId, new StoreViewModel()
            {
                SpeedPolicy = SpeedPolicy.MediumSpeed
            });

            await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
            {
                CryptoCurrency         = "BTC",
                DerivationSchemeFormat = "BTCPay",
                DerivationScheme       = DerivationScheme.ToString(),
            }, "Save");

            return(store);
        }
Пример #2
0
        public async Task <StoresController> CreateStoreAsync(string cryptoCode = null)
        {
            cryptoCode       = cryptoCode ?? CryptoCode;
            SupportedNetwork = parent.NetworkProvider.GetNetwork(cryptoCode);
            ExtKey           = new ExtKey().GetWif(SupportedNetwork.NBitcoinNetwork);
            var store = parent.PayTester.GetController <StoresController>(UserId);
            await store.CreateStore(new CreateStoreViewModel()
            {
                Name = "Test Store"
            });

            StoreId          = store.CreatedStoreId;
            DerivationScheme = new DerivationStrategyFactory(SupportedNetwork.NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + "-[legacy]");
            var vm = (StoreViewModel)((ViewResult)await store.UpdateStore(StoreId)).Model;

            vm.SpeedPolicy = SpeedPolicy.MediumSpeed;
            await store.UpdateStore(StoreId, vm);

            await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
            {
                CryptoCurrency         = cryptoCode,
                DerivationSchemeFormat = "BTCPay",
                DerivationScheme       = DerivationScheme.ToString(),
                Confirmation           = true
            }, "Save");

            return(store);
        }
Пример #3
0
        private DerivationStrategyBase FindMatch(HashSet <string> hintLabels, DerivationStrategyBase result)
        {
            var facto        = new DerivationStrategyFactory(Network);
            var firstKeyPath = new KeyPath("0/0");

            if (HintScriptPubKey == null)
            {
                return(result);
            }
            if (HintScriptPubKey == result.GetDerivation(firstKeyPath).ScriptPubKey)
            {
                return(result);
            }

            if (result is MultisigDerivationStrategy)
            {
                hintLabels.Add("keeporder");
            }

            var resultNoLabels = result.ToString();

            resultNoLabels = string.Join('-', resultNoLabels.Split('-').Where(p => !IsLabel(p)));
            foreach (var labels in ItemCombinations(hintLabels.ToList()))
            {
                var hinted = facto.Parse(resultNoLabels + '-' + string.Join('-', labels.Select(l => $"[{l}]").ToArray()));
                if (HintScriptPubKey == hinted.GetDerivation(firstKeyPath).ScriptPubKey)
                {
                    return(hinted);
                }
            }
            throw new FormatException("Could not find any match");
        }
Пример #4
0
 public NBXplorerNetwork(INetworkSet networkSet, NetworkType networkType,
                         DerivationStrategyFactory derivationStrategyFactory = null)
 {
     NBitcoinNetwork           = networkSet.GetNetwork(networkType);
     CryptoCode                = networkSet.CryptoCode;
     DefaultSettings           = NBXplorerDefaultSettings.GetDefaultSettings(networkType);
     DerivationStrategyFactory = derivationStrategyFactory;
 }
Пример #5
0
 public async Task RegisterDerivationSchemeAsync(string crytoCode)
 {
     var store           = parent.PayTester.GetController <StoresController>(UserId);
     var networkProvider = parent.PayTester.GetService <BTCPayNetworkProvider>();
     var derivation      = new DerivationStrategyFactory(networkProvider.GetNetwork(crytoCode).NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + "-[legacy]");
     await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
     {
         CryptoCurrency         = crytoCode,
         DerivationSchemeFormat = crytoCode,
         DerivationScheme       = derivation.ToString(),
         Confirmation           = true
     }, "Save");
 }
Пример #6
0
 public InvoiceWatcher(ExplorerClient explorerClient,
                       InvoiceRepository invoiceRepository,
                       BTCPayWallet wallet,
                       InvoiceNotificationManager notificationManager)
 {
     LongPollingMode      = explorerClient.Network == Network.RegTest;
     PollInterval         = explorerClient.Network == Network.RegTest ? TimeSpan.FromSeconds(10.0) : TimeSpan.FromMinutes(1.0);
     _Wallet              = wallet ?? throw new ArgumentNullException(nameof(wallet));
     _ExplorerClient      = explorerClient ?? throw new ArgumentNullException(nameof(explorerClient));
     _DerivationFactory   = new DerivationStrategyFactory(_ExplorerClient.Network);
     _InvoiceRepository   = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
     _NotificationManager = notificationManager ?? throw new ArgumentNullException(nameof(notificationManager));
 }
Пример #7
0
        public async Task<WalletId> RegisterDerivationSchemeAsync(string cryptoCode, bool segwit = false)
        {
            SupportedNetwork = parent.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
            var store = parent.PayTester.GetController<StoresController>(UserId, StoreId);
            ExtKey = new ExtKey().GetWif(SupportedNetwork.NBitcoinNetwork);
            DerivationScheme = new DerivationStrategyFactory(SupportedNetwork.NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + (segwit ? "" : "-[legacy]"));
            await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
            {
                DerivationScheme = DerivationScheme.ToString(),
                Confirmation = true
            }, cryptoCode);

            return new WalletId(StoreId, cryptoCode);
        }
Пример #8
0
 public InvoiceWatcher(ExplorerClient explorerClient,
                       BTCPayNetworkProvider networkProvider,
                       InvoiceRepository invoiceRepository,
                       EventAggregator eventAggregator,
                       BTCPayWallet wallet,
                       InvoiceWatcherAccessor accessor)
 {
     LongPollingMode    = explorerClient.Network == Network.RegTest;
     PollInterval       = explorerClient.Network == Network.RegTest ? TimeSpan.FromSeconds(10.0) : TimeSpan.FromMinutes(1.0);
     _Wallet            = wallet ?? throw new ArgumentNullException(nameof(wallet));
     _ExplorerClient    = explorerClient ?? throw new ArgumentNullException(nameof(explorerClient));
     _DerivationFactory = new DerivationStrategyFactory(_ExplorerClient.Network);
     _InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
     _EventAggregator   = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
     _NetworkProvider   = networkProvider;
     accessor.Instance  = this;
 }
Пример #9
0
        public async Task RegisterDerivationSchemeAsync(string cryptoCode)
        {
            SupportedNetwork = parent.NetworkProvider.GetNetwork(cryptoCode);
            var store = parent.PayTester.GetController <StoresController>(UserId, StoreId);

            ExtKey           = new ExtKey().GetWif(SupportedNetwork.NBitcoinNetwork);
            DerivationScheme = new DerivationStrategyFactory(SupportedNetwork.NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + "-[legacy]");
            var vm = (StoreViewModel)((ViewResult)store.UpdateStore()).Model;

            vm.SpeedPolicy = SpeedPolicy.MediumSpeed;
            await store.UpdateStore(vm);

            await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
            {
                DerivationScheme = DerivationScheme.ToString(),
                Confirmation     = true
            }, cryptoCode);
        }
        public async Task <GetXPubResult> GetExtPubKey(BTCPayNetwork network)
        {
            if (network == null)
            {
                throw new ArgumentNullException(nameof(network));
            }

            var pubkey = await GetExtPubKey(_Ledger, network, new KeyPath("49'").Derive(network.CoinType).Derive(0, true), false);

            var derivation = new DerivationStrategyFactory(network.NBitcoinNetwork).CreateDirectDerivationStrategy(pubkey, new DerivationStrategyOptions()
            {
                P2SH   = true,
                Legacy = false
            });

            return(new GetXPubResult()
            {
                ExtPubKey = derivation.ToString()
            });
        }
        public async Task <GetXPubResult> GetExtPubKey(BTCPayNetwork network, KeyPath keyPath, CancellationToken cancellation)
        {
            if (network == null)
            {
                throw new ArgumentNullException(nameof(network));
            }

            var segwit = network.NBitcoinNetwork.Consensus.SupportSegwit;
            var pubkey = await GetExtPubKey(Ledger, network, keyPath, false, cancellation);

            var derivation = new DerivationStrategyFactory(network.NBitcoinNetwork).CreateDirectDerivationStrategy(pubkey, new DerivationStrategyOptions()
            {
                P2SH   = segwit,
                Legacy = !segwit
            });

            return(new GetXPubResult()
            {
                ExtPubKey = derivation.ToString(), KeyPath = keyPath
            });
        }
Пример #12
0
        public async Task <GetXPubResult> GetExtPubKey(BTCPayNetwork network, int account)
        {
            if (network == null)
            {
                throw new ArgumentNullException(nameof(network));
            }

            var segwit = network.NBitcoinNetwork.Consensus.SupportSegwit;
            var path   = network.GetRootKeyPath().Derive(account, true);
            var pubkey = await GetExtPubKey(_Ledger, network, path, false);

            var derivation = new DerivationStrategyFactory(network.NBitcoinNetwork).CreateDirectDerivationStrategy(pubkey, new DerivationStrategyOptions()
            {
                P2SH   = segwit,
                Legacy = !segwit
            });

            return(new GetXPubResult()
            {
                ExtPubKey = derivation.ToString(), KeyPath = path
            });
        }
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (!typeof(DerivationStrategyBase).GetTypeInfo().IsAssignableFrom(bindingContext.ModelType))
            {
                return(Task.CompletedTask);
            }

            ValueProviderResult val = bindingContext.ValueProvider.GetValue(
                bindingContext.ModelName);

            if (val == null)
            {
                return(Task.CompletedTask);
            }

            string key = val.FirstValue as string;

            if (key == null)
            {
                return(Task.CompletedTask);
            }

            var networkProvider = (BTCPayNetworkProvider)bindingContext.HttpContext.RequestServices.GetService(typeof(BTCPayNetworkProvider));
            var cryptoCode      = bindingContext.ValueProvider.GetValue("cryptoCode").FirstValue;
            var network         = networkProvider.GetNetwork <BTCPayNetwork>(cryptoCode ?? "BTC");

            try
            {
                var data = new DerivationStrategyFactory(network.NBitcoinNetwork).Parse(key);
                if (!bindingContext.ModelType.IsInstanceOfType(data))
                {
                    throw new FormatException("Invalid destination type");
                }
                bindingContext.Result = ModelBindingResult.Success(data);
            }
            catch { throw new FormatException("Invalid derivation scheme"); }
            return(Task.CompletedTask);
        }
Пример #14
0
        public DerivationStrategyBase Parse(string str)
        {
            if (str == null)
            {
                throw new ArgumentNullException(nameof(str));
            }
            str = str.Trim();

            HashSet <string> hintedLabels = new HashSet <string>();

            var hintDestination = HintScriptPubKey?.GetDestination();

            if (hintDestination != null)
            {
                if (hintDestination is KeyId)
                {
                    hintedLabels.Add("legacy");
                }
                if (hintDestination is ScriptId)
                {
                    hintedLabels.Add("p2sh");
                }
            }

            if (!Network.Consensus.SupportSegwit)
            {
                hintedLabels.Add("legacy");
            }

            try
            {
                var result = new DerivationStrategyFactory(Network).Parse(str);
                return(FindMatch(hintedLabels, result));
            }
            catch (Exception ex)
            {
                Console.WriteLine("");
            }

            var  parts    = str.Split('-');
            bool hasLabel = false;

            for (int i = 0; i < parts.Length; i++)
            {
                if (IsLabel(parts[i]))
                {
                    if (!hasLabel)
                    {
                        hintedLabels.Clear();
                        if (!Network.Consensus.SupportSegwit)
                        {
                            hintedLabels.Add("legacy");
                        }
                    }
                    hasLabel = true;
                    hintedLabels.Add(parts[i].Substring(1, parts[i].Length - 2).ToLowerInvariant());
                    continue;
                }
                try
                {
                    var data = Network.GetBase58CheckEncoder().DecodeData(parts[i]);
                    if (data.Length < 4)
                    {
                        continue;
                    }
                    var prefix = Utils.ToUInt32(data, false);

                    var standardPrefix = Utils.ToBytes(0x0488b21eU, false);
                    for (int ii = 0; ii < 4; ii++)
                    {
                        data[ii] = standardPrefix[ii];
                    }
                    var derivationScheme = new BitcoinExtPubKey(Network.GetBase58CheckEncoder().EncodeData(data), Network.Main).ToNetwork(Network).ToString();

                    if (ElectrumMappingDerivationType.TryGetValue(prefix, out var type))
                    {
                        switch (type)
                        {
                        case DerivationType.Legacy:
                            hintedLabels.Add("legacy");
                            break;

                        case DerivationType.SegwitP2SH:
                            hintedLabels.Add("p2sh");
                            break;
                        }
                    }
                    parts[i] = derivationScheme;
                }
                catch { continue; }
            }

            if (hintDestination != null)
            {
                if (hintDestination is WitKeyId)
                {
                    hintedLabels.Remove("legacy");
                    hintedLabels.Remove("p2sh");
                }
            }

            str = string.Join('-', parts.Where(p => !IsLabel(p)));
            foreach (var label in hintedLabels)
            {
                str = $"{str}-[{label}]";
            }

            return(FindMatch(hintedLabels, new DerivationStrategyFactory(Network).Parse(str)));
        }
Пример #15
0
 public DerivationStrategyJsonConverter(DerivationStrategyFactory factory)
 {
     Factory = factory;
 }
Пример #16
0
        // We will:
        // 1. Create a multi sig wallet of Alice and Bob
        // 2. Fund it with 1 BTC
        // 3. Send 0.4 BTC to a random address from it
        public static async Task Main(string[] args)
        {
            // Start bitcoind and NBXplorer in regtest:
            // * Run "bitcoind -regtest"
            // * Run ".\build.ps1", then ".\run.ps1 -regtest" in NBXplorer

            var network = Network.RegTest;
            var client  = CreateNBXClient(network);

            // Now let's simulate alice and bob in a 2-2 multisig
            var alice = new Party(new Mnemonic(Wordlist.English), "Alice",
                                  new KeyPath("1'/2'/3'"));
            var bob = new Party(new Mnemonic(Wordlist.English), "Bob",
                                new KeyPath("5'/2'/3'"));


            Console.WriteLine($"Alice should secretly save '{alice.Mnemonic}', and remember her password 'Alice'");
            Console.WriteLine("---");
            Console.WriteLine($"Alice should secretly save '{bob.Mnemonic}', and remember her password 'Bob'");

            Console.WriteLine("---");
            Console.WriteLine($"Alice should share '{alice.AccountExtPubKey.GetWif(network)}' with Bob");
            Console.WriteLine("---");
            Console.WriteLine($"Bob should share '{bob.AccountExtPubKey.GetWif(network)}' with Alice");

            var factory            = new DerivationStrategyFactory(network);
            var derivationStrategy = factory.CreateMultiSigDerivationStrategy(new[]
            {
                alice.AccountExtPubKey.GetWif(network),
                bob.AccountExtPubKey.GetWif(network)
            }, 2, new DerivationStrategyOptions()
            {
                ScriptPubKeyType = ScriptPubKeyType.SegwitP2SH
            });

            Console.WriteLine("---");
            Console.WriteLine($"The derivation strategy '{derivationStrategy}' represents all the data you need to know to track the multisig wallet");

            // NBXplorer will start tracking this wallet.
            await client.TrackAsync(derivationStrategy);

            // This allow you to get events out of NBXPlorer
            var evts = client.CreateLongPollingNotificationSession();

            // Now let's fund the wallet
            var address1 = (await client.GetUnusedAsync(derivationStrategy, DerivationFeature.Deposit)).Address;

            var rpc = new RPCClient(network);
            // If that fail, your bitcoin node need some bitcoins
            // bitcoin-cli -regtest getnewaddress
            // bitcoin-cli -regtest generatetoaddress 101 <address>
            await rpc.SendToAddressAsync(address1, Money.Coins(1.0m));

            await WaitTransaction(evts, derivationStrategy);

            Console.WriteLine("---");
            Console.WriteLine("Sent some money to the multi sig wallet");
            Console.WriteLine("---");

            // You can list transactions
            var txs = await client.GetTransactionsAsync(derivationStrategy);

            Console.WriteLine($"Number of unconf transactions: {txs.UnconfirmedTransactions.Transactions.Count}");
            Console.WriteLine("---");
            var balance = await client.GetBalanceAsync(derivationStrategy);

            Console.WriteLine($"Balance: {balance.Unconfirmed}");

            Console.WriteLine("---");
            var randomDestination = new Key().PubKey.GetAddress(ScriptPubKeyType.Segwit, network);
            var psbt = (await client.CreatePSBTAsync(derivationStrategy, new CreatePSBTRequest()
            {
                Destinations =
                {
                    new CreatePSBTDestination()
                    {
                        Destination = randomDestination,
                        Amount = Money.Coins(0.4m),
                        SubstractFees = true // We will pay fee by sending to destination a bit less than 0.4 BTC
                    }
                },
                FeePreference = new FeePreference()
                {
                    // 10 sat/byte. You can remove this in prod, as it will use bitcoin's core estimation.
                    ExplicitFeeRate = new FeeRate(10.0m)
                }
            })).PSBT;

            var signedByAlice = Sign(alice, derivationStrategy, psbt);

            Console.WriteLine("---");
            var signedByBob = Sign(bob, derivationStrategy, psbt);

            // OK both have signed
            var fullySignedPSBT = signedByAlice.Combine(signedByBob);

            fullySignedPSBT.Finalize();
            var fullySignedTx = fullySignedPSBT.ExtractTransaction();
            await client.BroadcastAsync(fullySignedTx);

            // Let's wait NBX receives the tx
            await WaitTransaction(evts, derivationStrategy);

            balance = await client.GetBalanceAsync(derivationStrategy);

            Console.WriteLine($"New balance: {balance.Unconfirmed}");
        }
        public async Task <IActionResult> AddDerivationSchemeLedger(
            string storeId,
            string cryptoCode,
            string command,
            string keyPath = "")
        {
            if (!HttpContext.WebSockets.IsWebSocketRequest)
            {
                return(NotFound());
            }

            var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();

            var    hw      = new LedgerHardwareWalletService(webSocket);
            object result  = null;
            var    network = _NetworkProvider.GetNetwork <BTCPayNetwork>(cryptoCode);

            using (var normalOperationTimeout = new CancellationTokenSource())
            {
                normalOperationTimeout.CancelAfter(TimeSpan.FromMinutes(30));
                try
                {
                    if (command == "test")
                    {
                        result = await hw.Test(normalOperationTimeout.Token);
                    }
                    if (command == "getxpub")
                    {
                        var k = KeyPath.Parse(keyPath);
                        if (k.Indexes.Length == 0)
                        {
                            throw new FormatException("Invalid key path");
                        }

                        var getxpubResult = new GetXPubs();
                        getxpubResult.ExtPubKey = await hw.GetExtPubKey(network, k, normalOperationTimeout.Token);

                        var segwit     = network.NBitcoinNetwork.Consensus.SupportSegwit;
                        var derivation = new DerivationStrategyFactory(network.NBitcoinNetwork).CreateDirectDerivationStrategy(getxpubResult.ExtPubKey, new DerivationStrategyOptions()
                        {
                            ScriptPubKeyType = segwit ? ScriptPubKeyType.SegwitP2SH : ScriptPubKeyType.Legacy
                        });
                        getxpubResult.DerivationScheme = derivation;
                        getxpubResult.RootFingerprint  = (await hw.GetExtPubKey(network, new KeyPath(), normalOperationTimeout.Token)).ExtPubKey.PubKey.GetHDFingerPrint();
                        getxpubResult.Source           = hw.Device;
                        result = getxpubResult;
                    }
                }
                catch (OperationCanceledException)
                { result = new LedgerTestResult()
                  {
                      Success = false, Error = "Timeout"
                  }; }
                catch (Exception ex)
                { result = new LedgerTestResult()
                  {
                      Success = false, Error = ex.Message
                  }; }
                finally { hw.Dispose(); }
                try
                {
                    if (result != null)
                    {
                        UTF8Encoding UTF8NOBOM = new UTF8Encoding(false);
                        var          bytes     = UTF8NOBOM.GetBytes(JsonConvert.SerializeObject(result, network.NBXplorerNetwork.JsonSerializerSettings));
                        await webSocket.SendAsync(new ArraySegment <byte>(bytes), WebSocketMessageType.Text, true, new CancellationTokenSource(2000).Token);
                    }
                }
                catch { }
                finally
                {
                    await webSocket.CloseSocket();
                }
            }
            return(new EmptyResult());
        }
Пример #18
0
        public async Task <IActionResult> UpdateStore(string storeId, StoreViewModel model, string command)
        {
            if (!ModelState.IsValid)
            {
                return(View(model));
            }
            var store = await _Repo.FindStore(storeId, GetUserId());

            if (store == null)
            {
                return(NotFound());
            }

            if (command == "Save")
            {
                bool needUpdate = false;
                if (store.SpeedPolicy != model.SpeedPolicy)
                {
                    needUpdate        = true;
                    store.SpeedPolicy = model.SpeedPolicy;
                }
                if (store.StoreName != model.StoreName)
                {
                    needUpdate      = true;
                    store.StoreName = model.StoreName;
                }
                if (store.StoreWebsite != model.StoreWebsite)
                {
                    needUpdate         = true;
                    store.StoreWebsite = model.StoreWebsite;
                }

                if (store.DerivationStrategy != model.DerivationScheme)
                {
                    needUpdate = true;
                    try
                    {
                        var strategy = ParseDerivationStrategy(model.DerivationScheme);
                        await _Wallet.TrackAsync(strategy);

                        await _CallbackController.RegisterCallbackUriAsync(strategy, Request);

                        store.DerivationStrategy = model.DerivationScheme;
                    }
                    catch
                    {
                        ModelState.AddModelError(nameof(model.DerivationScheme), "Invalid Derivation Scheme");
                        return(View(model));
                    }
                }

                if (needUpdate)
                {
                    await _Repo.UpdateStore(store);

                    StatusMessage = "Store successfully updated";
                }

                return(RedirectToAction(nameof(UpdateStore), new
                {
                    storeId = storeId
                }));
            }
            else
            {
                var facto  = new DerivationStrategyFactory(_Network);
                var scheme = facto.Parse(model.DerivationScheme);
                var line   = scheme.GetLineFor(DerivationFeature.Deposit);

                for (int i = 0; i < 10; i++)
                {
                    var address = line.Derive((uint)i);
                    model.AddressSamples.Add((line.Path.Derive((uint)i).ToString(), address.ScriptPubKey.GetDestinationAddress(_Network).ToString()));
                }
                return(View(model));
            }
        }
        public DerivationStrategyBase Parse(string str)
        {
            if (str == null)
            {
                throw new ArgumentNullException(nameof(str));
            }
            str = str.Trim();

            HashSet <string> hintedLabels = new HashSet <string>();

            var hintDestination = HintScriptPubKey?.GetDestination();

            if (hintDestination != null)
            {
                if (hintDestination is KeyId)
                {
                    hintedLabels.Add("legacy");
                }
                if (hintDestination is ScriptId)
                {
                    hintedLabels.Add("p2sh");
                }
            }
            else
            {
                if (Network.Consensus.SupportSegwit)
                {
                    hintedLabels.Add("p2sh");
                }
                else
                {
                    hintedLabels.Add("legacy");
                }
            }

            try {
                var result = new DerivationStrategyFactory(Network).Parse(str);
                return(FindMatch(hintedLabels, result));
            }
            catch {
            }

            Dictionary <uint, string[]> electrumMapping = new Dictionary <uint, string[]>();
            //Source https://github.com/spesmilo/electrum/blob/9edffd17542de5773e7284a8c8a2673c766bb3c3/lib/bitcoin.py
            var standard = 0x0488b21eU;

            electrumMapping.Add(standard, new[] { "legacy" });
            var p2wpkh_p2sh = 0x049d7cb2U;

            electrumMapping.Add(p2wpkh_p2sh, new string[] { "p2sh" });
            var p2wpkh = 0x4b24746U;

            electrumMapping.Add(p2wpkh, Array.Empty <string>());

            var parts = str.Split('-');

            for (int i = 0; i < parts.Length; i++)
            {
                if (IsLabel(parts[i]))
                {
                    hintedLabels.Add(parts[i].Substring(1, parts[i].Length - 2).ToLowerInvariant());
                    continue;
                }
                try {
                    var data = Network.GetBase58CheckEncoder().DecodeData(parts[i]);
                    if (data.Length < 4)
                    {
                        continue;
                    }
                    var prefix         = NU.ToUInt32(data, false);
                    var standardPrefix = NU.ToBytes(Network.NetworkType == NetworkType.Mainnet ? 0x0488b21eU : 0x043587cf, false);
                    for (int ii = 0; ii < 4; ii++)
                    {
                        data[ii] = standardPrefix[ii];
                    }

                    var derivationScheme = new BitcoinExtPubKey(Network.GetBase58CheckEncoder().EncodeData(data), Network).ToString();
                    electrumMapping.TryGetValue(prefix, out string[] labels);
                    if (labels != null)
                    {
                        foreach (var label in labels)
                        {
                            hintedLabels.Add(label.ToLowerInvariant());
                        }
                    }
                    parts[i] = derivationScheme;
                }
                catch { continue; }
            }

            if (hintDestination != null)
            {
                if (hintDestination is WitKeyId)
                {
                    hintedLabels.Remove("legacy");
                    hintedLabels.Remove("p2sh");
                }
            }

            str = string.Join('-', parts.Where(p => !IsLabel(p)));
            foreach (var label in hintedLabels)
            {
                str = $"{str}-[{label}]";
            }

            return(FindMatch(hintedLabels, new DerivationStrategyFactory(Network).Parse(str)));
        }
Пример #20
0
        public async Task <IActionResult> ConnectWebSocket(
            string cryptoCode,
            bool includeTransaction        = true,
            CancellationToken cancellation = default)
        {
            if (!HttpContext.WebSockets.IsWebSocketRequest)
            {
                return(NotFound());
            }

            GetNetwork(cryptoCode);             // Internally check if cryptoCode is correct

            string listenAllDerivationSchemes = null;
            var    listenedBlocks             = new ConcurrentDictionary <string, string>();
            var    listenedDerivations        = new ConcurrentDictionary <(Network, DerivationStrategyBase), DerivationStrategyBase>();

            WebsocketMessageListener server        = new WebsocketMessageListener(await HttpContext.WebSockets.AcceptWebSocketAsync(), _SerializerSettings);
            CompositeDisposable      subscriptions = new CompositeDisposable();

            subscriptions.Add(_EventAggregator.Subscribe <Events.NewBlockEvent>(async o =>
            {
                if (listenedBlocks.ContainsKey(o.CryptoCode))
                {
                    var chain = ChainProvider.GetChain(o.CryptoCode);
                    if (chain == null)
                    {
                        return;
                    }
                    var block = chain.GetBlock(o.BlockId);
                    if (block != null)
                    {
                        await server.Send(new Models.NewBlockEvent()
                        {
                            CryptoCode        = o.CryptoCode,
                            Hash              = block.HashBlock,
                            Height            = block.Height,
                            PreviousBlockHash = block?.Previous.HashBlock
                        });
                    }
                }
            }));
            subscriptions.Add(_EventAggregator.Subscribe <Events.NewTransactionMatchEvent>(async o =>
            {
                var network = Waiters.GetWaiter(o.CryptoCode);
                if (network == null)
                {
                    return;
                }
                if (
                    listenAllDerivationSchemes == "*" ||
                    listenAllDerivationSchemes == o.CryptoCode ||
                    listenedDerivations.ContainsKey((network.Network.NBitcoinNetwork, o.Match.DerivationStrategy)))
                {
                    var chain = ChainProvider.GetChain(o.CryptoCode);
                    if (chain == null)
                    {
                        return;
                    }
                    var blockHeader = o.BlockId == null ? null : chain.GetBlock(o.BlockId);
                    await server.Send(new Models.NewTransactionEvent()
                    {
                        CryptoCode         = o.CryptoCode,
                        DerivationStrategy = o.Match.DerivationStrategy,
                        BlockId            = blockHeader?.HashBlock,
                        TransactionData    = ToTransactionResult(includeTransaction, chain, new[] { o.SavedTransaction }),
                        Inputs             = o.Match.Inputs,
                        Outputs            = o.Match.Outputs
                    });
                }
            }));
            try
            {
                while (server.Socket.State == WebSocketState.Open)
                {
                    object message = await server.NextMessageAsync(cancellation);

                    switch (message)
                    {
                    case Models.NewBlockEventRequest r:
                        r.CryptoCode = r.CryptoCode ?? cryptoCode;
                        listenedBlocks.TryAdd(r.CryptoCode, r.CryptoCode);
                        break;

                    case Models.NewTransactionEventRequest r:
                        if (r.DerivationSchemes != null)
                        {
                            r.CryptoCode = r.CryptoCode ?? cryptoCode;
                            var network = Waiters.GetWaiter(r.CryptoCode)?.Network;
                            if (network == null)
                            {
                                break;
                            }
                            foreach (var derivation in r.DerivationSchemes)
                            {
                                var parsed = new DerivationStrategyFactory(network.NBitcoinNetwork).Parse(derivation);
                                listenedDerivations.TryAdd((network.NBitcoinNetwork, parsed), parsed);
                            }
                        }
                        else
                        {
                            listenAllDerivationSchemes = r.CryptoCode;
                        }
                        break;

                    default:
                        break;
                    }
                }
            }
            catch when(server.Socket.State != WebSocketState.Open)
            {
            }
            finally { subscriptions.Dispose(); await server.DisposeAsync(cancellation); }
            return(new EmptyResult());
        }
Пример #21
0
        public async Task <IActionResult> ConnectWebSocket(
            string cryptoCode,
            bool includeTransaction        = true,
            CancellationToken cancellation = default)
        {
            if (!HttpContext.WebSockets.IsWebSocketRequest)
            {
                return(NotFound());
            }

            GetNetwork(cryptoCode, false);             // Internally check if cryptoCode is correct

            string listenAllDerivationSchemes = null;
            string listenAllTrackedSource     = null;
            var    listenedBlocks             = new ConcurrentDictionary <string, string>();
            var    listenedDerivations        = new ConcurrentDictionary <(Network, DerivationStrategyBase), DerivationStrategyBase>();
            var    listenedTrackedSource      = new ConcurrentDictionary <(Network, TrackedSource), TrackedSource>();

            WebsocketMessageListener server        = new WebsocketMessageListener(await HttpContext.WebSockets.AcceptWebSocketAsync(), _SerializerSettings);
            CompositeDisposable      subscriptions = new CompositeDisposable();

            subscriptions.Add(_EventAggregator.Subscribe <Models.NewBlockEvent>(async o =>
            {
                if (listenedBlocks.ContainsKey(o.CryptoCode))
                {
                    await server.Send(o);
                }
            }));
            subscriptions.Add(_EventAggregator.Subscribe <Models.NewTransactionEvent>(async o =>
            {
                var network = Waiters.GetWaiter(o.CryptoCode);
                if (network == null)
                {
                    return;
                }

                bool forward         = false;
                var derivationScheme = (o.TrackedSource as DerivationSchemeTrackedSource)?.DerivationStrategy;
                if (derivationScheme != null)
                {
                    forward |= listenAllDerivationSchemes == "*" ||
                               listenAllDerivationSchemes == o.CryptoCode ||
                               listenedDerivations.ContainsKey((network.Network.NBitcoinNetwork, derivationScheme));
                }

                forward |= listenAllTrackedSource == "*" || listenAllTrackedSource == o.CryptoCode ||
                           listenedTrackedSource.ContainsKey((network.Network.NBitcoinNetwork, o.TrackedSource));

                if (forward)
                {
                    var derivation = (o.TrackedSource as DerivationSchemeTrackedSource)?.DerivationStrategy;
                    await server.Send(o);
                }
            }));
            try
            {
                while (server.Socket.State == WebSocketState.Open)
                {
                    object message = await server.NextMessageAsync(cancellation);

                    switch (message)
                    {
                    case Models.NewBlockEventRequest r:
                        r.CryptoCode = r.CryptoCode ?? cryptoCode;
                        listenedBlocks.TryAdd(r.CryptoCode, r.CryptoCode);
                        break;

                    case Models.NewTransactionEventRequest r:
                        var network = Waiters.GetWaiter(r.CryptoCode)?.Network;
                        if (r.DerivationSchemes != null)
                        {
                            r.CryptoCode = r.CryptoCode ?? cryptoCode;
                            if (network != null)
                            {
                                foreach (var derivation in r.DerivationSchemes)
                                {
                                    var parsed = new DerivationStrategyFactory(network.NBitcoinNetwork).Parse(derivation);
                                    listenedDerivations.TryAdd((network.NBitcoinNetwork, parsed), parsed);
                                }
                            }
                        }
                        else if (
                            // Back compat: If no derivation scheme precised and ListenAllDerivationSchemes not set, we listen all
                            (r.TrackedSources == null && r.ListenAllDerivationSchemes == null) ||
                            (r.ListenAllDerivationSchemes != null && r.ListenAllDerivationSchemes.Value))
                        {
                            listenAllDerivationSchemes = r.CryptoCode;
                        }

                        if (r.ListenAllTrackedSource != null && r.ListenAllTrackedSource.Value)
                        {
                            listenAllTrackedSource = r.CryptoCode;
                        }
                        else if (r.TrackedSources != null)
                        {
                            r.CryptoCode = r.CryptoCode ?? cryptoCode;
                            if (network != null)
                            {
                                foreach (var trackedSource in r.TrackedSources)
                                {
                                    if (TrackedSource.TryParse(trackedSource, out var parsed, network.NBitcoinNetwork))
                                    {
                                        listenedTrackedSource.TryAdd((network.NBitcoinNetwork, parsed), parsed);
                                    }
                                }
                            }
                        }

                        break;

                    default:
                        break;
                    }
                }
            }
            catch when(server.Socket.State != WebSocketState.Open)
            {
            }
            finally { subscriptions.Dispose(); await server.DisposeAsync(cancellation); }
            return(new EmptyResult());
        }
 public LiquidNBXplorerNetwork(INetworkSet networkSet, NetworkType networkType, DerivationStrategyFactory derivationStrategyFactory = null) : base(networkSet, networkType, derivationStrategyFactory)
 {
 }