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); }
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)); }
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(); } } }
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); }
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; }
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 })
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)); }
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 });
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 { });
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); } } }
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)); }
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); } });
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; }); }
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; }); } }); }
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); } }
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); }
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)); }); }
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(); } }
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); } });
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); }
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; }
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); }