Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
 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();
     }
 }
Ejemplo n.º 3
0
 public NewPasswordViewModel(ChaincaseWalletManager walletManager, Config config, UiConfig uiConfig, SensitiveStorage storage)
 {
     _walletManager = walletManager;
     _config        = config;
     _uiConfig      = uiConfig;
     _storage       = storage;
 }
Ejemplo n.º 4
0
 public WalletInfoViewModel(ChaincaseWalletManager walletManager, Config config, UiConfig uiConfig, IShare share, IDataDirProvider dataDirProvider)
 {
     _walletManager   = walletManager;
     _config          = config;
     _uiConfig        = uiConfig;
     _share           = share;
     _dataDirProvider = dataDirProvider;
 }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        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);
            });
        }
Ejemplo n.º 7
0
 public BackUpViewModel(Config config, UiConfig uiConfig, IHsmStorage hsm, SensitiveStorage storage, ChaincaseWalletManager walletManager)
 {
     _config        = config;
     _uiConfig      = uiConfig;
     _hsm           = hsm;
     _storage       = storage;
     _walletManager = walletManager;
 }
Ejemplo n.º 8
0
 public ReceiveViewModel(ChaincaseWalletManager walletManager, Config config)
 {
     _walletManager = walletManager;
     _config        = config;
 }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
                                }
                            }
Ejemplo n.º 11
0
        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);
        }