Ejemplo n.º 1
0
        public async Task <IActionResult> SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))]
                                                       WalletId walletId, SignWithSeedViewModel viewModel)
        {
            if (!ModelState.IsValid)
            {
                return(View(viewModel));
            }
            var network = NetworkProvider.GetNetwork <BTCPayNetwork>(walletId.CryptoCode);

            if (network == null)
            {
                throw new FormatException("Invalid value for crypto code");
            }

            ExtKey extKey = viewModel.GetExtKey(network.NBitcoinNetwork);

            if (extKey == null)
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey),
                                         "Seed or Key was not in a valid format. It is either the 12/24 words or starts with xprv");
            }

            var psbt = PSBT.Parse(viewModel.PSBT, network.NBitcoinNetwork);

            if (!psbt.IsReadyToSign())
            {
                ModelState.AddModelError(nameof(viewModel.PSBT), "PSBT is not ready to be signed");
            }

            if (!ModelState.IsValid)
            {
                return(View(viewModel));
            }

            ExtKey signingKey         = null;
            var    settings           = GetDerivationSchemeSettings(walletId);
            var    signingKeySettings = settings.GetSigningAccountKeySettings();

            if (signingKeySettings.RootFingerprint is null)
            {
                signingKeySettings.RootFingerprint = extKey.GetPublicKey().GetHDFingerPrint();
            }

            RootedKeyPath rootedKeyPath = signingKeySettings.GetRootedKeyPath();

            if (rootedKeyPath == null)
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey), "The master fingerprint and/or account key path of your seed are not set in the wallet settings.");
                return(View(viewModel));
            }
            // The user gave the root key, let's try to rebase the PSBT, and derive the account private key
            if (rootedKeyPath.MasterFingerprint == extKey.GetPublicKey().GetHDFingerPrint())
            {
                psbt.RebaseKeyPaths(signingKeySettings.AccountKey, rootedKeyPath);
                signingKey = extKey.Derive(rootedKeyPath.KeyPath);
            }
            else
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey), "The master fingerprint does not match the one set in your wallet settings. Probable cause are: wrong seed, wrong passphrase or wrong fingerprint in your wallet settings.");
                return(View(viewModel));
            }

            var changed = PSBTChanged(psbt, () => psbt.SignAll(settings.AccountDerivation, signingKey, rootedKeyPath));

            if (!changed)
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey), "Impossible to sign the transaction. Probable cause: Incorrect account key path in wallet settings, PSBT already signed.");
                return(View(viewModel));
            }
            ModelState.Remove(nameof(viewModel.PSBT));
            return(await WalletPSBTReady(walletId, psbt.ToBase64(), signingKey.GetWif(network.NBitcoinNetwork).ToString(), rootedKeyPath?.ToString()));
        }
Ejemplo n.º 2
0
        public async Task <IActionResult> SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))]
                                                       WalletId walletId, SignWithSeedViewModel viewModel)
        {
            if (!ModelState.IsValid)
            {
                return(View(viewModel));
            }
            var network = NetworkProvider.GetNetwork <BTCPayNetwork>(walletId.CryptoCode);

            if (network == null)
            {
                throw new FormatException("Invalid value for crypto code");
            }

            ExtKey extKey = viewModel.GetExtKey(network.NBitcoinNetwork);

            if (extKey == null)
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey),
                                         "Seed or Key was not in a valid format. It is either the 12/24 words or starts with xprv");
            }

            var psbt = PSBT.Parse(viewModel.PSBT, network.NBitcoinNetwork);

            if (!psbt.IsReadyToSign())
            {
                ModelState.AddModelError(nameof(viewModel.PSBT), "PSBT is not ready to be signed");
            }

            if (!ModelState.IsValid)
            {
                return(View(viewModel));
            }

            ExtKey signingKey         = null;
            var    settings           = GetDerivationSchemeSettings(walletId);
            var    signingKeySettings = settings.GetSigningAccountKeySettings();

            if (signingKeySettings.RootFingerprint is null)
            {
                signingKeySettings.RootFingerprint = extKey.GetPublicKey().GetHDFingerPrint();
            }

            RootedKeyPath rootedKeyPath = signingKeySettings.GetRootedKeyPath();

            // The user gave the root key, let's try to rebase the PSBT, and derive the account private key
            if (rootedKeyPath?.MasterFingerprint == extKey.GetPublicKey().GetHDFingerPrint())
            {
                psbt.RebaseKeyPaths(signingKeySettings.AccountKey, rootedKeyPath);
                signingKey = extKey.Derive(rootedKeyPath.KeyPath);
            }
            // The user maybe gave the account key, let's try to sign with it
            else
            {
                signingKey = extKey;
            }
            var balanceChange = psbt.GetBalance(settings.AccountDerivation, signingKey, rootedKeyPath);

            if (balanceChange == Money.Zero)
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey), "This seed is unable to sign this transaction. Either the seed is incorrect, or the account path has not been properly configured in the Wallet Settings.");
                return(View(viewModel));
            }
            psbt.SignAll(settings.AccountDerivation, signingKey, rootedKeyPath);
            ModelState.Remove(nameof(viewModel.PSBT));
            return(await WalletPSBTReady(walletId, psbt.ToBase64(), signingKey.GetWif(network.NBitcoinNetwork).ToString(), rootedKeyPath?.ToString()));
        }
Ejemplo n.º 3
0
        private async Task FetchTransactionDetails(WalletId walletId, WalletPSBTReadyViewModel vm, BTCPayNetwork network)
        {
            var           psbtObject     = PSBT.Parse(vm.PSBT, network.NBitcoinNetwork);
            IHDKey        signingKey     = null;
            RootedKeyPath signingKeyPath = null;

            try
            {
                signingKey = new BitcoinExtPubKey(vm.SigningKey, network.NBitcoinNetwork);
            }
            catch { }
            try
            {
                signingKey = signingKey ?? new BitcoinExtKey(vm.SigningKey, network.NBitcoinNetwork);
            }
            catch { }

            try
            {
                signingKeyPath = RootedKeyPath.Parse(vm.SigningKeyPath);
            }
            catch { }

            var derivationSchemeSettings = await GetDerivationSchemeSettings(walletId);

            if (signingKey == null || signingKeyPath == null)
            {
                var signingKeySettings = derivationSchemeSettings.GetSigningAccountKeySettings();
                if (signingKey == null)
                {
                    signingKey    = signingKeySettings.AccountKey;
                    vm.SigningKey = signingKey.ToString();
                }
                if (vm.SigningKeyPath == null)
                {
                    signingKeyPath    = signingKeySettings.GetRootedKeyPath();
                    vm.SigningKeyPath = signingKeyPath?.ToString();
                }
            }

            if (psbtObject.IsAllFinalized())
            {
                vm.CanCalculateBalance = false;
            }
            else
            {
                var balanceChange = psbtObject.GetBalance(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath);
                vm.BalanceChange       = ValueToString(balanceChange, network);
                vm.CanCalculateBalance = true;
                vm.Positive            = balanceChange >= Money.Zero;
            }

            foreach (var output in psbtObject.Outputs)
            {
                var dest = new WalletPSBTReadyViewModel.DestinationViewModel();
                vm.Destinations.Add(dest);
                var mine           = output.HDKeysFor(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath).Any();
                var balanceChange2 = output.Value;
                if (!mine)
                {
                    balanceChange2 = -balanceChange2;
                }
                dest.Balance     = ValueToString(balanceChange2, network);
                dest.Positive    = balanceChange2 >= Money.Zero;
                dest.Destination = output.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork)?.ToString() ?? output.ScriptPubKey.ToString();
            }

            if (psbtObject.TryGetFee(out var fee))
            {
                vm.Destinations.Add(new WalletPSBTReadyViewModel.DestinationViewModel()
                {
                    Positive    = false,
                    Balance     = ValueToString(-fee, network),
                    Destination = "Mining fees"
                });
            }
            if (psbtObject.TryGetEstimatedFeeRate(out var feeRate))
            {
                vm.FeeRate = feeRate.ToString();
            }

            if (!psbtObject.IsAllFinalized() && !psbtObject.TryFinalize(out var errors))
            {
                vm.SetErrors(errors);
            }
        }
Ejemplo n.º 4
0
        private async Task FetchTransactionDetails(DerivationSchemeSettings derivationSchemeSettings, WalletPSBTReadyViewModel vm, BTCPayNetwork network)
        {
            var psbtObject = PSBT.Parse(vm.SigningContext.PSBT, network.NBitcoinNetwork);

            if (!psbtObject.IsAllFinalized())
            {
                psbtObject = await ExplorerClientProvider.UpdatePSBT(derivationSchemeSettings, psbtObject) ?? psbtObject;
            }
            IHDKey        signingKey     = null;
            RootedKeyPath signingKeyPath = null;

            try
            {
                signingKey = new BitcoinExtPubKey(vm.SigningKey, network.NBitcoinNetwork);
            }
            catch { }
            try
            {
                signingKey = signingKey ?? new BitcoinExtKey(vm.SigningKey, network.NBitcoinNetwork);
            }
            catch { }

            try
            {
                signingKeyPath = RootedKeyPath.Parse(vm.SigningKeyPath);
            }
            catch { }

            if (signingKey == null || signingKeyPath == null)
            {
                var signingKeySettings = derivationSchemeSettings.GetSigningAccountKeySettings();
                if (signingKey == null)
                {
                    signingKey    = signingKeySettings.AccountKey;
                    vm.SigningKey = signingKey.ToString();
                }
                if (vm.SigningKeyPath == null)
                {
                    signingKeyPath    = signingKeySettings.GetRootedKeyPath();
                    vm.SigningKeyPath = signingKeyPath?.ToString();
                }
            }

            if (psbtObject.IsAllFinalized())
            {
                vm.CanCalculateBalance = false;
            }
            else
            {
                var balanceChange = psbtObject.GetBalance(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath);
                vm.BalanceChange       = ValueToString(balanceChange, network);
                vm.CanCalculateBalance = true;
                vm.Positive            = balanceChange >= Money.Zero;
            }
            vm.Inputs = new List <WalletPSBTReadyViewModel.InputViewModel>();
            foreach (var input in psbtObject.Inputs)
            {
                var inputVm = new WalletPSBTReadyViewModel.InputViewModel();
                vm.Inputs.Add(inputVm);
                var mine           = input.HDKeysFor(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath).Any();
                var balanceChange2 = input.GetTxOut()?.Value ?? Money.Zero;
                if (mine)
                {
                    balanceChange2 = -balanceChange2;
                }
                inputVm.BalanceChange = ValueToString(balanceChange2, network);
                inputVm.Positive      = balanceChange2 >= Money.Zero;
                inputVm.Index         = (int)input.Index;
            }
            vm.Destinations = new List <WalletPSBTReadyViewModel.DestinationViewModel>();
            foreach (var output in psbtObject.Outputs)
            {
                var dest = new WalletPSBTReadyViewModel.DestinationViewModel();
                vm.Destinations.Add(dest);
                var mine           = output.HDKeysFor(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath).Any();
                var balanceChange2 = output.Value;
                if (!mine)
                {
                    balanceChange2 = -balanceChange2;
                }
                dest.Balance     = ValueToString(balanceChange2, network);
                dest.Positive    = balanceChange2 >= Money.Zero;
                dest.Destination = output.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork)?.ToString() ?? output.ScriptPubKey.ToString();
            }

            if (psbtObject.TryGetFee(out var fee))
            {
                vm.Destinations.Add(new WalletPSBTReadyViewModel.DestinationViewModel
                {
                    Positive    = false,
                    Balance     = ValueToString(-fee, network),
                    Destination = "Mining fees"
                });
            }
            if (psbtObject.TryGetEstimatedFeeRate(out var feeRate))
            {
                vm.FeeRate = feeRate.ToString();
            }

            var sanityErrors = psbtObject.CheckSanity();

            if (sanityErrors.Count != 0)
            {
                vm.SetErrors(sanityErrors);
            }
            else if (!psbtObject.IsAllFinalized() && !psbtObject.TryFinalize(out var errors))
            {
                vm.SetErrors(errors);
            }
        }
        public async Task <IActionResult> SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))]
                                                       WalletId walletId, SignWithSeedViewModel viewModel)
        {
            if (!ModelState.IsValid)
            {
                return(View(viewModel));
            }
            var network = NetworkProvider.GetNetwork(walletId.CryptoCode);

            if (network == null)
            {
                throw new FormatException("Valor no válido para el código criptográfico");
            }

            ExtKey extKey = viewModel.GetExtKey(network.NBitcoinNetwork);

            if (extKey == null)
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey),
                                         "La seed o la clave no estaban en un formato válido. Es el 12/24 palabras o comienza con xprv");
            }

            var psbt = PSBT.Parse(viewModel.PSBT, network.NBitcoinNetwork);

            if (!psbt.IsReadyToSign())
            {
                ModelState.AddModelError(nameof(viewModel.PSBT), "PSBT no está listo para ser firmado");
            }

            if (!ModelState.IsValid)
            {
                return(View(viewModel));
            }

            ExtKey signingKey         = null;
            var    settings           = (await GetDerivationSchemeSettings(walletId));
            var    signingKeySettings = settings.GetSigningAccountKeySettings();

            if (signingKeySettings.RootFingerprint is null)
            {
                signingKeySettings.RootFingerprint = extKey.GetPublicKey().GetHDFingerPrint();
            }

            RootedKeyPath rootedKeyPath = signingKeySettings.GetRootedKeyPath();

            // The user gave the root key, let's try to rebase the PSBT, and derive the account private key
            if (rootedKeyPath?.MasterFingerprint == extKey.GetPublicKey().GetHDFingerPrint())
            {
                psbt.RebaseKeyPaths(signingKeySettings.AccountKey, rootedKeyPath);
                signingKey = extKey.Derive(rootedKeyPath.KeyPath);
            }
            // The user maybe gave the account key, let's try to sign with it
            else
            {
                signingKey = extKey;
            }
            var balanceChange = psbt.GetBalance(settings.AccountDerivation, signingKey, rootedKeyPath);

            if (balanceChange == Money.Zero)
            {
                ModelState.AddModelError(nameof(viewModel.SeedOrKey), "Esta seed no parece poder firmar esta transacción. Esta es la clave incorrecta o la configuración de la cartera no tiene la ruta de cuenta correcta en la configuración de la cartera.");
                return(View(viewModel));
            }
            psbt.SignAll(settings.AccountDerivation, signingKey, rootedKeyPath);
            ModelState.Remove(nameof(viewModel.PSBT));
            return(await WalletPSBTReady(walletId, psbt.ToBase64(), signingKey.GetWif(network.NBitcoinNetwork).ToString(), rootedKeyPath.ToString()));
        }