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; }
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)); }
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 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(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 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 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; }
private async Task TryRegisterCoinsAsync(CcjClientRound inputRegistrableRound) { try { List <(uint256 txid, uint index)> registrableCoins = State.GetRegistrableCoins( inputRegistrableRound.State.MaximumInputCountPerPeer, inputRegistrableRound.State.Denomination, inputRegistrableRound.State.FeePerInputs, inputRegistrableRound.State.FeePerOutputs).ToList(); if (registrableCoins.Any()) { BitcoinAddress changeAddress = null; BitcoinAddress activeAddress = null; lock (CustomChangeAddressesLock) { if (CustomChangeAddresses.Count > 0) { changeAddress = CustomChangeAddresses.First(); CustomChangeAddresses.RemoveFirst(); } } lock (CustomActiveAddressesLock) { if (CustomActiveAddresses.Count > 0) { activeAddress = CustomActiveAddresses.First(); CustomActiveAddresses.RemoveFirst(); } } if (changeAddress is null || activeAddress is null) { IEnumerable <HdPubKey> allUnusedInternalKeys = KeyManager.GetKeys(keyState: null, isInternal: true).Where(x => x.KeyState != KeyState.Used); if (changeAddress is null) { string changeLabel = "ZeroLink Change"; IEnumerable <HdPubKey> allChangeKeys = allUnusedInternalKeys.Where(x => x.Label == changeLabel); HdPubKey changeKey = null; KeyManager.AssertLockedInternalKeysIndexed(14); IEnumerable <HdPubKey> internalNotCachedLockedKeys = KeyManager.GetKeys(KeyState.Locked, isInternal: true).Except(AccessCache.Keys); if (allChangeKeys.Count() >= 7 || !internalNotCachedLockedKeys.Any()) // Then don't generate new keys, because it'd bloat the wallet. { // Find the first one that we did not try to register in the current session. changeKey = allChangeKeys.FirstOrDefault(x => !AccessCache.ContainsKey(x)); // If there is no such a key, then use the oldest. if (changeKey == default) { changeKey = AccessCache.Where(x => allChangeKeys.Contains(x.Key)).OrderBy(x => x.Value).First().Key; } changeKey.SetLabel(changeLabel); changeKey.SetKeyState(KeyState.Locked); } else { changeKey = internalNotCachedLockedKeys.RandomElement(); changeKey.SetLabel(changeLabel); } changeAddress = changeKey.GetP2wpkhAddress(Network); AccessCache.AddOrReplace(changeKey, DateTimeOffset.UtcNow); } if (activeAddress is null) { string activeLabel = "ZeroLink Mixed Coin"; IEnumerable <HdPubKey> allActiveKeys = allUnusedInternalKeys.Where(x => x.Label == activeLabel); HdPubKey activeKey = null; KeyManager.AssertLockedInternalKeysIndexed(14); IEnumerable <HdPubKey> internalNotCachedLockedKeys = KeyManager.GetKeys(KeyState.Locked, isInternal: true).Except(AccessCache.Keys); if (allActiveKeys.Count() >= 7 || !internalNotCachedLockedKeys.Any()) // Then don't generate new keys, because it'd bloat the wallet. { // Find the first one that we did not try to register in the current session. activeKey = allActiveKeys.FirstOrDefault(x => !AccessCache.ContainsKey(x)); // If there is no such a key, then use the oldest. if (activeKey == default) { activeKey = AccessCache.Where(x => allActiveKeys.Contains(x.Key)).OrderBy(x => x.Value).First().Key; } activeKey.SetLabel(activeLabel); activeKey.SetKeyState(KeyState.Locked); activeAddress = activeKey.GetP2wpkhAddress(Network); } else { activeKey = internalNotCachedLockedKeys.RandomElement(); activeKey.SetLabel(activeLabel); } activeAddress = activeKey.GetP2wpkhAddress(Network); AccessCache.AddOrReplace(activeKey, DateTimeOffset.UtcNow); } } KeyManager.ToFile(); var blind = CoordinatorPubKey.Blind(activeAddress.ScriptPubKey.ToBytes()); var inputProofs = new List <InputProofModel>(); foreach ((uint256 txid, uint index)coinReference in registrableCoins) { SmartCoin coin = State.GetSingleOrDefaultFromWaitingList(coinReference); if (coin is null) { throw new NotSupportedException("This is impossible."); } coin.Secret = coin.Secret ?? KeyManager.GetSecrets(OnePiece, coin.ScriptPubKey).Single(); var inputProof = new InputProofModel { Input = coin.GetTxoRef(), Proof = coin.Secret.PrivateKey.SignMessage(ByteHelpers.ToHex(blind.BlindedData)) }; inputProofs.Add(inputProof); } AliceClient aliceClient = await AliceClient.CreateNewAsync(Network, changeAddress, blind.BlindedData, inputProofs, CcjHostUri, TorSocks5EndPoint); byte[] unblindedSignature = CoordinatorPubKey.UnblindSignature(aliceClient.BlindedOutputSignature, blind.BlindingFactor); if (!CoordinatorPubKey.Verify(unblindedSignature, activeAddress.ScriptPubKey.ToBytes())) { throw new NotSupportedException("Coordinator did not sign the blinded output properly."); } CcjClientRound roundRegistered = State.GetSingleOrDefaultRound(aliceClient.RoundId); if (roundRegistered is null) { // If our SatoshiClient doesn't yet know about the round because of the dealy create it. // Make its state as it'd be the same as our assumed round was, except the roundId and registeredPeerCount, it'll be updated later. roundRegistered = new CcjClientRound(CcjRunningRoundState.CloneExcept(inputRegistrableRound.State, aliceClient.RoundId, registeredPeerCount: 1)); State.AddOrReplaceRound(roundRegistered); } foreach ((uint256 txid, uint index)coinReference in registrableCoins) { var coin = State.GetSingleOrDefaultFromWaitingList(coinReference); if (coin is null) { throw new NotSupportedException("This is impossible."); } roundRegistered.CoinsRegistered.Add(coin); State.RemoveCoinFromWaitingList(coin); } roundRegistered.ActiveOutputAddress = activeAddress; roundRegistered.ChangeOutputAddress = changeAddress; roundRegistered.UnblindedSignature = unblindedSignature; roundRegistered.AliceClient = aliceClient; } } catch (Exception ex) { Logger.LogError <CcjClient>(ex); } }