public async Task <IActionResult> AddDerivationScheme(string storeId, DerivationSchemeViewModel vm, string cryptoCode) { vm.CryptoCode = cryptoCode; var store = HttpContext.GetStoreData(); if (store == null) { return(NotFound()); } var network = cryptoCode == null ? null : _ExplorerProvider.GetNetwork(cryptoCode); if (network == null) { return(NotFound()); } vm.Network = network; vm.RootKeyPath = network.GetRootKeyPath(); DerivationSchemeSettings strategy = null; var wallet = _WalletProvider.GetWallet(network); if (wallet == null) { return(NotFound()); } if (!string.IsNullOrEmpty(vm.Config)) { if (!DerivationSchemeSettings.TryParseFromJson(vm.Config, network, out strategy)) { TempData.SetStatusMessageModel(new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Error, Message = "Config file was not in the correct format" }); vm.Confirmation = false; return(View(vm)); } } if (vm.ColdcardPublicFile != null) { if (!DerivationSchemeSettings.TryParseFromColdcard(await ReadAllText(vm.ColdcardPublicFile), network, out strategy)) { TempData.SetStatusMessageModel(new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Error, Message = "Coldcard public file was not in the correct format" }); vm.Confirmation = false; return(View(vm)); } } else { try { if (!string.IsNullOrEmpty(vm.DerivationScheme)) { var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, null, network); if (newStrategy.AccountDerivation != strategy?.AccountDerivation) { var accountKey = string.IsNullOrEmpty(vm.AccountKey) ? null : new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork); if (accountKey != null) { var accountSettings = newStrategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey); if (accountSettings != null) { accountSettings.AccountKeyPath = vm.KeyPath == null ? null : KeyPath.Parse(vm.KeyPath); accountSettings.RootFingerprint = string.IsNullOrEmpty(vm.RootFingerprint) ? (HDFingerprint?)null : new HDFingerprint(NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint)); } } strategy = newStrategy; strategy.Source = vm.Source; vm.DerivationScheme = strategy.AccountDerivation.ToString(); } } else { strategy = null; } } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid Derivation Scheme"); vm.Confirmation = false; return(View(vm)); } } var oldConfig = vm.Config; vm.Config = strategy == null ? null : strategy.ToJson(); PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike); var exisingStrategy = store.GetSupportedPaymentMethods(_NetworkProvider) .Where(c => c.PaymentId == paymentMethodId) .OfType <DerivationSchemeSettings>() .FirstOrDefault(); var storeBlob = store.GetStoreBlob(); var wasExcluded = storeBlob.GetExcludedPaymentMethods().Match(paymentMethodId); var willBeExcluded = !vm.Enabled; var showAddress = // Show addresses if: // - If the user is testing the hint address in confirmation screen (vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) || // - The user is clicking on continue after changing the config (!vm.Confirmation && oldConfig != vm.Config) || // - The user is clickingon continue without changing config nor enabling/disabling (!vm.Confirmation && oldConfig == vm.Config && willBeExcluded == wasExcluded); showAddress = showAddress && strategy != null; if (!showAddress) { try { if (strategy != null) { await wallet.TrackAsync(strategy.AccountDerivation); } store.SetSupportedPaymentMethod(paymentMethodId, strategy); storeBlob.SetExcluded(paymentMethodId, willBeExcluded); store.SetStoreBlob(storeBlob); } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid Derivation Scheme"); return(View(vm)); } await _Repo.UpdateStore(store); if (willBeExcluded != wasExcluded) { var label = willBeExcluded ? "disabled" : "enabled"; TempData[WellKnownTempData.SuccessMessage] = $"On-Chain payments for {network.CryptoCode} has been {label}."; } else { TempData[WellKnownTempData.SuccessMessage] = $"Derivation settings for {network.CryptoCode} has been modified."; } return(RedirectToAction(nameof(UpdateStore), new { storeId = storeId })); } else if (!string.IsNullOrEmpty(vm.HintAddress)) { BitcoinAddress address = null; try { address = BitcoinAddress.Create(vm.HintAddress, network.NBitcoinNetwork); } catch { ModelState.AddModelError(nameof(vm.HintAddress), "Invalid hint address"); return(ShowAddresses(vm, strategy)); } try { var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, address.ScriptPubKey, network); if (newStrategy.AccountDerivation != strategy.AccountDerivation) { strategy.AccountDerivation = newStrategy.AccountDerivation; strategy.AccountOriginal = null; } } catch { ModelState.AddModelError(nameof(vm.HintAddress), "Impossible to find a match with this address"); return(ShowAddresses(vm, strategy)); } vm.HintAddress = ""; TempData[WellKnownTempData.SuccessMessage] = "Address successfully found, please verify that the rest is correct and click on \"Confirm\""; ModelState.Remove(nameof(vm.HintAddress)); ModelState.Remove(nameof(vm.DerivationScheme)); } return(ShowAddresses(vm, strategy)); }
public async Task <IActionResult> UpdateWallet(WalletSetupViewModel vm) { var checkResult = IsAvailable(vm.CryptoCode, out var store, out var network); if (checkResult != null) { return(checkResult); } vm.Network = network; vm.RootKeyPath = network.GetRootKeyPath(); DerivationSchemeSettings strategy = null; var wallet = _WalletProvider.GetWallet(network); if (wallet == null) { return(NotFound()); } if (!string.IsNullOrEmpty(vm.Config)) { if (!DerivationSchemeSettings.TryParseFromJson(vm.Config, network, out strategy)) { ModelState.AddModelError(nameof(vm.Config), "Config file was not in the correct format"); return(View(vm.ViewName, vm)); } } if (vm.WalletFile != null) { if (!DerivationSchemeSettings.TryParseFromWalletFile(await ReadAllText(vm.WalletFile), network, out strategy)) { ModelState.AddModelError(nameof(vm.WalletFile), "Wallet file was not in the correct format"); return(View(vm.ViewName, vm)); } } else if (!string.IsNullOrEmpty(vm.WalletFileContent)) { if (!DerivationSchemeSettings.TryParseFromWalletFile(vm.WalletFileContent, network, out strategy)) { ModelState.AddModelError(nameof(vm.WalletFileContent), "QR import was not in the correct format"); return(View(vm.ViewName, vm)); } } else if (!string.IsNullOrEmpty(vm.DerivationScheme)) { try { var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, null, network); if (newStrategy.AccountDerivation != strategy?.AccountDerivation) { var accountKey = string.IsNullOrEmpty(vm.AccountKey) ? null : new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork); if (accountKey != null) { var accountSettings = newStrategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey); if (accountSettings != null) { accountSettings.AccountKeyPath = vm.KeyPath == null ? null : KeyPath.Parse(vm.KeyPath); accountSettings.RootFingerprint = string.IsNullOrEmpty(vm.RootFingerprint) ? (HDFingerprint?)null : new HDFingerprint( NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint)); } } strategy = newStrategy; strategy.Source = vm.Source; vm.DerivationScheme = strategy.AccountDerivation.ToString(); } } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid wallet format"); return(View(vm.ViewName, vm)); } } else { ModelState.AddModelError(nameof(vm.DerivationScheme), "Please provide your extended public key"); return(View(vm.ViewName, vm)); } var oldConfig = vm.Config; vm.Config = strategy?.ToJson(); var configChanged = oldConfig != vm.Config; PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike); var storeBlob = store.GetStoreBlob(); var wasExcluded = storeBlob.GetExcludedPaymentMethods().Match(paymentMethodId); var willBeExcluded = !vm.Enabled; var excludedChanged = willBeExcluded != wasExcluded; var showAddress = // Show addresses if: // - If the user is testing the hint address in confirmation screen (vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) || // - The user is clicking on continue after changing the config (!vm.Confirmation && configChanged); showAddress = showAddress && strategy != null; if (!showAddress) { try { if (strategy != null) { await wallet.TrackAsync(strategy.AccountDerivation); } store.SetSupportedPaymentMethod(paymentMethodId, strategy); storeBlob.SetExcluded(paymentMethodId, willBeExcluded); storeBlob.Hints.Wallet = false; store.SetStoreBlob(storeBlob); } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid derivation scheme"); return(View(vm.ViewName, vm)); } await _Repo.UpdateStore(store); _EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(vm.StoreId, vm.CryptoCode) }); if (excludedChanged) { var label = willBeExcluded ? "disabled" : "enabled"; TempData[WellKnownTempData.SuccessMessage] = $"On-Chain payments for {network.CryptoCode} have been {label}."; } else { TempData[WellKnownTempData.SuccessMessage] = $"Derivation settings for {network.CryptoCode} have been modified."; } // This is success case when derivation scheme is added to the store return(RedirectToAction(nameof(UpdateStore), new { storeId = vm.StoreId })); } if (!string.IsNullOrEmpty(vm.HintAddress)) { BitcoinAddress address; try { address = BitcoinAddress.Create(vm.HintAddress, network.NBitcoinNetwork); } catch { ModelState.AddModelError(nameof(vm.HintAddress), "Invalid hint address"); return(ConfirmAddresses(vm, strategy)); } try { var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, address.ScriptPubKey, network); if (newStrategy.AccountDerivation != strategy.AccountDerivation) { strategy.AccountDerivation = newStrategy.AccountDerivation; strategy.AccountOriginal = null; } } catch { ModelState.AddModelError(nameof(vm.HintAddress), "Impossible to find a match with this address. Are you sure the wallet and address provided are correct and from the same source?"); return(ConfirmAddresses(vm, strategy)); } vm.HintAddress = ""; TempData[WellKnownTempData.SuccessMessage] = "Address successfully found, please verify that the rest is correct and click on \"Confirm\""; ModelState.Remove(nameof(vm.HintAddress)); ModelState.Remove(nameof(vm.DerivationScheme)); } return(ConfirmAddresses(vm, strategy)); }
public async Task <IActionResult> UpdateWallet(WalletSetupViewModel vm) { var checkResult = IsAvailable(vm.CryptoCode, out var store, out var network); if (checkResult != null) { return(checkResult); } vm.Network = network; DerivationSchemeSettings strategy = null; var wallet = _WalletProvider.GetWallet(network); if (wallet == null) { return(NotFound()); } if (vm.WalletFile != null) { if (!DerivationSchemeSettings.TryParseFromWalletFile(await ReadAllText(vm.WalletFile), network, out strategy)) { ModelState.AddModelError(nameof(vm.WalletFile), "Wallet file was not in the correct format"); return(View(vm.ViewName, vm)); } } else if (!string.IsNullOrEmpty(vm.WalletFileContent)) { if (!DerivationSchemeSettings.TryParseFromWalletFile(vm.WalletFileContent, network, out strategy)) { ModelState.AddModelError(nameof(vm.WalletFileContent), "QR import was not in the correct format"); return(View(vm.ViewName, vm)); } } else if (!string.IsNullOrEmpty(vm.DerivationScheme)) { try { strategy = ParseDerivationStrategy(vm.DerivationScheme, network); strategy.Source = "ManualDerivationScheme"; if (!string.IsNullOrEmpty(vm.AccountKey)) { var accountKey = new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork); var accountSettings = strategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey); if (accountSettings != null) { accountSettings.AccountKeyPath = vm.KeyPath == null ? null : KeyPath.Parse(vm.KeyPath); accountSettings.RootFingerprint = string.IsNullOrEmpty(vm.RootFingerprint) ? (HDFingerprint?)null : new HDFingerprint( NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint)); } } vm.DerivationScheme = strategy.AccountDerivation.ToString(); ModelState.Remove(nameof(vm.DerivationScheme)); } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid wallet format"); return(View(vm.ViewName, vm)); } } else if (!string.IsNullOrEmpty(vm.Config)) { if (!DerivationSchemeSettings.TryParseFromJson(UnprotectString(vm.Config), network, out strategy)) { ModelState.AddModelError(nameof(vm.Config), "Config file was not in the correct format"); return(View(vm.ViewName, vm)); } } if (strategy is null) { ModelState.AddModelError(nameof(vm.DerivationScheme), "Please provide your extended public key"); return(View(vm.ViewName, vm)); } vm.Config = ProtectString(strategy.ToJson()); ModelState.Remove(nameof(vm.Config)); PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike); var storeBlob = store.GetStoreBlob(); if (vm.Confirmation) { try { await wallet.TrackAsync(strategy.AccountDerivation); store.SetSupportedPaymentMethod(paymentMethodId, strategy); storeBlob.SetExcluded(paymentMethodId, false); storeBlob.Hints.Wallet = false; storeBlob.PayJoinEnabled = strategy.IsHotWallet && !(vm.SetupRequest?.PayJoinEnabled is false); store.SetStoreBlob(storeBlob); } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid derivation scheme"); return(View(vm.ViewName, vm)); } await _Repo.UpdateStore(store); _EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(vm.StoreId, vm.CryptoCode) }); TempData[WellKnownTempData.SuccessMessage] = $"Wallet settings for {network.CryptoCode} have been updated."; // This is success case when derivation scheme is added to the store return(RedirectToAction(nameof(UpdateStore), new { storeId = vm.StoreId })); } return(ConfirmAddresses(vm, strategy)); }
public async Task <IActionResult> AddDerivationScheme(string storeId, DerivationSchemeViewModel vm, string cryptoCode) { vm.CryptoCode = cryptoCode; var store = HttpContext.GetStoreData(); if (store == null) { return(NotFound()); } var network = cryptoCode == null ? null : _ExplorerProvider.GetNetwork(cryptoCode); if (network == null) { return(NotFound()); } vm.RootKeyPath = network.GetRootKeyPath(); DerivationSchemeSettings strategy = null; var wallet = _WalletProvider.GetWallet(network); if (wallet == null) { return(NotFound()); } if (!string.IsNullOrEmpty(vm.Config)) { if (!DerivationSchemeSettings.TryParseFromJson(vm.Config, network, out strategy)) { vm.StatusMessage = new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Error, Message = "El archivo de configuración no estaba en el formato correcto" }.ToString(); vm.Confirmation = false; return(View(vm)); } } if (vm.ColdcardPublicFile != null) { if (!DerivationSchemeSettings.TryParseFromColdcard(await ReadAllText(vm.ColdcardPublicFile), network, out strategy)) { vm.StatusMessage = new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Error, Message = "El archivo público de Coldcard no estaba en el formato correcto" }.ToString(); vm.Confirmation = false; return(View(vm)); } } else { try { if (!string.IsNullOrEmpty(vm.DerivationScheme)) { var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, null, network); if (newStrategy.AccountDerivation != strategy?.AccountDerivation) { var accountKey = string.IsNullOrEmpty(vm.AccountKey) ? null : new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork); if (accountKey != null) { var accountSettings = newStrategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey); if (accountSettings != null) { accountSettings.AccountKeyPath = vm.KeyPath == null ? null : KeyPath.Parse(vm.KeyPath); accountSettings.RootFingerprint = string.IsNullOrEmpty(vm.RootFingerprint) ? (HDFingerprint?)null : new HDFingerprint(NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint)); } } strategy = newStrategy; strategy.Source = vm.Source; vm.DerivationScheme = strategy.AccountDerivation.ToString(); } } else { strategy = null; } } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Esquema de derivación no válido"); vm.Confirmation = false; return(View(vm)); } } var oldConfig = vm.Config; vm.Config = strategy == null ? null : strategy.ToJson(); PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike); var exisingStrategy = store.GetSupportedPaymentMethods(_NetworkProvider) .Where(c => c.PaymentId == paymentMethodId) .OfType <DerivationSchemeSettings>() .FirstOrDefault(); var storeBlob = store.GetStoreBlob(); var wasExcluded = storeBlob.GetExcludedPaymentMethods().Match(paymentMethodId); var willBeExcluded = !vm.Enabled; var showAddress = // Show addresses if: // - If the user is testing the hint address in confirmation screen (vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) || // - The user is clicking on continue after changing the config (!vm.Confirmation && oldConfig != vm.Config) || // - The user is clickingon continue without changing config nor enabling/disabling (!vm.Confirmation && oldConfig == vm.Config && willBeExcluded == wasExcluded); showAddress = showAddress && strategy != null; if (!showAddress) { try { if (strategy != null) { await wallet.TrackAsync(strategy.AccountDerivation); } store.SetSupportedPaymentMethod(paymentMethodId, strategy); storeBlob.SetExcluded(paymentMethodId, willBeExcluded); store.SetStoreBlob(storeBlob); } catch { ModelState.AddModelError(nameof(vm.DerivationScheme), "Esquema de derivación no válido"); return(View(vm)); } await _Repo.UpdateStore(store); if (oldConfig != vm.Config) { StatusMessage = $"Ajustes de derivación para{network.CryptoCode} ha sido modificado."; } if (willBeExcluded != wasExcluded) { var label = willBeExcluded ? "desactivado" : "activado"; StatusMessage = $"Pagos en cadena para {network.CryptoCode} ha sido {label}."; } return(RedirectToAction(nameof(UpdateStore), new { storeId = storeId })); } else if (!string.IsNullOrEmpty(vm.HintAddress)) { BitcoinAddress address = null; try { address = BitcoinAddress.Create(vm.HintAddress, network.NBitcoinNetwork); } catch { ModelState.AddModelError(nameof(vm.HintAddress), "Dirección de sugerencia no válida"); return(ShowAddresses(vm, strategy)); } try { var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, address.ScriptPubKey, network); if (newStrategy.AccountDerivation != strategy.AccountDerivation) { strategy.AccountDerivation = newStrategy.AccountDerivation; strategy.AccountOriginal = null; } } catch { ModelState.AddModelError(nameof(vm.HintAddress), "Imposible encontrar una coincidencia con esta dirección"); return(ShowAddresses(vm, strategy)); } vm.HintAddress = ""; vm.StatusMessage = "Dirección encontrada con éxito, verifique que el resto sea correcto y haga clic en \"Confirm\""; ModelState.Remove(nameof(vm.HintAddress)); ModelState.Remove(nameof(vm.DerivationScheme)); } return(ShowAddresses(vm, strategy)); }