public OverviewViewModel(ChaincaseWalletManager walletManager, Config config, UiConfig uiConfig, BitcoinStore bitcoinStore, IMainThreadInvoker mainThreadInvoker) { _walletManager = walletManager; _config = config; _uiConfig = uiConfig; _bitcoinStore = bitcoinStore; _mainThreadInvoker = mainThreadInvoker; Transactions = new ObservableCollection <TransactionViewModel>(); if (_walletManager.HasDefaultWalletFile() && _walletManager.CurrentWallet == null) { _walletManager.SetDefaultWallet(); Task.Run(async() => await LoadWalletAsync()); TryWriteTableFromCache(); } _hasSeed = this.WhenAnyValue(x => x._uiConfig.HasSeed) .ToProperty(this, nameof(HasSeed)); _isBackedUp = this.WhenAnyValue(x => x._uiConfig.IsBackedUp) .ToProperty(this, nameof(IsBackedUp)); var canBackUp = this.WhenAnyValue(x => x.HasSeed, x => x.IsBackedUp, (hasSeed, isBackedUp) => hasSeed && !isBackedUp); canBackUp.ToProperty(this, x => x.CanBackUp, out _canBackUp); Balance = _uiConfig.Balance; Initializing += OnInit; Initializing(this, EventArgs.Empty); }
public Global( ITorManager torManager, IDataDirProvider dataDirProvider, Config config, UiConfig uiConfig, ChaincaseWalletManager walletManager, BitcoinStore bitcoinStore, ChaincaseSynchronizer synchronizer, FeeProviders feeProviders ) { _torManager = torManager; _dataDirProvider = dataDirProvider; _config = config; _uiConfig = uiConfig; _walletManager = walletManager; _bitcoinStore = bitcoinStore; _synchronizer = synchronizer; _feeProviders = feeProviders; using (BenchmarkLogger.Measure()) { StoppingCts = new CancellationTokenSource(); Logger.InitializeDefaults(Path.Combine(DataDir, "Logs.txt")); _uiConfig.LoadOrCreateDefaultFile(); } }
public NewPasswordViewModel(ChaincaseWalletManager walletManager, Config config, UiConfig uiConfig, SensitiveStorage storage) { _walletManager = walletManager; _config = config; _uiConfig = uiConfig; _storage = storage; }
public WalletInfoViewModel(ChaincaseWalletManager walletManager, Config config, UiConfig uiConfig, IShare share, IDataDirProvider dataDirProvider) { _walletManager = walletManager; _config = config; _uiConfig = uiConfig; _share = share; _dataDirProvider = dataDirProvider; }
public CoinViewModel(ChaincaseWalletManager walletManager, Config config, BitcoinStore bitcoinStore, SmartCoin model) { _walletManager = walletManager; _config = config; _bitcoinStore = bitcoinStore; Model = model; Disposables = new CompositeDisposable(); _coinJoinInProgress = Model.WhenAnyValue(x => x.CoinJoinInProgress) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.CoinJoinInProgress) .DisposeWith(Disposables); _unspent = Model.WhenAnyValue(x => x.Unspent).ToProperty(this, x => x.Unspent, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _confirmed = Model.WhenAnyValue(x => x.Confirmed).ToProperty(this, x => x.Confirmed, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); _unavailable = Model.WhenAnyValue(x => x.Unavailable).ToProperty(this, x => x.Unavailable, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); this.WhenAnyValue(x => x.Status) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => this.RaisePropertyChanged(nameof(ToolTip))); _cluster = Model .WhenAnyValue(x => x.Clusters, x => x.Clusters.Labels) .Select(x => x.Item2.ToString()) .ToProperty(this, x => x.Clusters, scheduler: RxApp.MainThreadScheduler) .DisposeWith(Disposables); Observable .Merge(Model.WhenAnyValue(x => x.IsBanned, x => x.SpentAccordingToBackend, x => x.CoinJoinInProgress).Select(_ => Unit.Default)) .Merge(Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.StateUpdated)).Select(_ => Unit.Default)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => RefreshSmartCoinStatus()) .DisposeWith(Disposables); _bitcoinStore.SmartHeaderChain .WhenAnyValue(x => x.TipHeight).Select(_ => Unit.Default) .Merge(Model.WhenAnyValue(x => x.Height).Select(_ => Unit.Default)) .Throttle(TimeSpan.FromSeconds(0.1)) // DO NOT TAKE THIS THROTTLE OUT, OTHERWISE SYNCING WITH COINS IN THE WALLET WILL STACKOVERFLOW! .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => this.RaisePropertyChanged(nameof(Confirmations))) .DisposeWith(Disposables); }
public SelectCoinsViewModel(ChaincaseWalletManager walletManager, Config config, BitcoinStore bitcoinStore, bool isPrivate = false) { _walletManager = walletManager; _config = config; _bitcoinStore = bitcoinStore; RootList = new SourceList <CoinViewModel>(); RootList .Connect() .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _coinViewModels) .Subscribe(); Disposables = Disposables is null ? new CompositeDisposable() : throw new NotSupportedException($"Cannot open {GetType().Name} before closing it."); UpdateRootList(); Task.Run(async() => { while (_walletManager.CurrentWallet?.TransactionProcessor == null) { await Task.Delay(50).ConfigureAwait(false); } Observable .Merge(Observable.FromEventPattern <ProcessedResult>(_walletManager.CurrentWallet.TransactionProcessor, nameof(_walletManager.CurrentWallet.TransactionProcessor.WalletRelevantTransactionProcessed)).Select(_ => Unit.Default)) .Throttle(TimeSpan.FromSeconds(1)) // Throttle TransactionProcessor events adds/removes. .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { UpdateRootList(); }) .DisposeWith(Disposables); }); }
public BackUpViewModel(Config config, UiConfig uiConfig, IHsmStorage hsm, SensitiveStorage storage, ChaincaseWalletManager walletManager) { _config = config; _uiConfig = uiConfig; _hsm = hsm; _storage = storage; _walletManager = walletManager; }
public ReceiveViewModel(ChaincaseWalletManager walletManager, Config config) { _walletManager = walletManager; _config = config; }
public SendViewModel(Global global, ChaincaseWalletManager walletManager, Config config, UiConfig uiConfig, SelectCoinsViewModel selectCoinsViewModel, FeeProviders feeProviders) { _global = global; _walletManager = walletManager; _config = config; _uiConfig = uiConfig; _feeProviders = feeProviders; SelectCoinsViewModel = selectCoinsViewModel; AmountText = "0.0"; AllSelectedAmount = Money.Zero; EstimatedBtcFee = Money.Zero; if (_global.IsInitialized) { OnAppInitialized(this, new AppInitializedEventArgs(_global)); } else { _global.Initialized += OnAppInitialized; } _outputAmount = this.WhenAnyValue(x => x.AmountText, (amountText) => { Money.TryParse(amountText.TrimStart('~', ' '), out Money outputAmount); return(outputAmount ?? OutputAmount); }).ToProperty(this, x => x.OutputAmount); this.WhenAnyValue(x => x.IsMax) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(isMax => { if (isMax) { SetAmountIfMax(); } }); Observable.FromEventPattern(SelectCoinsViewModel, nameof(SelectCoinsViewModel.SelectionChanged)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => ApplyFees()); _minMaxFeeTargetsEqual = this.WhenAnyValue(x => x.MinimumFeeTarget, x => x.MaximumFeeTarget, (x, y) => x == y) .ToProperty(this, x => x.MinMaxFeeTargetsEqual, scheduler: RxApp.MainThreadScheduler); SetFeeTargetLimits(); FeeTarget = _uiConfig.FeeTarget; FeeRate = new FeeRate((decimal)50); //50 sat/vByte placeholder til loads this.WhenAnyValue(x => x.FeeTarget) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { ApplyFees(); }); _destinationUrl = this.WhenAnyValue(x => x.DestinationString, ParseDestinationString) .ToProperty(this, nameof(DestinationUrl)); var isTransactionOkToSign = this.WhenAnyValue( x => x.Label, x => x.DestinationUrl, x => x.OutputAmount, x => x.SelectCoinsViewModel.SelectedAmount, x => x.EstimatedBtcFee, (label, address, outputAmount, selectedAmount, feeAmount) => { return(label.NotNullAndNotEmpty() && DestinationUrl.Address is not null && outputAmount > Money.Zero && outputAmount + feeAmount <= selectedAmount); }); _isTransactionOkToSign = isTransactionOkToSign .ToProperty(this, x => x.IsTransactionOkToSign); SendTransactionCommand = ReactiveCommand.CreateFromTask <string, bool>(SendTransaction, isTransactionOkToSign); }
public StatusViewModel(Global global, ChaincaseWalletManager walletManager, Config config, UiConfig uiConfig, BitcoinStore bitcoinStore, ChaincaseSynchronizer synchronizer) { _global = global; _walletManager = walletManager; _bitcoinStore = bitcoinStore; _Config = config; _uiConfig = uiConfig; _synchronizer = synchronizer; Backend = BackendStatus.NotConnected; Tor = TorStatus.NotRunning; Peers = 0; BtcPrice = "$0"; ActiveStatuses = new StatusSet(); UseTor = _Config.UseTor; // Do not make it dynamic, because if you change this config settings only next time will it activate. if (_global.IsInitialized) { OnAppInitialized(this, new AppInitializedEventArgs(_global)); } else { _global.Initialized += OnAppInitialized; } _status = ActiveStatuses.WhenAnyValue(x => x.CurrentStatus) .Select(x => x.ToString()) .ObserveOn(RxApp.MainThreadScheduler) .ToProperty(this, x => x.Status) .DisposeWith(Disposables); // Set number of peers currently connected Peers = Tor == TorStatus.NotRunning ? 0 : Nodes.Count; // Subscribe to downloading block activity Observable.FromEventPattern <bool>(typeof(P2pBlockProvider), nameof(P2pBlockProvider.DownloadingBlockChanged)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => DownloadingBlock = x.EventArgs) .DisposeWith(Disposables); // Calculate progress precentage bool progressReset = true; _progressPercent = this.WhenAnyValue(x => x.ActiveStatuses.CurrentStatus, x => x.Peers) .Select(tup => { var(status, peers) = tup; if (peers == 0 && progressReset) { progressReset = false; return(0.01); } switch (status.Type) { case StatusType.Ready: progressReset = true; return(1); case StatusType.Synchronizing: return(status.Percentage / 200.0 + 0.3); case StatusType.Connecting: default: return(0.3); } }) .ToProperty(this, x => x.ProgressPercent); IDisposable walletCheckingInterval = null; Observable.FromEventPattern <bool>(typeof(Wallet), nameof(Wallet.InitializingChanged)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { if (x.EventArgs) { TryAddStatus(StatusType.WalletLoading); if (walletCheckingInterval is null) { walletCheckingInterval = Observable.Interval(TimeSpan.FromSeconds(1)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { var wallet = _walletManager.CurrentWallet; if (wallet is { }) { var startingHeight = SmartHeader.GetStartingHeader(wallet.Network).Height; if (wallet.LastProcessedFilter?.Header?.Height is uint lastProcessedFilterHeight && lastProcessedFilterHeight > startingHeight && _bitcoinStore?.SmartHeaderChain?.TipHeight is uint tipHeight && tipHeight > startingHeight) { var allFilters = tipHeight - startingHeight; var processedFilters = lastProcessedFilterHeight - startingHeight; var perc = allFilters == 0 ? 100 : ((decimal)processedFilters / allFilters * 100); TryAddStatus(StatusType.WalletProcessingFilters, (ushort)perc); } var txProcessor = wallet.TransactionProcessor; if (txProcessor is { }) { var perc = txProcessor.QueuedTxCount == 0 ? 100 : ((decimal)txProcessor.QueuedProcessedTxCount / txProcessor.QueuedTxCount * 100); TryAddStatus(StatusType.WalletProcessingTransactions, (ushort)perc); } }
public CoinJoinViewModel(ChaincaseWalletManager walletManager, Config config, INotificationManager notificationManager, SelectCoinsViewModel selectCoinsViewModel) { _walletManager = walletManager; _config = config; _notificationManager = notificationManager; CoinList = selectCoinsViewModel; if (Disposables != null) { throw new Exception("Wallet opened before it was closed."); } Disposables = new CompositeDisposable(); // Infer coordinator fee var registrableRound = _walletManager.CurrentWallet?.ChaumianClient?.State?.GetRegistrableRoundOrDefault(); CoordinatorFeePercent = registrableRound?.State?.CoordinatorFeePercent.ToString() ?? "0.003"; // Select most advanced coin join round ClientRound mostAdvancedRound = _walletManager.CurrentWallet?.ChaumianClient?.State?.GetMostAdvancedRoundOrDefault(); if (mostAdvancedRound != default) { RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase, _walletManager.CurrentWallet.ChaumianClient?.State.IsInErrorState ?? false); RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration ? mostAdvancedRound.State.InputRegistrationTimesout : DateTimeOffset.UtcNow; PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount; PeersQueued = mostAdvancedRound.State.QueuedPeerCount; PeersNeeded = mostAdvancedRound.State.RequiredPeerCount; RequiredBTC = mostAdvancedRound.State.CalculateRequiredAmount(); } else { RoundPhaseState = new RoundPhaseState(RoundPhase.InputRegistration, false); RoundTimesout = DateTimeOffset.UtcNow; PeersRegistered = 0; PeersQueued = 0; PeersNeeded = 100; RequiredBTC = Money.Parse("0.01"); } // Set time left in round this.WhenAnyValue(x => x.RoundTimesout) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { TimeLeftTillRoundTimeout = TimeUntilOffset(RoundTimesout); }); Task.Run(async() => { while (_walletManager.CurrentWallet?.ChaumianClient == null) { await Task.Delay(50).ConfigureAwait(false); } // Update view model state on chaumian client state updates Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.CoinQueued)) .Merge(Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.OnDequeue))) .Merge(Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.StateUpdated))) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => UpdateStates()) .DisposeWith(Disposables); // Remove notification on unconfirming status in coin join round Observable.FromEventPattern(_walletManager.CurrentWallet.ChaumianClient, nameof(_walletManager.CurrentWallet.ChaumianClient.OnDequeue)) .Subscribe(pattern => { var e = (DequeueResult)pattern.EventArgs; try { foreach (var success in e.Successful.Where(x => x.Value.Any())) { DequeueReason reason = success.Key; if (reason == DequeueReason.UserRequested) { _notificationManager.RemoveAllPendingNotifications(); } } } catch (Exception ex) { Logger.LogWarning(ex); } }) .DisposeWith(Disposables); }); // Update timeout label Observable.Interval(TimeSpan.FromSeconds(1)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { TimeLeftTillRoundTimeout = TimeUntilOffset(RoundTimesout); }).DisposeWith(Disposables); }