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;
        }
示例#2
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));
        }
示例#3
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;
        }
示例#4
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);
            }
        });
示例#5
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));
            });
        }
示例#6
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);
            }
        });
示例#7
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;
        }
示例#8
0
        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);
            }
        }