public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel)
        {
            ClearSensitiveData(true);

            ToggleSensitiveKeysCommand = ReactiveCommand.Create(() =>
            {
                try
                {
                    if (ShowSensitiveKeys)
                    {
                        ClearSensitiveData(true);
                    }
                    else
                    {
                        var secret = PasswordHelper.GetMasterExtKey(KeyManager, Password, out string isCompatibilityPasswordUsed);
                        Password   = "";

                        if (isCompatibilityPasswordUsed != null)
                        {
                            NotificationHelpers.Warning(PasswordHelper.CompatibilityPasswordWarnMessage);
                        }

                        string master   = secret.GetWif(Global.Network).ToWif();
                        string account  = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif();
                        string masterZ  = secret.ToZPrv(Global.Network);
                        string accountZ = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network);
                        SetSensitiveData(master, account, masterZ, accountZ);
                    }
                }
                catch (Exception ex)
                {
                    NotificationHelpers.Error(ex.ToTypeMessageString());
                }
            });
        }
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Interlocked.Exchange(ref _disableClipboard, 0);
            Transactions = new ObservableCollection <TransactionViewModel>();
            RewriteTable();

            Global.WalletService.NewBlockProcessed           += WalletService_NewBlockProcessed;
            Global.WalletService.Coins.CollectionChanged     += Coins_CollectionChanged;
            Global.WalletService.CoinSpentOrSpenderConfirmed += WalletService_CoinSpent;

            this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction =>
            {
                if (Interlocked.Read(ref _disableClipboard) == 0)
                {
                    if (transaction != null)
                    {
                        await Application.Current.Clipboard.SetTextAsync(transaction.TransactionId);
                        ClipboardNotificationVisible = true;
                        ClipboardNotificationOpacity = 1;

                        Dispatcher.UIThread.Post(async() =>
                        {
                            await Task.Delay(1000);
                            ClipboardNotificationOpacity = 0;
                        });
                    }
                }
                else
                {
                    Interlocked.Exchange(ref _disableClipboard, 0);
                }
            });
        }
        public CoinJoinTabViewModel(WalletViewModel walletViewModel)
            : base("CoinJoin", walletViewModel)
        {
            Password = "";

            var onCoinsSetModified = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged))
                                     .ObserveOn(RxApp.MainThreadScheduler);

            var globalCoins = Global.WalletService.Coins.CreateDerivedCollection(c => new CoinViewModel(c), null, (first, second) => second.Amount.CompareTo(first.Amount), signalReset: onCoinsSetModified, RxApp.MainThreadScheduler);

            globalCoins.ChangeTrackingEnabled = true;

            var available = globalCoins.CreateDerivedCollection(c => c, c => c.Confirmed && !c.SpentOrCoinJoinInProgress);

            var queued = globalCoins.CreateDerivedCollection(c => c, c => c.CoinJoinInProgress);

            var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault();

            UpdateRequiredBtcLabel(registrableRound, available, queued);

            if (registrableRound != default)
            {
                CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString();
            }
            else
            {
                CoordinatorFeePercent = "0.003";
            }

            if (!(registrableRound?.State?.Denomination is null) && registrableRound.State.Denomination != Money.Zero)
            {
                AvailableCoinsList = new CoinListViewModel(available, RequiredBTC, PreSelectMaxAnonSetExcludingCondition);
            }
Beispiel #4
0
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Disposables  = new CompositeDisposable();
            Transactions = new ObservableCollection <TransactionViewModel>();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            RewriteTableAsync();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

            var coinsChanged      = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged));
            var newBlockProcessed = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.NewBlockProcessed));
            var coinSpent         = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.CoinSpentOrSpenderConfirmed));

            coinsChanged
            .Merge(newBlockProcessed)
            .Merge(coinSpent)
            .Throttle(TimeSpan.FromSeconds(5))
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                RewriteTableAsync();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            }).DisposeWith(Disposables);

            this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(transaction => transaction?.CopyToClipboard()).DisposeWith(Disposables);

            SortCommand = ReactiveCommand.Create(() => RefreshOrdering()).DisposeWith(Disposables);

            DateSortDirection = SortOrder.Decreasing;
        }
Beispiel #5
0
        public WalletActionViewModel(string title, WalletViewModel walletViewModel)
            : base(title)
        {
            Disposables = new CompositeDisposable();

            Wallet      = walletViewModel;
            DoItCommand = ReactiveCommand.Create(DisplayActionTab).DisposeWith(Disposables);
        }
        public ReceiveTabViewModel(WalletViewModel walletViewModel)
            : base("Receive", walletViewModel)
        {
            Global                = Locator.Current.GetService <Global>();
            LabelSuggestion       = new SuggestLabelViewModel();
            _addresses            = new ObservableCollection <AddressViewModel>();
            LabelSuggestion.Label = "";

            InitializeAddresses();

            GenerateCommand = ReactiveCommand.Create(() =>
            {
                var label             = new SmartLabel(LabelSuggestion.Label);
                LabelSuggestion.Label = label;
                if (label.IsEmpty)
                {
                    NotificationHelpers.Warning("Observers are required.");
                    return;
                }

                AvaloniaThreadingExtensions.PostLogException(Dispatcher.UIThread, () =>
                {
                    var newKey = KeyManager.GetNextReceiveKey(label, out bool minGapLimitIncreased);
                    if (minGapLimitIncreased)
                    {
                        int minGapLimit     = KeyManager.MinGapLimit.Value;
                        int prevMinGapLimit = minGapLimit - 1;
                        NotificationHelpers.Warning($"{nameof(KeyManager.MinGapLimit)} increased from {prevMinGapLimit} to {minGapLimit}.");
                    }

                    var newAddress = new AddressViewModel(newKey, KeyManager);
                    Addresses.Insert(0, newAddress);
                    SelectedAddress       = newAddress;
                    LabelSuggestion.Label = "";
                });
            });

            this.WhenAnyValue(x => x.SelectedAddress)
            .Subscribe(async address =>
            {
                if (Global.UiConfig?.Autocopy is false || address is null)
                {
                    return;
                }

                await address.TryCopyToClipboardAsync();
            });

            Observable
            .Merge(GenerateCommand.ThrownExceptions)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex =>
            {
                Logger.LogError(ex);
                NotificationHelpers.Error(ex.ToUserFriendlyString());
            });
        }
Beispiel #7
0
        public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel)
        {
            ClearSensitiveData(true);
            SetWarningMessage("");

            this.WhenAnyValue(x => x.Password).Subscribe(x =>
            {
                try
                {
                    if (x.NotNullAndNotEmpty())
                    {
                        char lastChar = x.Last();
                        if (lastChar == '\r' || lastChar == '\n')                         // If the last character is cr or lf then act like it'd be a sign to do the job.
                        {
                            Password = x.TrimEnd('\r', '\n');
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logging.Logger.LogTrace(ex);
                }
            });

            ToggleSensitiveKeysCommand = ReactiveCommand.Create(() =>
            {
                try
                {
                    if (ShowSensitiveKeys)
                    {
                        ClearSensitiveData(true);
                    }
                    else
                    {
                        var secret = PasswordHelper.GetMasterExtKey(KeyManager, Password, out string isCompatibilityPasswordUsed);
                        Password   = "";

                        if (isCompatibilityPasswordUsed != null)
                        {
                            SetWarningMessage(PasswordHelper.CompatibilityPasswordWarnMessage);
                        }

                        string master   = secret.GetWif(Global.Network).ToWif();
                        string account  = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif();
                        string masterZ  = secret.ToZPrv(Global.Network);
                        string accountZ = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network);
                        SetSensitiveData(master, account, masterZ, accountZ);
                    }
                }
                catch (Exception ex)
                {
                    SetWarningMessage(ex.ToTypeMessageString());
                }
            });
        }
Beispiel #8
0
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Transactions = new ObservableCollection <TransactionViewModel>();

            SortCommand       = ReactiveCommand.Create(RefreshOrdering);
            DateSortDirection = SortOrder.Decreasing;

            _isItemSelected = this
                              .WhenAnyValue(x => x.SelectedTransaction)
                              .Select(x => x is { })
Beispiel #9
0
        internal void OpenWallet(string walletName)
        {
            if (_wallets.Any(x => x.Title == walletName))
            {
                return;
            }

            WalletViewModel walletViewModel = new WalletViewModel(walletName);

            _wallets.Add(walletViewModel);
        }
        internal void OpenWallet(string walletName, bool receiveDominant)
        {
            if (_wallets.Any(x => x.Title == walletName))
            {
                return;
            }

            WalletViewModel walletViewModel = new WalletViewModel(walletName, receiveDominant);

            _wallets.Add(walletViewModel);
        }
        public SendTabViewModel(WalletViewModel walletViewModel)
            : base("Send", walletViewModel)
        {
            CoinList = new CoinListViewModel(Global.WalletService.Coins);

            BuildTransactionButtonText = BuildTransactionButtonTextString;

            this.WhenAnyValue(x => x.Amount).Subscribe(_ =>
            {
                if (!_ignoreAmountChanges)
                {
                    IsMax = false;
                }
            });

            BuildTransactionCommand = ReactiveCommand.Create(async() =>
            {
                IsBusy = true;
                try
                {
                    await Task.Delay(5000);

                    //CoinList.SelectedCoins
                    //IsMax = use all selected coins.
                    // backend stuff here.
                }
                catch
                {
                }
                finally
                {
                    IsBusy = false;
                }
            },
                                                             this.WhenAny(x => x.IsMax, x => x.Amount, x => x.Address, x => x.IsBusy,
                                                                          (isMax, amount, address, busy) => (isMax.Value || !string.IsNullOrWhiteSpace(amount.Value) && !string.IsNullOrWhiteSpace(Address) && !IsBusy)));

            MaxCommand = ReactiveCommand.Create(() =>
            {
                SetMax();
            });

            this.WhenAnyValue(x => x.IsBusy).Subscribe(busy =>
            {
                if (busy)
                {
                    BuildTransactionButtonText = BuildingTransactionButtonTextString;
                }
                else
                {
                    BuildTransactionButtonText = BuildTransactionButtonTextString;
                }
            });
        }
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Disposables = new CompositeDisposable();
            Interlocked.Exchange(ref _disableClipboard, 0);
            Transactions = new ObservableCollection <TransactionViewModel>();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            RewriteTableAsync();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

            var coinsChanged      = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged));
            var newBlockProcessed = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.NewBlockProcessed));
            var coinSpent         = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.CoinSpentOrSpenderConfirmed));

            coinsChanged
            .Merge(newBlockProcessed)
            .Merge(coinSpent)
            .Throttle(TimeSpan.FromSeconds(5))
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                RewriteTableAsync();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            }).DisposeWith(Disposables);

            this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction =>
            {
                if (Interlocked.Read(ref _disableClipboard) == 0)
                {
                    if (!(transaction is null))
                    {
                        await Application.Current.Clipboard.SetTextAsync(transaction.TransactionId);
                        ClipboardNotificationVisible = true;
                        ClipboardNotificationOpacity = 1;

                        Dispatcher.UIThread.Post(async() =>
                        {
                            await Task.Delay(1000);
                            ClipboardNotificationOpacity = 0;
                        });
                    }
                }
                else
                {
                    Interlocked.Exchange(ref _disableClipboard, 0);
                }
            }).DisposeWith(Disposables);

            SortCommand = ReactiveCommand.Create(() => RefreshOrdering()).DisposeWith(Disposables);

            DateSortDirection = SortOrder.Decreasing;
        }
Beispiel #13
0
        public ReceiveTabViewModel(WalletViewModel walletViewModel)
            : base("Receive", walletViewModel)
        {
            _labelSuggestion       = new SuggestLabelViewModel(Global);
            _addresses             = new ObservableCollection <AddressViewModel>();
            _labelSuggestion.Label = "";

            InitializeAddresses();

            GenerateCommand = ReactiveCommand.Create(() =>
            {
                var label = new SmartLabel(_labelSuggestion.Label);
                _labelSuggestion.Label = label;
                if (label.IsEmpty)
                {
                    NotificationHelpers.Warning("Label is required.");

                    return;
                }

                Dispatcher.UIThread.PostLogException(() =>
                {
                    HdPubKey newKey = Global.WalletService.GetReceiveKey(_labelSuggestion.Label, Addresses.Select(x => x.Model).Take(7));                                     // Never touch the first 7 keys.

                    AddressViewModel found = Addresses.FirstOrDefault(x => x.Model == newKey);
                    if (found != default)
                    {
                        Addresses.Remove(found);
                    }

                    var newAddress = new AddressViewModel(newKey, Global);

                    Addresses.Insert(0, newAddress);

                    SelectedAddress = newAddress;

                    _labelSuggestion.Label = "";
                });
            });

            this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address =>
            {
                if (Global.UiConfig?.Autocopy is false || address is null)
                {
                    return;
                }

                await address.TryCopyToClipboardAsync();
            });

            var isCoinListItemSelected = this.WhenAnyValue(x => x.SelectedAddress).Select(coin => coin is { });
Beispiel #14
0
        public ReceiveTabViewModel(WalletViewModel walletViewModel)
            : base("Receive", walletViewModel)
        {
            _addresses = new ObservableCollection <AddressViewModel>();

            Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged))
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(o =>
            {
                InitializeAddresses();
            });

            InitializeAddresses();

            GenerateCommand = ReactiveCommand.Create(() =>
            {
                HdPubKey newKey = Global.WalletService.GetReceiveKey(Label);

                AddressViewModel found = Addresses.FirstOrDefault(x => x.Model == newKey);
                if (found != default)
                {
                    Addresses.Remove(found);
                }

                var newAddress = new AddressViewModel(newKey);

                Addresses.Insert(0, newAddress);

                SelectedAddress = newAddress;

                Label = string.Empty;
            }, this.WhenAnyValue(x => x.Label, label => !string.IsNullOrWhiteSpace(label)));

            this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address =>
            {
                if (address != null)
                {
                    await Application.Current.Clipboard.SetTextAsync(address.Address);
                    ClipboardNotificationVisible = true;
                    ClipboardNotificationOpacity = 1;

                    Dispatcher.UIThread.Post(async() =>
                    {
                        await Task.Delay(1000);
                        ClipboardNotificationOpacity = 0;
                    });
                }
            });
        }
Beispiel #15
0
        public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel)
        {
            Disposables = new CompositeDisposable();
            ClearSensitiveData(true);
            _warningMessage = "";
            Closing         = new CancellationTokenSource().DisposeWith(Disposables);

            this.WhenAnyValue(x => x.Password).Subscribe(x =>
            {
                try
                {
                    if (x.NotNullAndNotEmpty())
                    {
                        char lastChar = x.Last();
                        if (lastChar == '\r' || lastChar == '\n')                         // If the last character is cr or lf then act like it'd be a sign to do the job.
                        {
                            Password = x.TrimEnd('\r', '\n');
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logging.Logger.LogTrace(ex);
                }
            }).DisposeWith(Disposables);

            ShowSensitiveKeysCommand = ReactiveCommand.Create(() =>
            {
                try
                {
                    Password   = Guard.Correct(Password);
                    var secret = KeyManager.GetMasterExtKey(Password);
                    Password   = "";

                    string master     = secret.GetWif(Global.Network).ToWif();
                    string masterPub  = secret.Neuter().GetWif(Global.Network).ToWif();
                    string account    = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif();
                    string masterY    = secret.ToZPrv(Global.Network);
                    string masterPubY = secret.Neuter().ToZpub(Global.Network);
                    string accountY   = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network);
                    SetSensitiveData(master, masterPub, account, masterY, masterPubY, accountY);
                }
                catch (Exception ex)
                {
                    SetWarningMessage(ex.ToTypeMessageString());
                }
            }).DisposeWith(Disposables);
        }
        public ReceiveTabViewModel(WalletViewModel walletViewModel)
            : base("Receive", walletViewModel)
        {
            _labelSuggestion       = new SuggestLabelViewModel(Global);
            _addresses             = new ObservableCollection <AddressViewModel>();
            _labelSuggestion.Label = "";

            InitializeAddresses();

            GenerateCommand = ReactiveCommand.Create(() =>
            {
                var label = new SmartLabel(_labelSuggestion.Label);
                _labelSuggestion.Label = label;
                if (label.IsEmpty)
                {
                    NotificationHelpers.Warning("Label is required.");
                    return;
                }

                AvaloniaThreadingExtensions.PostLogException(Dispatcher.UIThread, () =>
                {
                    var newKey = KeyManager.GetNextReceiveKey(label, out bool minGapLimitIncreased);
                    if (minGapLimitIncreased)
                    {
                        int minGapLimit     = KeyManager.MinGapLimit.Value;
                        int prevMinGapLimit = minGapLimit - 1;
                        NotificationHelpers.Warning($"{nameof(KeyManager.MinGapLimit)} increased from {prevMinGapLimit} to {minGapLimit}.");
                    }

                    var newAddress = new AddressViewModel(newKey, Global);
                    Addresses.Insert(0, newAddress);
                    SelectedAddress        = newAddress;
                    _labelSuggestion.Label = "";
                });
            });

            this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address =>
            {
                if (Global.UiConfig?.Autocopy is false || address is null)
                {
                    return;
                }

                await address.TryCopyToClipboardAsync();
            });

            var isCoinListItemSelected = this.WhenAnyValue(x => x.SelectedAddress).Select(coin => coin is { });
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Transactions = new ObservableCollection <TransactionViewModel>();

            SortCommand       = ReactiveCommand.Create(RefreshOrdering);
            DateSortDirection = SortOrder.Decreasing;

            SortCommand.ThrownExceptions
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex =>
            {
                NotificationHelpers.Error(ex.ToTypeMessageString());
                Logger.LogWarning(ex);
            });

            _ = TryRewriteTableAsync();
        }
Beispiel #18
0
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Interlocked.Exchange(ref _disableClipboard, 0);
            Transactions = new ObservableCollection <TransactionViewModel>();
            RewriteTable();

            var coinsChanged      = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.CollectionChanged));
            var newBlockProcessed = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.NewBlockProcessed));
            var coinSpent         = Observable.FromEventPattern(Global.WalletService, nameof(Global.WalletService.CoinSpentOrSpenderConfirmed));

            coinsChanged
            .Merge(newBlockProcessed)
            .Merge(coinSpent)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(o =>
            {
                RewriteTable();
            });

            this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction =>
            {
                if (Interlocked.Read(ref _disableClipboard) == 0)
                {
                    if (!(transaction is null))
                    {
                        await Application.Current.Clipboard.SetTextAsync(transaction.TransactionId);
                        ClipboardNotificationVisible = true;
                        ClipboardNotificationOpacity = 1;

                        Dispatcher.UIThread.Post(async() =>
                        {
                            await Task.Delay(1000);
                            ClipboardNotificationOpacity = 0;
                        });
                    }
                }
                else
                {
                    Interlocked.Exchange(ref _disableClipboard, 0);
                }
            });
            DateSortDirection = SortOrder.Decreasing;
        }
Beispiel #19
0
        public CoinJoinTabViewModel(WalletViewModel walletViewModel)
            : base("CoinJoin", walletViewModel)
        {
            Password = "";

            var onCoinsSetModified = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged))
                                     .ObserveOn(RxApp.MainThreadScheduler);

            var globalCoins = Global.WalletService.Coins.CreateDerivedCollection(c => new CoinViewModel(c), null, (first, second) => second.Amount.CompareTo(first.Amount), signalReset: onCoinsSetModified, RxApp.MainThreadScheduler);

            globalCoins.ChangeTrackingEnabled = true;

            var available = globalCoins.CreateDerivedCollection(c => c, c => c.Confirmed && !c.SpentOrCoinJoinInProcess);

            var queued = globalCoins.CreateDerivedCollection(c => c, c => c.CoinJoinInProgress);

            AvailableCoinsList = new CoinListViewModel(available);

            QueuedCoinsList = new CoinListViewModel(queued);

            EnqueueCommand = ReactiveCommand.Create(async() =>
            {
                var selectedCoins = AvailableCoinsList.Coins.Where(c => c.IsSelected).ToList();

                foreach (var coin in selectedCoins)
                {
                    coin.IsSelected = false;
                }

                await Global.ChaumianClient.QueueCoinsToMixAsync(Password, selectedCoins.Select(c => c.Model).ToArray());
            });

            DequeueCommand = ReactiveCommand.Create(async() =>
            {
                var selectedCoins = QueuedCoinsList.Coins.Where(c => c.IsSelected).ToList();

                foreach (var coin in selectedCoins)
                {
                    coin.IsSelected = false;
                }

                await Global.ChaumianClient.DequeueCoinsFromMixAsync(selectedCoins.Select(c => c.Model).ToArray());
            });
        }
Beispiel #20
0
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Global = Locator.Current.GetService <Global>();

            Transactions = new ObservableCollection <TransactionViewModel>();

            SortCommand       = ReactiveCommand.Create(RefreshOrdering);
            DateSortDirection = SortOrder.Decreasing;

            SortCommand.ThrownExceptions
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex =>
            {
                Logger.LogError(ex);
                NotificationHelpers.Error(ex.ToUserFriendlyString());
            });

            _ = TryRewriteTableAsync();
        }
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Transactions = new ObservableCollection <TransactionViewModel>();

            RewriteTableAsync().GetAwaiter();

            this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction =>
            {
                if (Global.UiConfig.Autocopy is false || transaction is null)
                {
                    return;
                }
                await transaction.TryCopyTxIdToClipboardAsync();
            });

            SortCommand = ReactiveCommand.Create(() => RefreshOrdering());

            DateSortDirection = SortOrder.Decreasing;
        }
        public CoinJoinTabViewModel(WalletViewModel walletViewModel)
            : base("CoinJoin", walletViewModel)
        {
            Password = "";

            var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault();

            UpdateRequiredBtcLabel(registrableRound);

            if (registrableRound != default)
            {
                CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString();
            }
            else
            {
                CoordinatorFeePercent = "0.003";
            }

            if (!(registrableRound?.State?.Denomination is null) && registrableRound.State.Denomination != Money.Zero)
            {
                CoinsList = new CoinListViewModel(RequiredBTC, PreSelectMaxAnonSetExcludingCondition);
            }
Beispiel #23
0
        public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel)
        {
            Global = Locator.Current.GetService <Global>();

            ClearSensitiveData(true);

            ToggleSensitiveKeysCommand = ReactiveCommand.Create(() =>
            {
                if (ShowSensitiveKeys)
                {
                    ClearSensitiveData(true);
                }
                else
                {
                    var secret = PasswordHelper.GetMasterExtKey(KeyManager, Password, out string isCompatibilityPasswordUsed);
                    Password   = "";

                    if (isCompatibilityPasswordUsed != null)
                    {
                        NotificationHelpers.Warning(PasswordHelper.CompatibilityPasswordWarnMessage);
                    }

                    string master   = secret.GetWif(Global.Network).ToWif();
                    string account  = secret.Derive(KeyManager.AccountKeyPath).GetWif(Global.Network).ToWif();
                    string masterZ  = secret.ToZPrv(Global.Network);
                    string accountZ = secret.Derive(KeyManager.AccountKeyPath).ToZPrv(Global.Network);
                    SetSensitiveData(master, account, masterZ, accountZ);
                }
            });

            ToggleSensitiveKeysCommand.ThrownExceptions
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex =>
            {
                Logging.Logger.LogError(ex);
                NotificationHelpers.Error(ex.ToUserFriendlyString());
            });
        }
Beispiel #24
0
        public CoinJoinTabViewModel(WalletViewModel walletViewModel)
            : base("CoinJoin", walletViewModel)
        {
            Password      = "";
            TargetPrivacy = ShieldLevelHelper.GetTargetPrivacy(Global.Config.MixUntilAnonymitySet);

            var registrableRound = Global.ChaumianClient.State.GetRegistrableRoundOrDefault();

            UpdateRequiredBtcLabel(registrableRound);

            if (registrableRound != default)
            {
                CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString();
            }
            else
            {
                CoordinatorFeePercent = "0.003";
            }

            if (!(registrableRound?.State?.Denomination is null) && registrableRound.State.Denomination != Money.Zero)
            {
                CoinsList = new CoinListViewModel();
            }
        public WalletInfoViewModel(WalletViewModel walletViewModel) : base(walletViewModel.Name, walletViewModel)
        {
            Disposables     = new CompositeDisposable();
            _password       = "";
            _secret         = "";
            _warningMessage = "";
            Closing         = new CancellationTokenSource().DisposeWith(Disposables);

            this.WhenAnyValue(x => x.Password).Subscribe(x =>
            {
                if (x.NotNullAndNotEmpty())
                {
                    char lastChar = x.Last();
                    if (lastChar == '\r' || lastChar == '\n')                     // If the last character is cr or lf then act like it'd be a sign to do the job.
                    {
                        Password = x.TrimEnd('\r', '\n');
                    }
                }
            }).DisposeWith(Disposables);

            ShowMasterKeyCommand = ReactiveCommand.Create(() =>
            {
                try
                {
                    Password   = Guard.Correct(Password);
                    var secret = KeyManager.GetExtKey(Password);
                    Password   = "";

                    SetSecret(secret.GetWif(Global.Network).ToWif());
                }
                catch (Exception ex)
                {
                    SetWarningMessage(ex.ToTypeMessageString());
                }
            }).DisposeWith(Disposables);
        }
        public HistoryTabViewModel(WalletViewModel walletViewModel)
            : base("History", walletViewModel)
        {
            Transactions = new ObservableCollection <TransactionViewModel>();

            this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction =>
            {
                if (Global.UiConfig?.Autocopy is false || transaction is null)
                {
                    return;
                }

                await transaction.TryCopyTxIdToClipboardAsync();
            });

            SortCommand = ReactiveCommand.Create(RefreshOrdering);
            SortCommand.ThrownExceptions
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex => Logger.LogError(ex));

            DateSortDirection = SortOrder.Decreasing;

            _ = TryRewriteTableAsync();
        }
 public WalletActionViewModel(string title, WalletViewModel walletViewModel)
     : base(title)
 {
     Wallet      = walletViewModel;
     DoItCommand = ReactiveCommand.Create(DisplayActionTab);
 }
        public CoinJoinTabViewModel(WalletViewModel walletViewModel)
            : base("CoinJoin", walletViewModel)
        {
            Password = "";
            TimeLeftTillRoundTimeout = TimeSpan.Zero;

            CoinsList = new CoinListViewModel(Global, CoinListContainerType.CoinJoinTabViewModel);

            Observable.FromEventPattern(CoinsList, nameof(CoinsList.DequeueCoinsPressed)).Subscribe(_ => OnCoinsListDequeueCoinsPressedAsync());

            AmountQueued = Money.Zero;             // Global.ChaumianClient.State.SumAllQueuedCoinAmounts();

            EnqueueCommand = ReactiveCommand.CreateFromTask(async() => await DoEnqueueAsync(CoinsList.Coins.Where(c => c.IsSelected)));

            DequeueCommand = ReactiveCommand.CreateFromTask(async() => await DoDequeueAsync(CoinsList.Coins.Where(c => c.IsSelected)));

            PrivacySomeCommand = ReactiveCommand.Create(() => TargetPrivacy = TargetPrivacy.Some);

            PrivacyFineCommand = ReactiveCommand.Create(() => TargetPrivacy = TargetPrivacy.Fine);

            PrivacyStrongCommand = ReactiveCommand.Create(() => TargetPrivacy = TargetPrivacy.Strong);

            TargetButtonCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                switch (TargetPrivacy)
                {
                case TargetPrivacy.None:
                    TargetPrivacy = TargetPrivacy.Some;
                    break;

                case TargetPrivacy.Some:
                    TargetPrivacy = TargetPrivacy.Fine;
                    break;

                case TargetPrivacy.Fine:
                    TargetPrivacy = TargetPrivacy.Strong;
                    break;

                case TargetPrivacy.Strong:
                    TargetPrivacy = TargetPrivacy.Some;
                    break;
                }
                Global.Config.MixUntilAnonymitySet = CoinJoinUntilAnonymitySet;
                await Global.Config.ToFileAsync();
            });

            this.WhenAnyValue(x => x.Password).Subscribe(async x =>
            {
                try
                {
                    if (x.NotNullAndNotEmpty())
                    {
                        char lastChar = x.Last();
                        if (lastChar == '\r' || lastChar == '\n')                         // If the last character is cr or lf then act like it'd be a sign to do the job.
                        {
                            Password = x.TrimEnd('\r', '\n');
                            await DoEnqueueAsync(CoinsList.Coins.Where(c => c.IsSelected));
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogTrace(ex);
                }
            });

            this.WhenAnyValue(x => x.IsEnqueueBusy)
            .Select(x => x ? EnqueuingButtonTextString : EnqueueButtonTextString)
            .Subscribe(text => EnqueueButtonText = text);

            this.WhenAnyValue(x => x.IsDequeueBusy)
            .Select(x => x ? DequeuingButtonTextString : DequeueButtonTextString)
            .Subscribe(text => DequeueButtonText = text);

            this.WhenAnyValue(x => x.TargetPrivacy).Subscribe(target =>
            {
                CoinJoinUntilAnonymitySet = Global.Config.GetTargetLevel(target);
            });

            this.WhenAnyValue(x => x.RoundTimesout)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(x =>
            {
                TimeSpan left            = x - DateTimeOffset.UtcNow;
                TimeLeftTillRoundTimeout = left > TimeSpan.Zero ? left : TimeSpan.Zero;                         // Make sure cannot be less than zero.
            });
        }
        public SendTabViewModel(WalletViewModel walletViewModel)
            : base("Send", walletViewModel)
        {
            Label = "";

            var onCoinsSetModified = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged))
                                     .ObserveOn(RxApp.MainThreadScheduler);

            var globalCoins = Global.WalletService.Coins.CreateDerivedCollection(c => new CoinViewModel(c), null, (first, second) => second.Amount.CompareTo(first.Amount), signalReset: onCoinsSetModified, RxApp.MainThreadScheduler);

            globalCoins.ChangeTrackingEnabled = true;

            var filteredCoins = globalCoins.CreateDerivedCollection(c => c, c => !c.SpentOrCoinJoinInProgress);

            CoinList = new CoinListViewModel(filteredCoins);

            BuildTransactionButtonText = BuildTransactionButtonTextString;

            ResetMax();

            this.WhenAnyValue(x => x.Amount).Subscribe(amount =>
            {
                if (!IgnoreAmountChanges)
                {
                    IsMax = false;

                    // Correct amount
                    Regex digitsOnly      = new Regex(@"[^\d,.]");
                    string betterAmount   = digitsOnly.Replace(amount, "");                   // Make it digits , and . only.
                    betterAmount          = betterAmount.Replace(',', '.');
                    int countBetterAmount = betterAmount.Count(x => x == '.');
                    if (countBetterAmount > 1)                     // Don't enable typing two dots.
                    {
                        var index = betterAmount.IndexOf('.', betterAmount.IndexOf('.') + 1);
                        if (index > 0)
                        {
                            betterAmount = betterAmount.Substring(0, index);
                        }
                    }
                    var dotIndex = betterAmount.IndexOf('.');
                    if (betterAmount.Length - dotIndex > 8)                     // Enable max 8 decimals.
                    {
                        betterAmount = betterAmount.Substring(0, dotIndex + 1 + 8);
                    }

                    if (betterAmount != amount)
                    {
                        Dispatcher.UIThread.Post(() =>
                        {
                            Amount = betterAmount;
                        });
                    }
                }
            });

            BuildTransactionCommand = ReactiveCommand.Create(async() =>
            {
                IsBusy = true;
                try
                {
                    Password = Guard.Correct(Password);
                    if (!IsMax && string.IsNullOrWhiteSpace(Label))
                    {
                        SetWarningMessage("Label is required.");
                        return;
                    }

                    var selectedCoins = CoinList.Coins.Where(cvm => cvm.IsSelected).Select(cvm => new TxoRef(cvm.Model.TransactionId, cvm.Model.Index)).ToList();

                    if (!selectedCoins.Any())
                    {
                        SetWarningMessage("No coins are selected to spend.");
                        return;
                    }

                    BitcoinAddress address;
                    try
                    {
                        address = BitcoinAddress.Create(Address.Trim(), Global.Network);
                    }
                    catch (FormatException)
                    {
                        SetWarningMessage("Invalid address.");
                        return;
                    }

                    var script = address.ScriptPubKey;
                    var amount = Money.Zero;
                    if (!IsMax)
                    {
                        amount = Money.Parse(Amount);
                        if (amount == Money.Zero)
                        {
                            SetWarningMessage($"Invalid amount.");
                            return;
                        }
                    }
                    var label     = Label.Trim(',', ' ').Trim();
                    var operation = new WalletService.Operation(script, amount, label);

                    var result = await Task.Run(async() => await Global.WalletService.BuildTransactionAsync(Password, new[] { operation }, Fee, allowUnconfirmed: true, allowedInputs: selectedCoins));

                    await Task.Run(async() => await Global.WalletService.SendTransactionAsync(result.Transaction));

                    ResetMax();
                    Address  = "";
                    Label    = "";
                    Password = "";

                    SetSuccessMessage("Transaction is successfully sent!");
                }
                catch (InsufficientBalanceException ex)
                {
                    Money needed = ex.Minimum - ex.Actual;
                    SetWarningMessage($"Not enough coins selected. You need an estimated {needed.ToString(false, true)} BTC more to make this transaction.");
                }
                catch (Exception ex)
                {
                    SetWarningMessage(ex.ToTypeMessageString());
                }
                finally
                {
                    IsBusy = false;
                }
            },
                                                             this.WhenAny(x => x.IsMax, x => x.Amount, x => x.Address, x => x.IsBusy,
                                                                          (isMax, amount, address, busy) => ((isMax.Value || !string.IsNullOrWhiteSpace(amount.Value)) && !string.IsNullOrWhiteSpace(Address) && !IsBusy)));

            MaxCommand = ReactiveCommand.Create(() =>
            {
                SetMax();
            });

            this.WhenAnyValue(x => x.IsBusy).Subscribe(busy =>
            {
                if (busy)
                {
                    BuildTransactionButtonText = BuildingTransactionButtonTextString;
                }
                else
                {
                    BuildTransactionButtonText = BuildTransactionButtonTextString;
                }
            });

            this.WhenAnyValue(x => x.Password).Subscribe(x =>
            {
                if (x.NotNullAndNotEmpty())
                {
                    char lastChar = x.Last();
                    if (lastChar == '\r' || lastChar == '\n')                     // If the last character is cr or lf then act like it'd be a sign to do the job.
                    {
                        Password = x.TrimEnd('\r', '\n');
                    }
                }
            });

            this.WhenAnyValue(x => x.Label).Subscribe(x => UpdateSuggestions(x));
            this.WhenAnyValue(x => x.CaretIndex).Subscribe(_ =>
            {
                if (Label == null)
                {
                    return;
                }
                if (CaretIndex != Label.Length)
                {
                    CaretIndex = Label.Length;
                }
            });
            _suggestions = new ObservableCollection <SuggestionViewModel>();
        }
        public ReceiveTabViewModel(WalletViewModel walletViewModel)
            : base("Receive", walletViewModel)
        {
            _addresses = new ObservableCollection <AddressViewModel>();
            Label      = "";

            InitializeAddresses();

            GenerateCommand = ReactiveCommand.Create(() =>
            {
                var label = new SmartLabel(Label);
                Label     = label.ToString();
                if (label.IsEmpty)
                {
                    LabelRequiredNotificationVisible = true;
                    LabelRequiredNotificationOpacity = 1;

                    Dispatcher.UIThread.PostLogException(async() =>
                    {
                        await Task.Delay(TimeSpan.FromSeconds(4));
                        LabelRequiredNotificationOpacity = 0;
                    });

                    return;
                }

                Dispatcher.UIThread.PostLogException(() =>
                {
                    HdPubKey newKey = Global.WalletService.GetReceiveKey(new SmartLabel(Label), Addresses.Select(x => x.Model).Take(7));                                     // Never touch the first 7 keys.

                    AddressViewModel found = Addresses.FirstOrDefault(x => x.Model == newKey);
                    if (found != default)
                    {
                        Addresses.Remove(found);
                    }

                    var newAddress = new AddressViewModel(newKey, Global);

                    Addresses.Insert(0, newAddress);

                    SelectedAddress = newAddress;

                    Label = "";
                });
            });

            this.WhenAnyValue(x => x.Label).Subscribe(UpdateSuggestions);

            this.WhenAnyValue(x => x.SelectedAddress).Subscribe(async address =>
            {
                if (Global.UiConfig?.Autocopy is false || address is null)
                {
                    return;
                }

                await address.TryCopyToClipboardAsync();
            });

            var isCoinListItemSelected = this.WhenAnyValue(x => x.SelectedAddress).Select(coin => coin != null);

            CopyAddress = ReactiveCommand.CreateFromTask(async() =>
            {
                if (SelectedAddress is null)
                {
                    return;
                }

                await SelectedAddress.TryCopyToClipboardAsync();
            },
                                                         isCoinListItemSelected);

            CopyLabel = ReactiveCommand.CreateFromTask(async() =>
            {
                try
                {
                    await Application.Current.Clipboard.SetTextAsync(SelectedAddress.Label ?? string.Empty);
                }
                catch (Exception)
                { }
            },
                                                       isCoinListItemSelected);

            ToggleQrCode = ReactiveCommand.Create(() =>
            {
                try
                {
                    SelectedAddress.IsExpanded = !SelectedAddress.IsExpanded;
                }
                catch (Exception)
                { }
            },
                                                  isCoinListItemSelected);

#pragma warning disable IDE0053 // Use expression body for lambda expressions
            ChangeLabelCommand = ReactiveCommand.Create(() => { SelectedAddress.InEditMode = true; });
#pragma warning restore IDE0053 // Use expression body for lambda expressions

            DisplayAddressOnHwCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                var client    = new HwiClient(Global.Network);
                using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
                try
                {
                    await client.DisplayAddressAsync(KeyManager.MasterFingerprint.Value, SelectedAddress.Model.FullKeyPath, cts.Token);
                }
                catch (HwiException)
                {
                    await PinPadViewModel.UnlockAsync(Global);
                    await client.DisplayAddressAsync(KeyManager.MasterFingerprint.Value, SelectedAddress.Model.FullKeyPath, cts.Token);
                }
            });

            _suggestions = new ObservableCollection <SuggestionViewModel>();
        }