private async Task OnNext(TransactionBroadcaster broadcaster) { var transactionInfo = _transactionInfo; var wallet = _owner.Wallet; var targetAnonymitySet = wallet.ServiceConfiguration.GetMixUntilAnonymitySetValue(); var mixedCoins = wallet.Coins.Where(x => x.HdPubKey.AnonymitySet >= targetAnonymitySet).ToList(); var totalMixedCoinsAmount = Money.FromUnit(mixedCoins.Sum(coin => coin.Amount), MoneyUnit.Satoshi); if (transactionInfo.Amount <= totalMixedCoinsAmount) { try { try { var txRes = await Task.Run(() => TransactionHelpers.BuildTransaction(wallet, transactionInfo.Address, transactionInfo.Amount, transactionInfo.Labels, transactionInfo.FeeRate, mixedCoins, subtractFee: false)); Navigate().To(new OptimisePrivacyViewModel(wallet, transactionInfo, broadcaster, txRes)); return; } catch (InsufficientBalanceException) { var txRes = await Task.Run(() => TransactionHelpers.BuildTransaction(wallet, transactionInfo.Address, totalMixedCoinsAmount, transactionInfo.Labels, transactionInfo.FeeRate, mixedCoins, subtractFee: true)); var dialog = new InsufficientBalanceDialogViewModel(BalanceType.Private, txRes, wallet.Synchronizer.UsdExchangeRate); var result = await NavigateDialog(dialog, NavigationTarget.DialogScreen); if (result.Result) { Navigate().To(new OptimisePrivacyViewModel(wallet, transactionInfo, broadcaster, txRes)); return; } } } catch (Exception ex) { Logger.LogError(ex); await ShowErrorAsync("Transaction Building", ex.ToUserFriendlyString(), "Wasabi was unable to create your transaction."); return; } } Navigate().To(new PrivacyControlViewModel(wallet, transactionInfo, broadcaster)); }
private async Task OnNext(Wallet wallet, TransactionInfo transactionInfo, TransactionBroadcaster broadcaster, IObservableList <PocketViewModel> selectedList) { var coins = selectedList.Items.SelectMany(x => x.Coins).ToArray(); try { try { var transactionResult = await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo.Address, transactionInfo.Amount, transactionInfo.Labels, transactionInfo.FeeRate, coins, subtractFee: false)); Navigate().To(new OptimisePrivacyViewModel(wallet, transactionInfo, broadcaster, transactionResult)); } catch (InsufficientBalanceException) { var transactionResult = await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo.Address, transactionInfo.Amount, transactionInfo.Labels, transactionInfo.FeeRate, coins, subtractFee: true)); var dialog = new InsufficientBalanceDialogViewModel(BalanceType.Pocket, transactionResult, wallet.Synchronizer.UsdExchangeRate); var result = await NavigateDialog(dialog, NavigationTarget.DialogScreen); if (result.Result) { Navigate().To(new OptimisePrivacyViewModel(wallet, transactionInfo, broadcaster, transactionResult)); } else { Navigate().BackTo <SendViewModel>(); } } } catch (Exception ex) { Logger.LogError(ex); await ShowErrorAsync("Transaction Building", ex.ToUserFriendlyString(), "Wasabi was unable to create your transaction."); Navigate().BackTo <SendViewModel>(); } }
public SendViewModel(WalletViewModel walletVm, TransactionBroadcaster broadcaster) : base(NavigationMode.Normal) { _to = ""; _owner = walletVm; _transactionInfo = new TransactionInfo(); _labels = new ObservableCollection <string>(); _lastXAxisCurrentValue = _xAxisCurrentValue; ExchangeRate = walletVm.Wallet.Synchronizer.UsdExchangeRate; PriorLabels = new(); this.ValidateProperty(x => x.To, ValidateToField); this.ValidateProperty(x => x.AmountBtc, ValidateAmount); this.WhenAnyValue(x => x.To) .Subscribe(ParseToField); this.WhenAnyValue(x => x.AmountBtc) .Subscribe(x => _transactionInfo.Amount = new Money(x, MoneyUnit.BTC)); this.WhenAnyValue(x => x.XAxisCurrentValue) .Subscribe(x => { if (x > 0) { _transactionInfo.FeeRate = new FeeRate(GetYAxisValueFromXAxisCurrentValue(x)); SetXAxisCurrentValueIndex(x); } }); this.WhenAnyValue(x => x.XAxisCurrentValueIndex) .Subscribe(SetXAxisCurrentValue); Labels.ToObservableChangeSet().Subscribe(x => { _transactionInfo.Labels = new SmartLabel(_labels.ToArray()); }); PasteCommand = ReactiveCommand.CreateFromTask(async() => { var text = await Application.Current.Clipboard.GetTextAsync(); _parsingUrl = true; if (!TryParseUrl(text)) { To = text; // todo validation errors. } _parsingUrl = false; }); var nextCommandCanExecute = this.WhenAnyValue(x => x.Labels, x => x.AmountBtc, x => x.To, x => x.XAxisCurrentValue).Select(_ => Unit.Default) .Merge(Observable.FromEventPattern(Labels, nameof(Labels.CollectionChanged)).Select(_ => Unit.Default)) .Select(_ => { var allFilled = !string.IsNullOrEmpty(To) && AmountBtc > 0 && Labels.Any(); var hasError = Validations.Any; return(allFilled && !hasError); }); NextCommand = ReactiveCommand.CreateFromTask(async() => { var transactionInfo = _transactionInfo; var wallet = _owner.Wallet; var targetAnonymitySet = wallet.ServiceConfiguration.GetMixUntilAnonymitySetValue(); var mixedCoins = wallet.Coins.Where(x => x.HdPubKey.AnonymitySet >= targetAnonymitySet).ToList(); var totalMixedCoinsAmount = Money.FromUnit(mixedCoins.Sum(coin => coin.Amount), MoneyUnit.Satoshi); if (transactionInfo.Amount <= totalMixedCoinsAmount) { try { try { var txRes = await Task.Run(() => TransactionHelpers.BuildTransaction(wallet, transactionInfo.Address, transactionInfo.Amount, transactionInfo.Labels, transactionInfo.FeeRate, mixedCoins, subtractFee: false)); Navigate().To(new OptimisePrivacyViewModel(wallet, transactionInfo, broadcaster, txRes)); return; } catch (InsufficientBalanceException) { var dialog = new InsufficientBalanceDialogViewModel(BalanceType.Private); var result = await NavigateDialog(dialog, NavigationTarget.DialogScreen); if (result.Result) { var txRes = await Task.Run(() => TransactionHelpers.BuildTransaction(wallet, transactionInfo.Address, totalMixedCoinsAmount, transactionInfo.Labels, transactionInfo.FeeRate, mixedCoins, subtractFee: true)); Navigate().To(new OptimisePrivacyViewModel(wallet, transactionInfo, broadcaster, txRes)); return; } } } catch (Exception ex) { Logger.LogError(ex); await ShowErrorAsync("Transaction Building", ex.ToUserFriendlyString(), "Wasabi was unable to create your transaction."); return; } } Navigate().To(new PrivacyControlViewModel(wallet, transactionInfo, broadcaster)); }, nextCommandCanExecute); EnableAutoBusyOn(NextCommand); }
public PrivacyControlViewModel(Wallet wallet, TransactionInfo transactionInfo, TransactionBroadcaster broadcaster) { _wallet = wallet; _pocketSource = new SourceList <PocketViewModel>(); _pocketSource.Connect() .Bind(out _pockets) .Subscribe(); var selected = _pocketSource.Connect() .AutoRefresh() .Filter(x => x.IsSelected); var selectedList = selected.AsObservableList(); selected.Sum(x => x.TotalBtc) .Subscribe(x => { StillNeeded = transactionInfo.Amount.ToDecimal(MoneyUnit.BTC) - x; EnoughSelected = StillNeeded <= 0; }); StillNeeded = transactionInfo.Amount.ToDecimal(MoneyUnit.BTC); NextCommand = ReactiveCommand.CreateFromTask( async() => { var coins = selectedList.Items.SelectMany(x => x.Coins).ToArray(); try { try { var transactionResult = await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo.Address, transactionInfo.Amount, transactionInfo.Labels, transactionInfo.FeeRate, coins, subtractFee: false)); Navigate().To(new TransactionPreviewViewModel(wallet, transactionInfo, broadcaster, transactionResult)); } catch (InsufficientBalanceException) { var dialog = new InsufficientBalanceDialogViewModel(BalanceType.Pocket); var result = await NavigateDialog(dialog, NavigationTarget.DialogScreen); if (result.Result) { var transactionResult = await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo.Address, transactionInfo.Amount, transactionInfo.Labels, transactionInfo.FeeRate, coins, subtractFee: true)); Navigate().To(new TransactionPreviewViewModel(wallet, transactionInfo, broadcaster, transactionResult)); } else { Navigate().BackTo <SendViewModel>(); } } } catch (Exception ex) { Logger.LogError(ex); await ShowErrorAsync("Transaction Building", ex.ToUserFriendlyString(), "Wasabi was unable to create your transaction."); Navigate().BackTo <SendViewModel>(); } }, this.WhenAnyValue(x => x.EnoughSelected)); EnableAutoBusyOn(NextCommand); }