예제 #1
0
        /// <summary>
        /// Handle the data context changing.
        /// </summary>
        /// <param name="sender">
        /// The event sender.
        /// </param>
        /// <param name="e">
        /// The event arguments.
        /// </param>
        private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            TransactionUnlockViewModel oldViewModel = e.OldValue as TransactionUnlockViewModel;
            TransactionUnlockViewModel newViewModel = e.NewValue as TransactionUnlockViewModel;

            if (oldViewModel != null)
            {
                oldViewModel.ReadyToClose -= OnViewModelReadyToClose;
            }
            if (newViewModel != null)
            {
                newViewModel.ReadyToClose += OnViewModelReadyToClose;
            }
        }
        /// <summary>
        /// Purchase SIFT from one of our accounts.
        /// </summary>
        /// <param name="address">
        /// The account to use for purchase.
        /// </param>
        /// <param name="quantity">
        /// The quantity to purchase.
        /// </param>
        /// <returns>
        /// Details of the purchase result indicating whether a success or failure happened.
        /// </returns>
        public async Task <SiftPurchaseResponse> PurchaseSift(string address, uint quantity)
        {
            try
            {
                // Ensure we have the balance
                decimal         purchaseCostWei = WeiPerSift * quantity;
                EthereumAccount account         = Accounts.FirstOrDefault(acc => acc.Address == address);
                if (account == null)
                {
                    return(new SiftPurchaseResponse(SiftPurchaseFailureType.UnknownAccount, "The specified account address is not known."));
                }
                if (account.BalanceWei < purchaseCostWei)
                {
                    return(new SiftPurchaseResponse(SiftPurchaseFailureType.InsufficientFunds, "The specified account does not have sufficient funds."));
                }

                // Determine the gas cost for this
                TransactionGasInfo gasInfo = await CalculateGasCostForEtherSend(address, IcoContractAddress, purchaseCostWei);

                decimal gasPrice          = gasInfo.GasPrice;
                decimal gasCost           = gasInfo.GasCost;
                decimal gas               = gasInfo.Gas;
                decimal remainingGasMoney = account.BalanceWei - purchaseCostWei;
                if (remainingGasMoney < gasCost)
                {
                    return(new SiftPurchaseResponse(SiftPurchaseFailureType.InsufficientGas, "You do not have enough gas for this transaction."));
                }
                byte    gasMultiple = 25;
                decimal maximumGasCost;
                while ((maximumGasCost = gasCost * gasMultiple) * gasPrice > remainingGasMoney)
                {
                    gasMultiple--;
                }

                // Prompt to unlock account
                Logger.ApplicationInstance.Debug("Asking user confirmation for sending " + purchaseCostWei + " from " + address + " to " + IcoContractAddress);
                Func <TransactionUnlockViewModel> fnc = new Func <TransactionUnlockViewModel>(() =>
                {
                    TransactionUnlockViewModel vm  = new TransactionUnlockViewModel(gasCost, gasMultiple, gas, address, IcoContractAddress, purchaseCostWei);
                    TransactionUnlockWindow window = new TransactionUnlockWindow
                    {
                        DataContext = vm
                    };
                    window.ShowDialog();
                    return(vm);
                });
                TransactionUnlockViewModel viewModel = Application.Current.Dispatcher.Invoke(fnc);
                if (viewModel.WasCancelled)
                {
                    return(new SiftPurchaseResponse(SiftPurchaseFailureType.UserCancelled, "User cancelled transaction on confirmation screen."));
                }

                // Unlock the account
                SiftDialog dialog = SiftDialog.ShowButtonless("Sending Transaction", "Please wait whilst the transaction to buy SIFT is sent to the Ethereum network, this should only take a few seconds...", true);
                Logger.ApplicationInstance.Debug("Attempting to unlock " + address);
                if (!await _web3.Personal.UnlockAccount.SendRequestAsync(address, viewModel.Password == null ? string.Empty : viewModel.Password.ToString(), 120))
                {
                    return(new SiftPurchaseResponse(SiftPurchaseFailureType.UnlockError, "Unable to unlock account with the supplied password."));
                }

                // Send and mine the transaction
                Logger.ApplicationInstance.Debug("Account unlocked, sending " + purchaseCostWei + " from " + address + " to " + IcoContractAddress);
                TransactionInput transactionInput = new TransactionInput
                {
                    From     = address,
                    To       = IcoContractAddress,
                    Value    = new HexBigInteger(new BigInteger(purchaseCostWei)),
                    GasPrice = new HexBigInteger(new BigInteger(viewModel.SelectedGasMultiplier * gasCost)),
                    Gas      = new HexBigInteger(new BigInteger(viewModel.Gas))
                };
                Logger.ApplicationInstance.Info("Sending transaction for " + purchaseCostWei + " to " + IcoContractAddress + " from " + address);
                string transactionHash = await _web3.Eth.Transactions.SendTransaction.SendRequestAsync(transactionInput);

                Action act = dialog.Close;
                if (dialog.Dispatcher.CheckAccess())
                {
                    act();
                }
                else
                {
                    dialog.Dispatcher.Invoke(act);
                }

                // Return the response of the transaction hash
                return(new SiftPurchaseResponse(transactionHash));
            }
            catch (Exception ex)
            {
                Logger.ApplicationInstance.Error("Error purchasing SIFT", ex);
                if (ex.Message.Contains("personal_unlockAccount method not implemented"))
                {
                    return(new SiftPurchaseResponse(SiftPurchaseFailureType.MissingRpcPersonal, "Your geth installation doesn't have the personal RPC enabled, please enable it to continue."));
                }
                else if (ex.Message.Contains("could not decrypt key with given passphrase"))
                {
                    return(new SiftPurchaseResponse(SiftPurchaseFailureType.PasswordInvalid, "The password you supplied was incorrect"));
                }
                return(new SiftPurchaseResponse(SiftPurchaseFailureType.Unknown, ex.ToString()));
            }
        }
예제 #3
0
        /// <summary>
        /// Handle the password being changed.
        /// </summary>
        /// <param name="sender">
        /// The event sender.
        /// </param>
        /// <param name="e">
        /// The event arguments.
        /// </param>
        private void OnPasswordChanged(object sender, RoutedEventArgs e)
        {
            TransactionUnlockViewModel vm = (TransactionUnlockViewModel)DataContext;

            vm.Password = ((PasswordBox)sender).SecurePassword;
        }