Esempio n. 1
0
        private void AddPaymentMethods(StoreData store, StoreBlob storeBlob, StoreViewModel vm)
        {
            var excludeFilters         = storeBlob.GetExcludedPaymentMethods();
            var derivationByCryptoCode =
                store
                .GetSupportedPaymentMethods(_NetworkProvider)
                .OfType <DerivationStrategy>()
                .ToDictionary(c => c.Network.CryptoCode);

            foreach (var network in _NetworkProvider.GetAll())
            {
                var strategy = derivationByCryptoCode.TryGet(network.CryptoCode);
                vm.DerivationSchemes.Add(new StoreViewModel.DerivationScheme()
                {
                    Crypto   = network.CryptoCode,
                    Value    = strategy?.DerivationStrategyBase?.ToString() ?? string.Empty,
                    WalletId = new WalletId(store.Id, network.CryptoCode),
                    Enabled  = !excludeFilters.Match(new Payments.PaymentMethodId(network.CryptoCode, Payments.PaymentTypes.BTCLike))
                });
            }

            var lightningByCryptoCode = store
                                        .GetSupportedPaymentMethods(_NetworkProvider)
                                        .OfType <Payments.Lightning.LightningSupportedPaymentMethod>()
                                        .ToDictionary(c => c.CryptoCode);

            foreach (var network in _NetworkProvider.GetAll())
            {
                var lightning = lightningByCryptoCode.TryGet(network.CryptoCode);
                var paymentId = new Payments.PaymentMethodId(network.CryptoCode, Payments.PaymentTypes.LightningLike);
                vm.LightningNodes.Add(new StoreViewModel.LightningNode()
                {
                    CryptoCode = network.CryptoCode,
                    Address    = lightning?.GetLightningUrl()?.BaseUri.AbsoluteUri ?? string.Empty,
                    Enabled    = !excludeFilters.Match(paymentId)
                });
            }


            var changellyEnabled = storeBlob.ChangellySettings != null && storeBlob.ChangellySettings.Enabled;

            vm.ThirdPartyPaymentMethods.Add(new StoreViewModel.ThirdPartyPaymentMethod()
            {
                Enabled  = changellyEnabled,
                Action   = nameof(UpdateChangellySettings),
                Provider = "Changelly"
            });

            var coinSwitchEnabled = storeBlob.CoinSwitchSettings != null && storeBlob.CoinSwitchSettings.Enabled;

            vm.ThirdPartyPaymentMethods.Add(new StoreViewModel.ThirdPartyPaymentMethod()
            {
                Enabled  = coinSwitchEnabled,
                Action   = nameof(UpdateCoinSwitchSettings),
                Provider = "CoinSwitch"
            });
        }
        public async Task <IActionResult> LedgerConnection(
            [ModelBinder(typeof(WalletIdModelBinder))]
            WalletId walletId,
            string command,
            // getinfo
            // getxpub
            int account = 0,
            // sendtoaddress
            bool noChange      = false,
            string destination = null, string amount = null, string feeRate = null, string substractFees = null
            )
        {
            if (!HttpContext.WebSockets.IsWebSocketRequest)
            {
                return(NotFound());
            }

            var cryptoCode       = walletId.CryptoCode;
            var storeData        = (await Repository.FindStore(walletId.StoreId, GetUserId()));
            var derivationScheme = GetPaymentMethod(walletId, storeData).DerivationStrategyBase;

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

            using (var normalOperationTimeout = new CancellationTokenSource())
                using (var signTimeout = new CancellationTokenSource())
                {
                    normalOperationTimeout.CancelAfter(TimeSpan.FromMinutes(30));
                    var    hw     = new HardwareWalletService(webSocket);
                    object result = null;
                    try
                    {
                        BTCPayNetwork network = null;
                        if (cryptoCode != null)
                        {
                            network = NetworkProvider.GetNetwork(cryptoCode);
                            if (network == null)
                            {
                                throw new FormatException("Invalid value for crypto code");
                            }
                        }

                        BitcoinAddress destinationAddress = null;
                        if (destination != null)
                        {
                            try
                            {
                                destinationAddress = BitcoinAddress.Create(destination.Trim(), network.NBitcoinNetwork);
                            }
                            catch { }
                            if (destinationAddress == null)
                            {
                                throw new FormatException("Invalid value for destination");
                            }
                        }

                        FeeRate feeRateValue = null;
                        if (feeRate != null)
                        {
                            try
                            {
                                feeRateValue = new FeeRate(Money.Satoshis(int.Parse(feeRate, CultureInfo.InvariantCulture)), 1);
                            }
                            catch { }
                            if (feeRateValue == null || feeRateValue.FeePerK <= Money.Zero)
                            {
                                throw new FormatException("Invalid value for fee rate");
                            }
                        }

                        Money amountBTC = null;
                        if (amount != null)
                        {
                            try
                            {
                                amountBTC = Money.Parse(amount);
                            }
                            catch { }
                            if (amountBTC == null || amountBTC <= Money.Zero)
                            {
                                throw new FormatException("Invalid value for amount");
                            }
                        }

                        bool subsctractFeesValue = false;
                        if (substractFees != null)
                        {
                            try
                            {
                                subsctractFeesValue = bool.Parse(substractFees);
                            }
                            catch { throw new FormatException("Invalid value for subtract fees"); }
                        }
                        if (command == "test")
                        {
                            result = await hw.Test(normalOperationTimeout.Token);
                        }
                        if (command == "sendtoaddress")
                        {
                            if (!_dashboard.IsFullySynched(network.CryptoCode, out var summary))
                            {
                                throw new Exception($"{network.CryptoCode}: not started or fully synched");
                            }
                            var         strategy       = GetDirectDerivationStrategy(derivationScheme);
                            var         wallet         = _walletProvider.GetWallet(network);
                            var         change         = wallet.GetChangeAddressAsync(derivationScheme);
                            var         keypaths       = new Dictionary <Script, KeyPath>();
                            List <Coin> availableCoins = new List <Coin>();
                            foreach (var c in await wallet.GetUnspentCoins(derivationScheme))
                            {
                                keypaths.TryAdd(c.Coin.ScriptPubKey, c.KeyPath);
                                availableCoins.Add(c.Coin);
                            }

                            var changeAddress = await change;

                            var storeBlob    = storeData.GetStoreBlob();
                            var paymentId    = new Payments.PaymentMethodId(cryptoCode, Payments.PaymentTypes.BTCLike);
                            var foundKeyPath = storeBlob.GetWalletKeyPathRoot(paymentId);
                            // Some deployment have the wallet root key path saved in the store blob
                            // If it does, we only have to make 1 call to the hw to check if it can sign the given strategy,
                            if (foundKeyPath == null || !await hw.CanSign(network, strategy, foundKeyPath, normalOperationTimeout.Token))
                            {
                                // If the saved wallet key path is not present or incorrect, let's scan the wallet to see if it can sign strategy
                                foundKeyPath = await hw.FindKeyPath(network, strategy, normalOperationTimeout.Token);

                                if (foundKeyPath == null)
                                {
                                    throw new HardwareWalletException($"This store is not configured to use this ledger");
                                }
                                storeBlob.SetWalletKeyPathRoot(paymentId, foundKeyPath);
                                storeData.SetStoreBlob(storeBlob);
                                await Repository.UpdateStore(storeData);
                            }
retry:
                            var send = new[] { (
Esempio n. 3
0
        public async Task <IActionResult> LedgerConnection(
            [ModelBinder(typeof(WalletIdModelBinder))]
            WalletId walletId,
            string command,
            // getinfo
            // getxpub
            int account = 0,
            // sendtoaddress
            bool noChange      = false,
            string destination = null, string amount = null, string feeRate = null, bool substractFees = false, bool disableRBF = false
            )
        {
            if (!HttpContext.WebSockets.IsWebSocketRequest)
            {
                return(NotFound());
            }

            var cryptoCode       = walletId.CryptoCode;
            var storeData        = (await Repository.FindStore(walletId.StoreId, GetUserId()));
            var derivationScheme = GetPaymentMethod(walletId, storeData).DerivationStrategyBase;

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

            using (var normalOperationTimeout = new CancellationTokenSource())
                using (var signTimeout = new CancellationTokenSource())
                {
                    normalOperationTimeout.CancelAfter(TimeSpan.FromMinutes(30));
                    var    hw     = new HardwareWalletService(webSocket);
                    var    model  = new WalletSendLedgerModel();
                    object result = null;
                    try
                    {
                        BTCPayNetwork network = null;
                        if (cryptoCode != null)
                        {
                            network = NetworkProvider.GetNetwork(cryptoCode);
                            if (network == null)
                            {
                                throw new FormatException("Invalid value for crypto code");
                            }
                        }

                        if (destination != null)
                        {
                            try
                            {
                                BitcoinAddress.Create(destination.Trim(), network.NBitcoinNetwork);
                                model.Destination = destination.Trim();
                            }
                            catch { }
                        }


                        if (feeRate != null)
                        {
                            try
                            {
                                model.FeeSatoshiPerByte = int.Parse(feeRate, CultureInfo.InvariantCulture);
                            }
                            catch { }
                            if (model.FeeSatoshiPerByte <= 0)
                            {
                                throw new FormatException("Invalid value for fee rate");
                            }
                        }

                        if (amount != null)
                        {
                            try
                            {
                                model.Amount = Money.Parse(amount).ToDecimal(MoneyUnit.BTC);
                            }
                            catch { }
                            if (model.Amount <= 0m)
                            {
                                throw new FormatException("Invalid value for amount");
                            }
                        }

                        model.SubstractFees = substractFees;
                        model.NoChange      = noChange;
                        model.DisableRBF    = disableRBF;
                        if (command == "test")
                        {
                            result = await hw.Test(normalOperationTimeout.Token);
                        }
                        if (command == "sendtoaddress")
                        {
                            if (!_dashboard.IsFullySynched(network.CryptoCode, out var summary))
                            {
                                throw new Exception($"{network.CryptoCode}: not started or fully synched");
                            }

                            var psbt = await CreatePSBT(network, derivationScheme, model, normalOperationTimeout.Token);

                            var strategy     = GetDirectDerivationStrategy(derivationScheme);
                            var storeBlob    = storeData.GetStoreBlob();
                            var paymentId    = new Payments.PaymentMethodId(cryptoCode, Payments.PaymentTypes.BTCLike);
                            var foundKeyPath = storeBlob.GetWalletKeyPathRoot(paymentId);
                            // Some deployment have the wallet root key path saved in the store blob
                            // If it does, we only have to make 1 call to the hw to check if it can sign the given strategy,
                            if (foundKeyPath == null || !await hw.CanSign(network, strategy, foundKeyPath, normalOperationTimeout.Token))
                            {
                                // If the saved wallet key path is not present or incorrect, let's scan the wallet to see if it can sign strategy
                                foundKeyPath = await hw.FindKeyPath(network, strategy, normalOperationTimeout.Token);

                                if (foundKeyPath == null)
                                {
                                    throw new HardwareWalletException($"This store is not configured to use this ledger");
                                }
                                storeBlob.SetWalletKeyPathRoot(paymentId, foundKeyPath);
                                storeData.SetStoreBlob(storeBlob);
                                await Repository.UpdateStore(storeData);
                            }

                            // NBX only know the path relative to the account xpub.
                            // Here we rebase the hd_keys in the PSBT to have a keypath relative to the root HD so the wallet can sign
                            // Note that the fingerprint of the hd keys are now 0, which is wrong
                            // However, hardware wallets does not give a damn, and sometimes does not even allow us to get this fingerprint anyway.
                            foreach (var o in psbt.PSBT.Inputs.OfType <PSBTCoin>().Concat(psbt.PSBT.Outputs))
                            {
                                foreach (var keypath in o.HDKeyPaths.ToList())
                                {
                                    var newKeyPath = foundKeyPath.Derive(keypath.Value.Item2);
                                    o.HDKeyPaths.Remove(keypath.Key);
                                    o.HDKeyPaths.Add(keypath.Key, Tuple.Create(default(HDFingerprint), newKeyPath));
                                }
                            }

                            signTimeout.CancelAfter(TimeSpan.FromMinutes(5));
                            psbt.PSBT = await hw.SignTransactionAsync(psbt.PSBT, psbt.ChangeAddress?.ScriptPubKey, signTimeout.Token);

                            if (!psbt.PSBT.TryFinalize(out var errors))
                            {
                                throw new Exception($"Error while finalizing the transaction ({new PSBTException(errors).ToString()})");
                            }
                            var transaction = psbt.PSBT.ExtractTransaction();
                            try
                            {
                                var broadcastResult = await ExplorerClientProvider.GetExplorerClient(network).BroadcastAsync(transaction);

                                if (!broadcastResult.Success)
                                {
                                    throw new Exception($"RPC Error while broadcasting: {broadcastResult.RPCCode} {broadcastResult.RPCCodeMessage} {broadcastResult.RPCMessage}");
                                }
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Error while broadcasting: " + ex.Message);
                            }
                            var wallet = _walletProvider.GetWallet(network);
                            wallet.InvalidateCache(derivationScheme);
                            result = new SendToAddressResult()
                            {
                                TransactionId = transaction.GetHash().ToString()
                            };
                        }
                    }
                    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, _mvcJsonOptions.Value.SerializerSettings));
                            await webSocket.SendAsync(new ArraySegment <byte>(bytes), WebSocketMessageType.Text, true, new CancellationTokenSource(2000).Token);
                        }
                    }
                    catch { }
                    finally
                    {
                        await webSocket.CloseSocket();
                    }
                }
            return(new EmptyResult());
        }
Esempio n. 4
0
 public static bool IsSupported(this PullPaymentData data, Payments.PaymentMethodId paymentId)
 {
     return(data.GetBlob().SupportedPaymentMethods.Contains(paymentId));
 }