Example #1
0
    public async Task StartParticipatingAsync(CancellationToken cancellationToken)
    {
        ThrowIfDisposed();
        var apiClient = new WabiSabiHttpApiClient(HttpClientFactory.NewHttpClientWithDefaultCircuit());

        using var roundStateUpdater = new RoundStateUpdater(TimeSpan.FromSeconds(3), apiClient);
        await roundStateUpdater.StartAsync(cancellationToken).ConfigureAwait(false);

        var coinJoinClient = new CoinJoinClient(
            HttpClientFactory,
            Wallet,
            Wallet,
            roundStateUpdater,
            consolidationMode: true);

        // Run the coinjoin client task.
        var walletHdPubKey = new HdPubKey(Wallet.PubKey, KeyPath.Parse("m/84'/0/0/0/0"), SmartLabel.Empty, KeyState.Clean);

        walletHdPubKey.SetAnonymitySet(1);         // bug if not settled

        if (SplitTransaction is null)
        {
            throw new InvalidOperationException($"{nameof(GenerateCoinsAsync)} has to be called first.");
        }

        var smartCoins = SplitTransaction.Transaction.Outputs.AsIndexedOutputs()
                         .Select(x => new SmartCoin(SplitTransaction, x.N, walletHdPubKey))
                         .ToList();

        // Run the coinjoin client task.
        await coinJoinClient.StartCoinJoinAsync(smartCoins, cancellationToken).ConfigureAwait(false);

        await roundStateUpdater.StopAsync(cancellationToken).ConfigureAwait(false);
    }
        public ReceiveAddressViewModel(Wallet wallet, HdPubKey model)
        {
            _wallet           = wallet;
            _model            = model;
            Address           = _model.GetP2wpkhAddress(_wallet.Network).ToString();
            Labels            = _model.Label;
            IsHardwareWallet  = _wallet.KeyManager.IsHardwareWallet;
            IsAutoCopyEnabled = Services.UiConfig.Autocopy;

            GenerateQrCode();

            SetupCancel(enableCancel: false, enableCancelOnEscape: true, enableCancelOnPressed: true);

            EnableBack = true;

            CopyAddressCommand = ReactiveCommand.CreateFromTask(async() => await Application.Current.Clipboard.SetTextAsync(Address));

            ShowOnHwWalletCommand = ReactiveCommand.CreateFromTask(async() => await OnShowOnHwWalletAsync(_model, _wallet.Network, _wallet.KeyManager.MasterFingerprint));

            SaveQrCodeCommand = ReactiveCommand.CreateFromTask(async() => await OnSaveQrCodeAsync());

            SaveQrCodeCommand.ThrownExceptions
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex => Logger.LogError(ex));

            NextCommand = CancelCommand;
        }
        private async Task OnShowOnHwWalletAsync(HdPubKey model, Network network, HDFingerprint?masterFingerprint)
        {
            if (masterFingerprint is null)
            {
                return;
            }

            await Task.Run(async() =>
            {
                try
                {
                    var client    = new HwiClient(network);
                    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                    await client.DisplayAddressAsync(masterFingerprint.Value, model.FullKeyPath, cts.Token);
                }
                catch (FormatException ex) when(ex.Message.Contains("network") && network == Network.TestNet)
                {
                    // This exception happens everytime on TestNet because of Wasabi Keypath handling.
                    // The user doesn't need to know about it.
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                    await ShowErrorAsync(Title, ex.ToUserFriendlyString(), "We were unable to send the address to the device");
                }
            });
        }
        public AddressViewModel(HdPubKey model)
            : base(Locator.Current.GetService <IViewStackService>())
        {
            Global = Locator.Current.GetService <Global>();
            Global.NotificationManager.RequestAuthorization();

            Model = model;

            _bitcoinUri = this
                          .WhenAnyValue(x => x.RequestAmountViewModel.RequestAmount)
                          .Select(amount => {
                return($"bitcoin:{Address}?amount={amount}");
            })
                          .ToProperty(this, nameof(BitcoinUri));

            this.WhenAnyValue(x => x.BitcoinUri)
            .Subscribe((uri) => EncodeQRCode());

            RequestAmountCommand = ReactiveCommand.CreateFromObservable <Unit, Unit>(_ =>
            {
                if (RequestAmountViewModel is null)
                {
                    RequestAmountViewModel = new RequestAmountViewModel();
                }

                ViewStackService.PushModal(RequestAmountViewModel).Subscribe();
                return(Observable.Return(Unit.Default));
            });
            ShareCommand     = ReactiveCommand.CreateFromTask <string>(ShareBoundString);
            NavWalletCommand = ReactiveCommand.CreateFromObservable <Unit, Unit>(_ =>
            {
                ViewStackService.PopPage(false);
                return(ViewStackService.PopPage(true));
            });
        }
        private void AnalyzeCoinjoin(SmartTransaction tx, int newInputAnonset, ISet <HdPubKey> distinctWalletInputPubKeys)
        {
            var indistinguishableWalletOutputs = tx
                                                 .WalletOutputs.GroupBy(x => x.Amount)
                                                 .ToDictionary(x => x.Key, y => y.Count());

            var anonsets = tx.Transaction.GetAnonymitySets(tx.WalletOutputs.Select(x => x.Index));

            foreach (var newCoin in tx.WalletOutputs.ToArray())
            {
                // Begin estimating the anonymity set size based on the number of
                // equivalent outputs that the i-th output has in in the transaction.
                int anonset = anonsets[newCoin.Index];

                // Picking randomly an output would make our anonset: total/ours.
                anonset /= indistinguishableWalletOutputs[newCoin.Amount];

                // Account for the inherited anonymity set size from the inputs in the
                // anonymity set size estimate.
                // The anonymity set size estimated for the input cluster is corrected
                // by -1 to avoid double counting ourselves in the anonset.
                // Stated differently, the right value to use for the calculation is not the
                // anonymity set size, but the subset of only the other participants, since
                // every output must belong to a member of the set.
                anonset += newInputAnonset - 1;

                HdPubKey hdPubKey = newCoin.HdPubKey;
                uint256  txid     = tx.GetHash();
                if (hdPubKey.AnonymitySet == HdPubKey.DefaultHighAnonymitySet)
                {
                    // If the new coin's HD pubkey haven't been used yet
                    // then its anonset haven't been set yet.
                    // In that case the acquired anonset does not have to be intersected with the default anonset,
                    // so this coin gets the aquired anonset.
                    hdPubKey.SetAnonymitySet(anonset, txid);
                }
                else if (distinctWalletInputPubKeys.Contains(hdPubKey))
                {
                    // If it's a reuse of an input's pubkey, then intersection punishment is senseless.
                    hdPubKey.SetAnonymitySet(newInputAnonset, txid);
                }
                else if (tx.WalletOutputs.Where(x => x != newCoin).Select(x => x.HdPubKey).Contains(hdPubKey))
                {
                    // If it's a reuse of another output' pubkey, then intersection punishment can only go as low as the inherited anonset.
                    hdPubKey.SetAnonymitySet(Math.Max(newInputAnonset, Intersect(new[] { anonset, hdPubKey.AnonymitySet }, 1)), txid);
                }
                else if (hdPubKey.AnonymitySetReasons.Contains(txid))
                {
                    // If we already processed this transaction for this script
                    // then we'll go with normal processing, it's not an address reuse,
                    // it's just we're processing the transaction twice.
                    hdPubKey.SetAnonymitySet(anonset, txid);
                }
                else
                {
                    // It's address reuse.
                    hdPubKey.SetAnonymitySet(Intersect(new[] { anonset, hdPubKey.AnonymitySet }, 1), txid);
                }
            }
        }
        public AddressViewModel(HdPubKey model, Global global)
        {
            Global = global;
            Model  = model;
            ClipboardNotificationVisible = false;
            ClipboardNotificationOpacity = 0;

            // TODO fix this performance issue this should only be generated when accessed.
            Task.Run(() =>
            {
                var encoder = new QrEncoder();
                encoder.TryEncode(Address, out var qrCode);

                return(qrCode.Matrix.InternalArray);
            }).ContinueWith(x =>
            {
                QrCode = x.Result;
            });

            Global.UiConfig.WhenAnyValue(x => x.LurkingWifeMode).Subscribe(_ =>
            {
                this.RaisePropertyChanged(nameof(Address));
                this.RaisePropertyChanged(nameof(Label));
            }).DisposeWith(Disposables);
        }
        static HdPubKey CreateHdPubKey(ExtPubKey extPubKey)
        {
            var hdPubKey = new HdPubKey(extPubKey.PubKey, KeyPath.Parse($"m/84'/0/0/0/{extPubKey.Child}"), SmartLabel.Empty, KeyState.Clean);

            hdPubKey.SetAnonymitySet(1);             // bug if not settled
            return(hdPubKey);
        }
Example #8
0
        public AddressViewModel(HdPubKey model, Network network, Func <HdPubKey, string, Task> hideCommand)
        {
            Model    = model;
            _address = model.GetP2wpkhAddress(network).ToString();
            _label   = model.Label;

            CopyAddressCommand = ReactiveCommand.CreateFromTask(async() => await Application.Current.Clipboard.SetTextAsync(Address));
            HideAddressCommand = ReactiveCommand.CreateFromTask(async() => await hideCommand.Invoke(model, Address));
        }
Example #9
0
        private void ProcessTransaction(SmartTransaction tx, List <HdPubKey> keys = null)
        {
            // If key list is not provided refresh the key list.
            if (keys == null)
            {
                keys = KeyManager.GetKeys().ToList();
            }

            // If transaction received to any of the wallet keys:
            for (var i = 0; i < tx.Transaction.Outputs.Count; i++)
            {
                var      output   = tx.Transaction.Outputs[i];
                HdPubKey foundKey = keys.SingleOrDefault(x => x.GetP2wpkhScript() == output.ScriptPubKey);
                if (foundKey != default)
                {
                    // If we already had it, just update the height. Maybe got from mempool to block or reorged.
                    var foundCoin = Coins.SingleOrDefault(x => x.TransactionId == tx.GetHash() && x.Index == i);
                    if (foundCoin != default)
                    {
                        // If tx height is mempool then don't, otherwise update the height.
                        if (tx.Height == Height.MemPool)
                        {
                            continue;
                        }
                        else
                        {
                            foundCoin.Height = tx.Height;
                            continue;
                        }
                    }

                    foundKey.KeyState = KeyState.Used;
                    var coin = new SmartCoin(tx.GetHash(), i, output.ScriptPubKey, output.Value, tx.Transaction.Inputs.ToTxoRefs().ToArray(), tx.Height, foundKey.Label, null);
                    Coins.Add(coin);

                    // Make sure there's always 21 clean keys generated and indexed.
                    if (AssertCleanKeysIndexed(21, foundKey.IsInternal()))
                    {
                        // If it generated a new key refresh the keys:
                        keys = KeyManager.GetKeys().ToList();
                    }
                }
            }

            // If spends any of our coin
            for (var i = 0; i < tx.Transaction.Inputs.Count; i++)
            {
                var input = tx.Transaction.Inputs[i];

                var foundCoin = Coins.SingleOrDefault(x => x.TransactionId == input.PrevOut.Hash && x.Index == input.PrevOut.N);
                if (foundCoin != null)
                {
                    foundCoin.SpenderTransactionId = tx.GetHash();
                }
            }
        }
Example #10
0
        public AddressViewModel(HdPubKey model, Global global)
        {
            Global = global;
            Model  = model;
            ClipboardNotificationVisible = false;
            ClipboardNotificationOpacity = 0;
            _label = model.Label;

            this.WhenAnyValue(x => x.IsExpanded)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Where(x => x)
            .Take(1)
            .Subscribe(_ =>
            {
                try
                {
                    var encoder = new QrEncoder();
                    encoder.TryEncode(Address, out var qrCode);
                    Dispatcher.UIThread.PostLogException(() => QrCode = qrCode.Matrix.InternalArray);
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                }
            });

            Global.UiConfig.WhenAnyValue(x => x.LurkingWifeMode).Subscribe(_ =>
            {
                this.RaisePropertyChanged(nameof(IsLurkingWifeMode));
                this.RaisePropertyChanged(nameof(Address));
                this.RaisePropertyChanged(nameof(Label));
            }).DisposeWith(Disposables);

            this.WhenAnyValue(x => x.Label)
            .Subscribe(newLabel =>
            {
                if (InEditMode)
                {
                    KeyManager keyManager = Global.WalletService.KeyManager;
                    HdPubKey hdPubKey     = keyManager.GetKeys(x => Model == x).FirstOrDefault();

                    if (hdPubKey != default)
                    {
                        hdPubKey.SetLabel(newLabel, kmToFile: keyManager);
                    }
                }
            });

            _expandMenuCaption = this.WhenAnyValue(x => x.IsExpanded)
                                 .Select(x => (x ? "Hide " : "Show ") + "QR Code")
                                 .ObserveOn(RxApp.MainThreadScheduler)
                                 .ToProperty(this, x => x.ExpandMenuCaption)
                                 .DisposeWith(Disposables);
        }
Example #11
0
        public ReceiveAddressViewModel(HdPubKey model, Network network, HDFingerprint?masterFingerprint, bool isHardwareWallet)
        {
            Address          = model.GetP2wpkhAddress(network).ToString();
            Reference        = model.Label;
            IsHardwareWallet = isHardwareWallet;

            GenerateQrCode();

            CopyAddressCommand = ReactiveCommand.CreateFromTask(async() => await Application.Current.Clipboard.SetTextAsync(Address));

            ShowOnHwWalletCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (masterFingerprint is null)
                {
                    return;
                }

                await Task.Run(async() =>
                {
                    try
                    {
                        var client    = new HwiClient(network);
                        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                        await client.DisplayAddressAsync(masterFingerprint.Value, model.FullKeyPath, cts.Token);
                    }
                    catch (FormatException ex) when(ex.Message.Contains("network") && network == Network.TestNet)
                    {
                        // This exception happens everytime on TestNet because of Wasabi Keypath handling.
                        // The user doesn't need to know about it.
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(ex);
                        await ShowErrorAsync(Title, ex.ToUserFriendlyString(), "We were unable to send the address to the device");
                    }
                });
            });

            SaveQrCodeCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (QrCodeCommand is { } cmd)
                {
                    await cmd.Execute(Address);
                }
            });

            SaveQrCodeCommand.ThrownExceptions
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex => Logger.LogError(ex));

            NextCommand = CancelCommand;
        }
Example #12
0
    public async Task HideAddressAsync(HdPubKey model, string address)
    {
        var result = await NavigateDialogAsync(new ConfirmHideAddressViewModel(model.Label));

        if (result.Result == false)
        {
            return;
        }

        model.SetKeyState(KeyState.Locked, Wallet.KeyManager);
        InitializeAddresses();

        if (Application.Current is { Clipboard : { } clipboard })
Example #13
0
        public static SmartCoin RandomSmartCoin(HdPubKey pubKey, decimal amount, bool confirmed = true, int anonymitySet = 1)
        {
            var height = confirmed ? new Height(new Random().Next(0, 200)) : Height.Mempool;

            pubKey.SetKeyState(KeyState.Used);
            var tx = Transaction.Create(Network.Main);

            tx.Outputs.Add(new TxOut(Money.Coins(amount), pubKey.P2wpkhScript));
            var stx = new SmartTransaction(tx, height);

            pubKey.AnonymitySet = anonymitySet;
            return(new SmartCoin(stx, 0, pubKey));
        }
Example #14
0
        public AddressLabelEditViewModel(ReceiveAddressesViewModel owner, HdPubKey hdPubKey, KeyManager keyManager, HashSet <string> suggestions)
        {
            Suggestions = suggestions;
            _labels     = new(hdPubKey.Label);

            SetupCancel(enableCancel: true, enableCancelOnEscape: true, enableCancelOnPressed: true);

            Labels
            .WhenAnyValue(x => x.Count)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ => FinalLabel = new SmartLabel(Labels));

            var canExecute = this.WhenAnyValue(x => x.FinalLabel).Select(x => x is { IsEmpty: false });
Example #15
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 { });
Example #16
0
        private void AnalyzeCoinjoin(SmartTransaction tx, int newInputAnonset, ISet <HdPubKey> distinctWalletInputPubKeys)
        {
            var indistinguishableWalletOutputs = tx
                                                 .WalletOutputs.GroupBy(x => x.Amount)
                                                 .ToDictionary(x => x.Key, y => y.Count());

            var anonsets = tx.Transaction.GetAnonymitySets(tx.WalletOutputs.Select(x => x.Index));

            foreach (var newCoin in tx.WalletOutputs.ToArray())
            {
                // Begin estimating the anonymity set size based on the number of
                // equivalent outputs that the i-th output has in in the transaction.
                int anonset = anonsets[newCoin.Index];

                // Don't count our own equivalent outputs in the anonset.
                anonset -= indistinguishableWalletOutputs[newCoin.Amount] - 1;

                // Account for the inherited anonymity set size from the inputs in the
                // anonymity set size estimate.
                // The anonymity set size estimated for the input cluster is corrected
                // by -1 to avoid double counting ourselves in the anonset.
                // Stated differently, the right value to use for the calculation is not the
                // anonymity set size, but the subset of only the other participants, since
                // every output must belong to a member of the set.
                anonset += newInputAnonset - 1;

                HdPubKey hdPubKey = newCoin.HdPubKey;
                if (hdPubKey.AnonymitySet == HdPubKey.DefaultHighAnonymitySet)
                {
                    // If the new coin's HD pubkey haven't been used yet
                    // then its anonset haven't been set yet.
                    // In that case the acquired anonset does not have to be intersected with the default anonset,
                    // so this coin gets the aquired anonset.
                    hdPubKey.AnonymitySet = anonset;
                }
                else if (distinctWalletInputPubKeys.Contains(hdPubKey))
                {
                    // If it's a reuse of an input's pubkey, then intersection punishment is senseless.
                    hdPubKey.AnonymitySet = newInputAnonset;
                }
                else if (tx.WalletOutputs.Where(x => x != newCoin).Select(x => x.HdPubKey).Contains(hdPubKey))
                {
                    // If it's a reuse of another output' pubkey, then intersection punishment can only go as low as the inherited anonset.
                    hdPubKey.AnonymitySet = Math.Max(newInputAnonset, Intersect(new[] { anonset, hdPubKey.AnonymitySet }, 1));
                }
                else
                {
                    hdPubKey.AnonymitySet = Intersect(new[] { anonset, hdPubKey.AnonymitySet }, 1);
                }
            }
        }
Example #17
0
        private static SmartCoin Coin(string label, HdPubKey pubKey, decimal amount, bool confirmed = true, int anonymitySet = 1)
        {
            var        randomIndex = new Func <int>(() => new Random().Next(0, 200));
            var        height      = confirmed ? new Height(randomIndex()) : Height.Mempool;
            SmartLabel slabel      = label;
            var        spentOutput = new[]
            {
                new OutPoint(RandomUtils.GetUInt256(), (uint)randomIndex())
            };

            pubKey.SetLabel(slabel);
            pubKey.SetKeyState(KeyState.Used);
            return(new SmartCoin(RandomUtils.GetUInt256(), (uint)randomIndex(), pubKey.P2wpkhScript, Money.Coins(amount), spentOutput, height, false, anonymitySet, slabel, pubKey: pubKey));
        }
Example #18
0
    public AddressViewModel(ReceiveAddressesViewModel parent, Wallet wallet, HdPubKey model, Network network)
    {
        _address = model.GetP2wpkhAddress(network).ToString();

        Label = model.Label;

        CopyAddressCommand =
            ReactiveCommand.CreateFromTask(async() =>
        {
            if (Application.Current is { Clipboard: { } clipboard })
            {
                await clipboard.SetTextAsync(Address);
            }
        });
Example #19
0
        public AddressViewModel(HdPubKey model)
        {
            Model = model;

            Task.Run(() =>
            {
                var encoder = new QrEncoder(ErrorCorrectionLevel.M);
                encoder.TryEncode(Address, out var qrCode);

                return(qrCode.Matrix.InternalArray);
            }).ContinueWith(x => {
                QrCode = x.Result;
            });
        }
Example #20
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;
                    });
                }
            });
        }
Example #21
0
        private volatile bool _disposedValue = false;         // To detect redundant calls

        public AddressViewModel(HdPubKey model, KeyManager km, ReceiveTabViewModel owner)
        {
            Global                       = Locator.Current.GetService <Global>();
            KeyManager                   = km;
            Owner                        = owner;
            IsHardwareWallet             = km.IsHardwareWallet;
            Model                        = model;
            ClipboardNotificationVisible = false;
            ClipboardNotificationOpacity = 0;
            _label                       = model.Label;

            this.WhenAnyValue(x => x.IsExpanded)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Where(x => x)
            .Take(1)
            .Select(x =>
            {
                var encoder = new QrEncoder();
                encoder.TryEncode(Address, out var qrCode);
                return(qrCode.Matrix.InternalArray);
            })
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(qr => QrCode = qr, onError: ex => Logger.LogError(ex));                     // Catch the exceptions everywhere (e.g.: Select) except in Subscribe.

            Global.UiConfig
            .WhenAnyValue(x => x.PrivacyMode)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
                this.RaisePropertyChanged(nameof(IsPrivacyMode));
                this.RaisePropertyChanged(nameof(Address));
                this.RaisePropertyChanged(nameof(Label));
            }).DisposeWith(Disposables);

            this.WhenAnyValue(x => x.Label)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(newLabel =>
            {
                if (InEditMode)
                {
                    KeyManager keyManager = KeyManager;
                    HdPubKey hdPubKey     = keyManager.GetKeys(x => Model == x).FirstOrDefault();

                    if (hdPubKey is { })
                    {
                        hdPubKey.SetLabel(newLabel, kmToFile: keyManager);
                    }
                }
Example #22
0
        public HdPubKey GetReceiveKey(string label)
        {
            label = Guard.Correct(label);

            // Make sure there's always 21 clean keys generated and indexed.
            AssertCleanKeysIndexed(21, false);

            IEnumerable <HdPubKey> keys = KeyManager.GetKeys(KeyState.Clean, false);

            var      foundLabelless = keys.FirstOrDefault(x => !x.HasLabel());                             // return the first labelless
            HdPubKey ret            = foundLabelless ?? KeyManager.GetKeys(KeyState.Clean, false).First(); // return the first, because that's the oldest

            ret.SetLabel(label, KeyManager);

            return(ret);
        }
Example #23
0
        public AddressViewModel(ReceiveAddressesViewModel parent, Wallet wallet, HdPubKey model, Network network)
        {
            _address = model.GetP2wpkhAddress(network).ToString();
            _label   = model.Label;

            CopyAddressCommand =
                ReactiveCommand.CreateFromTask(async() => await Application.Current.Clipboard.SetTextAsync(Address));
            HideAddressCommand =
                ReactiveCommand.CreateFromTask(async() => await parent.HideAddressAsync(model, Address));
            EditLabelCommand =
                ReactiveCommand.Create(() => parent.NavigateToAddressEdit(model, parent.Wallet.KeyManager));

            NavigateCommand = ReactiveCommand.Create(() =>
            {
                parent.Navigate().To(new ReceiveAddressViewModel(wallet, model));
            });
        }
Example #24
0
        public SmartCoin(SmartTransaction transaction, uint outputIndex, HdPubKey pubKey)
        {
            Transaction    = transaction;
            Index          = outputIndex;
            _transactionId = new Lazy <uint256>(() => Transaction.GetHash(), true);

            _outPoint = new Lazy <OutPoint>(() => new OutPoint(TransactionId, Index), true);
            _txOut    = new Lazy <TxOut>(() => Transaction.Transaction.Outputs[Index], true);
            _coin     = new Lazy <Coin>(() => new Coin(OutPoint, TxOut), true);

            _hashCode = new Lazy <int>(() => OutPoint.GetHashCode(), true);

            Height = transaction.Height;

            HdPubKey = pubKey;

            Transaction.WalletOutputs.Add(this);
        }
        private async Task HideAddress(HdPubKey model, string address)
        {
            var result = await NavigateDialog(new ConfirmHideAddressViewModel(model.Label));

            if (result.Result == false)
            {
                return;
            }

            model.SetKeyState(KeyState.Locked, Wallet.KeyManager);
            InitializeAddresses();

            var isAddressCopied = await Application.Current.Clipboard.GetTextAsync() == address;

            if (isAddressCopied)
            {
                await Application.Current.Clipboard.ClearAsync();
            }
        }
Example #26
0
    public ReceiveAddressViewModel(Wallet wallet, HdPubKey model)
    {
        _wallet           = wallet;
        _model            = model;
        Address           = _model.GetP2wpkhAddress(_wallet.Network).ToString();
        Labels            = _model.Label;
        IsHardwareWallet  = _wallet.KeyManager.IsHardwareWallet;
        IsAutoCopyEnabled = Services.UiConfig.Autocopy;

        GenerateQrCode();

        SetupCancel(enableCancel: false, enableCancelOnEscape: true, enableCancelOnPressed: true);

        EnableBack = true;

        CopyAddressCommand = ReactiveCommand.CreateFromTask(async() =>
        {
            if (Application.Current is { Clipboard: { } clipboard })
            {
                await clipboard.SetTextAsync(Address);
            }
        });
Example #27
0
    public AddressLabelEditViewModel(ReceiveAddressesViewModel owner, HdPubKey hdPubKey, KeyManager keyManager)
    {
        SuggestionLabels = new SuggestionLabelsViewModel(keyManager, Intent.Receive, 3, hdPubKey.Label);

        SetupCancel(enableCancel: true, enableCancelOnEscape: true, enableCancelOnPressed: true);

        var canExecute =
            this.WhenAnyValue(x => x.SuggestionLabels.Labels.Count, x => x.IsCurrentTextValid)
            .Select(tup =>
        {
            var(labelsCount, isCurrentTextValid) = tup;
            return(labelsCount > 0 || isCurrentTextValid);
        });

        NextCommand = ReactiveCommand.Create(
            () =>
        {
            hdPubKey.SetLabel(new SmartLabel(SuggestionLabels.Labels), kmToFile: keyManager);
            owner.InitializeAddresses();
            Navigate().Back();
        },
            canExecute);
    }
Example #28
0
        public ReceiveAddressViewModel(HdPubKey model, Network network, HDFingerprint?masterFingerprint, bool isHardwareWallet)
        {
            Address          = model.GetP2wpkhAddress(network).ToString();
            Reference        = model.Label;
            IsHardwareWallet = isHardwareWallet;

            GenerateQrCode();

            EnableCancel = false;

            EnableBack = true;

            CopyAddressCommand = ReactiveCommand.CreateFromTask(async() => await Application.Current.Clipboard.SetTextAsync(Address));

            ShowOnHwWalletCommand = ReactiveCommand.CreateFromTask(async() => await OnShowOnHwWallet(model, network, masterFingerprint));

            SaveQrCodeCommand = ReactiveCommand.CreateFromTask(async() => await OnSaveQrCode());

            SaveQrCodeCommand.ThrownExceptions
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex => Logger.LogError(ex));

            NextCommand = CancelCommand;
        }
Example #29
0
        public AddressViewModel(HdPubKey model)
        {
            Model = model;

            this.WhenAnyValue(x => x.IsExpanded).Subscribe(async expanded =>
            {
                if (expanded && !_generating && QrCode == null)
                {
                    IsBusy = true;

                    _generating = true;

                    QrCode = await Task.Run(() =>
                    {
                        var encoder = new QrEncoder(ErrorCorrectionLevel.H);
                        encoder.TryEncode(Address, out var qrCode);

                        return(qrCode.Matrix.InternalArray);
                    });

                    IsBusy = false;
                }
            });
        }
        public AddressViewModel(HdPubKey model, Global global)
        {
            Global = global;
            Model  = model;
            ClipboardNotificationVisible = false;
            ClipboardNotificationOpacity = 0;

            this.WhenAnyValue(x => x.IsExpanded)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(x =>
            {
                try
                {
                    if (x == true && QrCodeBacking is null)
                    {
                        var encoder = new QrEncoder();
                        encoder.TryEncode(Address, out var qrCode);
                        QrCodeBacking = qrCode.Matrix.InternalArray;
                    }
                }
                catch (Exception ex)
                {
                    Logging.Logger.LogError <AddressViewModel>(ex);
                }
            });

            this.WhenAnyValue(x => x.QrCodeBacking)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(x => QrCode = x);

            Global.UiConfig.WhenAnyValue(x => x.LurkingWifeMode).Subscribe(_ =>
            {
                this.RaisePropertyChanged(nameof(Address));
                this.RaisePropertyChanged(nameof(Label));
            }).DisposeWith(Disposables);
        }