Search in sources :

Example 6 with Trade

use of io.bitsquare.trade.Trade in project bitsquare by bitsquare.

the class NotificationCenter method onAllServicesAndViewsInitialized.

public void onAllServicesAndViewsInitialized() {
    tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> {
        change.next();
        if (change.wasRemoved()) {
            change.getRemoved().stream().forEach(trade -> {
                String tradeId = trade.getId();
                if (disputeStateSubscriptionsMap.containsKey(tradeId)) {
                    disputeStateSubscriptionsMap.get(tradeId).unsubscribe();
                    disputeStateSubscriptionsMap.remove(tradeId);
                }
                if (tradeStateSubscriptionsMap.containsKey(tradeId)) {
                    tradeStateSubscriptionsMap.get(tradeId).unsubscribe();
                    tradeStateSubscriptionsMap.remove(tradeId);
                }
            });
        }
        if (change.wasAdded()) {
            change.getAddedSubList().stream().forEach(trade -> {
                String tradeId = trade.getId();
                if (disputeStateSubscriptionsMap.containsKey(tradeId)) {
                    log.debug("We have already an entry in disputeStateSubscriptionsMap.");
                } else {
                    Subscription disputeStateSubscription = EasyBind.subscribe(trade.disputeStateProperty(), disputeState -> onDisputeStateChanged(trade, disputeState));
                    disputeStateSubscriptionsMap.put(tradeId, disputeStateSubscription);
                }
                if (tradeStateSubscriptionsMap.containsKey(tradeId)) {
                    log.debug("We have already an entry in tradeStateSubscriptionsMap.");
                } else {
                    Subscription tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), tradeState -> onTradeStateChanged(trade, tradeState));
                    tradeStateSubscriptionsMap.put(tradeId, tradeStateSubscription);
                }
            });
        }
    });
    tradeManager.getTrades().stream().forEach(trade -> {
        String tradeId = trade.getId();
        Subscription disputeStateSubscription = EasyBind.subscribe(trade.disputeStateProperty(), disputeState -> onDisputeStateChanged(trade, disputeState));
        disputeStateSubscriptionsMap.put(tradeId, disputeStateSubscription);
        Subscription tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), tradeState -> onTradeStateChanged(trade, tradeState));
        tradeStateSubscriptionsMap.put(tradeId, tradeStateSubscription);
    });
}
Also used : MainView(io.bitsquare.gui.main.MainView) Logger(org.slf4j.Logger) Inject(com.google.inject.Inject) UserThread(io.bitsquare.common.UserThread) LoggerFactory(org.slf4j.LoggerFactory) DisputeManager(io.bitsquare.arbitration.DisputeManager) Trade(io.bitsquare.trade.Trade) HashMap(java.util.HashMap) Subscription(org.fxmisc.easybind.Subscription) ArrayList(java.util.ArrayList) DisputesView(io.bitsquare.gui.main.disputes.DisputesView) Consumer(java.util.function.Consumer) TradeManager(io.bitsquare.trade.TradeManager) Preferences(io.bitsquare.user.Preferences) PortfolioView(io.bitsquare.gui.main.portfolio.PortfolioView) List(java.util.List) ListChangeListener(javafx.collections.ListChangeListener) EasyBind(org.fxmisc.easybind.EasyBind) Navigation(io.bitsquare.gui.Navigation) TraderDisputeView(io.bitsquare.gui.main.disputes.trader.TraderDisputeView) Map(java.util.Map) PendingTradesView(io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView) Nullable(javax.annotation.Nullable) Log(io.bitsquare.app.Log) Trade(io.bitsquare.trade.Trade) Subscription(org.fxmisc.easybind.Subscription)

Example 7 with Trade

use of io.bitsquare.trade.Trade in project bitsquare by bitsquare.

the class DisputeManager method onDisputeResultMessage.

// We get that message at both peers. The dispute object is in context of the trader
private void onDisputeResultMessage(DisputeResultMessage disputeResultMessage) {
    DisputeResult disputeResult = disputeResultMessage.disputeResult;
    if (!isArbitrator(disputeResult)) {
        final String tradeId = disputeResult.tradeId;
        Optional<Dispute> disputeOptional = findDispute(tradeId, disputeResult.traderId);
        final String uid = disputeResultMessage.getUID();
        if (disputeOptional.isPresent()) {
            cleanupRetryMap(uid);
            Dispute dispute = disputeOptional.get();
            DisputeCommunicationMessage disputeCommunicationMessage = disputeResult.getDisputeCommunicationMessage();
            if (!dispute.getDisputeCommunicationMessagesAsObservableList().contains(disputeCommunicationMessage))
                dispute.addDisputeMessage(disputeCommunicationMessage);
            else
                log.warn("We got a dispute mail msg what we have already stored. TradeId = " + disputeCommunicationMessage.getTradeId());
            dispute.setIsClosed(true);
            if (dispute.disputeResultProperty().get() != null)
                log.warn("We got already a dispute result. That should only happen if a dispute needs to be closed " + "again because the first close did not succeed. TradeId = " + tradeId);
            dispute.setDisputeResult(disputeResult);
            // We need to avoid publishing the tx from both traders as it would create problems with zero confirmation withdrawals
            // There would be different transactions if both sign and publish (signers: once buyer+arb, once seller+arb)
            // The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives 
            // more BTC as he has deposited
            final Contract contract = dispute.getContract();
            boolean isBuyer = keyRing.getPubKeyRing().equals(contract.getBuyerPubKeyRing());
            DisputeResult.Winner publisher = disputeResult.getWinner();
            // Default isLoserPublisher is set to false
            if (disputeResult.isLoserPublisher()) {
                // we invert the logic
                if (publisher == DisputeResult.Winner.BUYER)
                    publisher = DisputeResult.Winner.SELLER;
                else if (publisher == DisputeResult.Winner.SELLER)
                    publisher = DisputeResult.Winner.BUYER;
            }
            if ((isBuyer && publisher == DisputeResult.Winner.BUYER) || (!isBuyer && publisher == DisputeResult.Winner.SELLER) || (isBuyer && publisher == DisputeResult.Winner.STALE_MATE)) {
                final Optional<Trade> tradeOptional = tradeManager.getTradeById(tradeId);
                Transaction payoutTx = null;
                if (tradeOptional.isPresent()) {
                    payoutTx = tradeOptional.get().getPayoutTx();
                } else {
                    final Optional<Tradable> tradableOptional = closedTradableManager.getTradableById(tradeId);
                    if (tradableOptional.isPresent() && tradableOptional.get() instanceof Trade) {
                        payoutTx = ((Trade) tradableOptional.get()).getPayoutTx();
                    }
                }
                if (payoutTx == null) {
                    if (dispute.getDepositTxSerialized() != null) {
                        try {
                            log.debug("do payout Transaction ");
                            AddressEntry multiSigAddressEntry = walletService.getOrCreateAddressEntry(dispute.getTradeId(), AddressEntry.Context.MULTI_SIG);
                            Transaction signedDisputedPayoutTx = tradeWalletService.traderSignAndFinalizeDisputedPayoutTx(dispute.getDepositTxSerialized(), disputeResult.getArbitratorSignature(), disputeResult.getBuyerPayoutAmount(), disputeResult.getSellerPayoutAmount(), disputeResult.getArbitratorPayoutAmount(), contract.getBuyerPayoutAddressString(), contract.getSellerPayoutAddressString(), disputeResult.getArbitratorAddressAsString(), multiSigAddressEntry.getKeyPair(), contract.getBuyerMultiSigPubKey(), contract.getSellerMultiSigPubKey(), disputeResult.getArbitratorPubKey());
                            Transaction committedDisputedPayoutTx = tradeWalletService.addTransactionToWallet(signedDisputedPayoutTx);
                            log.debug("broadcast committedDisputedPayoutTx");
                            tradeWalletService.broadcastTx(committedDisputedPayoutTx, new FutureCallback<Transaction>() {

                                @Override
                                public void onSuccess(Transaction transaction) {
                                    log.debug("BroadcastTx succeeded. Transaction:" + transaction);
                                    // after successful publish we send peer the tx
                                    dispute.setDisputePayoutTxId(transaction.getHashAsString());
                                    sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);
                                    // set state after payout as we call swapTradeEntryToAvailableEntry 
                                    if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
                                        tradeManager.closeDisputedTrade(dispute.getTradeId());
                                    else {
                                        Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(dispute.getTradeId());
                                        if (openOfferOptional.isPresent())
                                            openOfferManager.closeOpenOffer(openOfferOptional.get().getOffer());
                                    }
                                }

                                @Override
                                public void onFailure(@NotNull Throwable t) {
                                    log.error(t.getMessage());
                                }
                            });
                        } catch (AddressFormatException | WalletException | TransactionVerificationException e) {
                            e.printStackTrace();
                            log.error("Error at traderSignAndFinalizeDisputedPayoutTx " + e.getMessage());
                        }
                    } else {
                        log.warn("DepositTx is null. TradeId = " + tradeId);
                    }
                } else {
                    log.warn("We got already a payout tx. That might be the case if the other peer did not get the " + "payout tx and opened a dispute. TradeId = " + tradeId);
                    dispute.setDisputePayoutTxId(payoutTx.getHashAsString());
                    sendPeerPublishedPayoutTxMessage(payoutTx, dispute, contract);
                }
            } else {
                log.trace("We don't publish the tx as we are not the winning party.");
                // Clean up tangling trades
                if (dispute.disputeResultProperty().get() != null && dispute.isClosed() && tradeManager.getTradeById(dispute.getTradeId()).isPresent())
                    tradeManager.closeDisputedTrade(dispute.getTradeId());
            }
        } else {
            log.debug("We got a dispute result msg but we don't have a matching dispute. " + "That might happen when we get the disputeResultMessage before the dispute was created. " + "We try again after 2 sec. to apply the disputeResultMessage. TradeId = " + tradeId);
            if (!delayMsgMap.containsKey(uid)) {
                // We delay2 sec. to be sure the comm. msg gets added first
                Timer timer = UserThread.runAfter(() -> onDisputeResultMessage(disputeResultMessage), 2);
                delayMsgMap.put(uid, timer);
            } else {
                log.warn("We got a dispute result msg after we already repeated to apply the message after a delay. " + "That should never happen. TradeId = " + tradeId);
            }
        }
    } else {
        log.error("Arbitrator received disputeResultMessage. That must never happen.");
    }
}
Also used : WalletException(io.bitsquare.btc.exceptions.WalletException) AddressFormatException(org.bitcoinj.core.AddressFormatException) Optional(java.util.Optional) AddressEntry(io.bitsquare.btc.AddressEntry) TransactionVerificationException(io.bitsquare.btc.exceptions.TransactionVerificationException) Tradable(io.bitsquare.trade.Tradable) Trade(io.bitsquare.trade.Trade) Transaction(org.bitcoinj.core.Transaction) Timer(io.bitsquare.common.Timer) Contract(io.bitsquare.trade.Contract)

Example 8 with Trade

use of io.bitsquare.trade.Trade in project bitsquare by bitsquare.

the class TradeProtocol method cleanupTradable.

private void cleanupTradable() {
    Trade.State tradeState = trade.getState();
    log.debug("cleanupTradable tradeState=" + tradeState);
    boolean isOffererTrade = trade instanceof OffererTrade;
    if (isOffererTrade && (tradeState == Trade.State.OFFERER_SENT_PUBLISH_DEPOSIT_TX_REQUEST || tradeState == Trade.State.DEPOSIT_SEEN_IN_NETWORK))
        processModel.getOpenOfferManager().closeOpenOffer(trade.getOffer());
    //boolean isTakerTrade = trade instanceof TakerTrade;
    // if (isTakerTrade) {
    TradeManager tradeManager = processModel.getTradeManager();
    if (tradeState.getPhase() == Trade.Phase.PREPARATION) {
        tradeManager.removePreparedTrade(trade);
    } else if (tradeState.getPhase() == Trade.Phase.TAKER_FEE_PAID) {
        tradeManager.addTradeToFailedTrades(trade);
        processModel.getWalletService().swapAnyTradeEntryContextToAvailableEntry(trade.getId());
    }
// }
}
Also used : TradeManager(io.bitsquare.trade.TradeManager) OffererTrade(io.bitsquare.trade.OffererTrade) Trade(io.bitsquare.trade.Trade) OffererTrade(io.bitsquare.trade.OffererTrade)

Example 9 with Trade

use of io.bitsquare.trade.Trade in project bitsquare by bitsquare.

the class MainViewModel method onAllServicesInitialized.

private void onAllServicesInitialized() {
    Log.traceCall();
    clock.start();
    // disputeManager
    disputeManager.onAllServicesInitialized();
    disputeManager.getDisputesAsObservableList().addListener((ListChangeListener<Dispute>) change -> {
        change.next();
        onDisputesChangeListener(change.getAddedSubList(), change.getRemoved());
    });
    onDisputesChangeListener(disputeManager.getDisputesAsObservableList(), null);
    // tradeManager
    tradeManager.onAllServicesInitialized();
    tradeManager.getTrades().addListener((ListChangeListener<Trade>) c -> updateBalance());
    tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> onTradesChanged());
    onTradesChanged();
    // We handle the trade period here as we display a global popup if we reached dispute time
    tradesAndUIReady = EasyBind.combine(isSplashScreenRemoved, tradeManager.pendingTradesInitializedProperty(), (a, b) -> a && b);
    tradesAndUIReady.subscribe((observable, oldValue, newValue) -> {
        if (newValue)
            applyTradePeriodState();
    });
    // walletService
    walletService.addBalanceListener(new BalanceListener() {

        @Override
        public void onBalanceChanged(Coin balance, Transaction tx) {
            updateBalance();
        }
    });
    openOfferManager.getOpenOffers().addListener((ListChangeListener<OpenOffer>) c -> updateBalance());
    tradeManager.getTrades().addListener((ListChangeListener<Trade>) c -> updateBalance());
    openOfferManager.onAllServicesInitialized();
    arbitratorManager.onAllServicesInitialized();
    alertManager.alertMessageProperty().addListener((observable, oldValue, newValue) -> displayAlertIfPresent(newValue));
    privateNotificationManager.privateNotificationProperty().addListener((observable, oldValue, newValue) -> displayPrivateNotification(newValue));
    displayAlertIfPresent(alertManager.alertMessageProperty().get());
    p2PService.onAllServicesInitialized();
    setupBtcNumPeersWatcher();
    setupP2PNumPeersWatcher();
    updateBalance();
    if (DevFlags.DEV_MODE) {
        preferences.setShowOwnOffersInOfferBook(true);
        if (user.getPaymentAccounts().isEmpty())
            setupDevDummyPaymentAccounts();
    }
    setupMarketPriceFeed();
    swapPendingOfferFundingEntries();
    fillPriceFeedComboBoxItems();
    showAppScreen.set(true);
    // We want to test if the client is compiled with the correct crypto provider (BountyCastle) 
    // and if the unlimited Strength for cryptographic keys is set.
    // If users compile themselves they might miss that step and then would get an exception in the trade.
    // To avoid that we add here at startup a sample encryption and signing to see if it don't causes an exception.
    // See: https://github.com/bitsquare/bitsquare/blob/master/doc/build.md#7-enable-unlimited-strength-for-cryptographic-keys
    Thread checkCryptoThread = new Thread() {

        @Override
        public void run() {
            try {
                Thread.currentThread().setName("checkCryptoThread");
                log.trace("Run crypto test");
                // just use any simple dummy msg
                io.bitsquare.p2p.peers.keepalive.messages.Ping payload = new Ping(1, 1);
                SealedAndSigned sealedAndSigned = Encryption.encryptHybridWithSignature(payload, keyRing.getSignatureKeyPair(), keyRing.getPubKeyRing().getEncryptionPubKey());
                DecryptedDataTuple tuple = Encryption.decryptHybridWithSignature(sealedAndSigned, keyRing.getEncryptionKeyPair().getPrivate());
                if (tuple.payload instanceof Ping && ((Ping) tuple.payload).nonce == payload.nonce && ((Ping) tuple.payload).lastRoundTripTime == payload.lastRoundTripTime)
                    log.debug("Crypto test succeeded");
                else
                    throw new CryptoException("Payload not correct after decryption");
            } catch (CryptoException e) {
                e.printStackTrace();
                String msg = "Seems that you use a self compiled binary and have not following the build " + "instructions in https://github.com/bitsquare/bitsquare/blob/master/doc/build.md#7-enable-unlimited-strength-for-cryptographic-keys.\n\n" + "If that is not the case and you use the official Bitsquare binary, " + "please file a bug report to the Github page.\n" + "Error=" + e.getMessage();
                log.error(msg);
                UserThread.execute(() -> new Popup<>().warning(msg).actionButtonText("Shut down").onAction(BitsquareApp.shutDownHandler::run).closeButtonText("Report bug at Github issues").onClose(() -> GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues")).show());
            }
        }
    };
    checkCryptoThread.start();
    if (Security.getProvider("BC") == null) {
        new Popup<>().warning("There is a problem with the crypto libraries. BountyCastle is not available.").actionButtonText("Shut down").onAction(BitsquareApp.shutDownHandler::run).closeButtonText("Report bug at Github issues").onClose(() -> GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues")).show();
    }
    String remindPasswordAndBackupKey = "remindPasswordAndBackup";
    user.getPaymentAccountsAsObservable().addListener((SetChangeListener<PaymentAccount>) change -> {
        if (!walletService.getWallet().isEncrypted() && preferences.showAgain(remindPasswordAndBackupKey) && change.wasAdded()) {
            new Popup<>().headLine("Important security recommendation").information("We would like to remind you to consider using password protection for your wallet if you have not already enabled that.\n\n" + "It is also highly recommended to write down the wallet seed words. Those seed words are like a master password for recovering your Bitcoin wallet.\n" + "At the \"Wallet Seed\" section you find more information.\n\n" + "Additionally you can backup the complete application data folder at the \"Backup\" section.\n" + "Please note, that this backup is not encrypted!").dontShowAgainId(remindPasswordAndBackupKey, preferences).show();
        }
    });
    checkIfOpenOffersMatchTradeProtocolVersion();
}
Also used : Clock(io.bitsquare.common.Clock) OpenOffer(io.bitsquare.trade.offer.OpenOffer) PriceFeedService(io.bitsquare.btc.pricefeed.PriceFeedService) Popup(io.bitsquare.gui.main.overlays.popups.Popup) Transaction(org.bitcoinj.core.Transaction) MarketPrice(io.bitsquare.btc.pricefeed.MarketPrice) Coin(org.bitcoinj.core.Coin) Inject(com.google.inject.Inject) ViewModel(io.bitsquare.gui.common.model.ViewModel) LoggerFactory(org.slf4j.LoggerFactory) TradeCurrency(io.bitsquare.locale.TradeCurrency) Security(java.security.Security) TimeoutException(java.util.concurrent.TimeoutException) DisputeManager(io.bitsquare.arbitration.DisputeManager) BalanceWithConfirmationTextField(io.bitsquare.gui.components.BalanceWithConfirmationTextField) Trade(io.bitsquare.trade.Trade) GUIUtil(io.bitsquare.gui.util.GUIUtil) DevFlags(io.bitsquare.app.DevFlags) PaymentAccount(io.bitsquare.payment.PaymentAccount) NotificationCenter(io.bitsquare.gui.main.overlays.notifications.NotificationCenter) ListChangeListener(javafx.collections.ListChangeListener) Navigation(io.bitsquare.gui.Navigation) TradeWalletService(io.bitsquare.btc.TradeWalletService) BlockStoreException(org.bitcoinj.store.BlockStoreException) MonadicBinding(org.fxmisc.easybind.monadic.MonadicBinding) AddressEntry(io.bitsquare.btc.AddressEntry) WalletPasswordWindow(io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow) FilterManager(io.bitsquare.filter.FilterManager) Subscription(org.fxmisc.easybind.Subscription) Collectors(java.util.stream.Collectors) PrivateNotificationManager(io.bitsquare.alert.PrivateNotificationManager) ConnectionListener(io.bitsquare.p2p.network.ConnectionListener) Preferences(io.bitsquare.user.Preferences) CryptoCurrencyAccount(io.bitsquare.payment.CryptoCurrencyAccount) Dispute(io.bitsquare.arbitration.Dispute) BalanceTextField(io.bitsquare.gui.components.BalanceTextField) Address(org.bitcoinj.core.Address) Ping(io.bitsquare.p2p.peers.keepalive.messages.Ping) ObservableList(javafx.collections.ObservableList) CurrencyUtil(io.bitsquare.locale.CurrencyUtil) io.bitsquare.common.crypto(io.bitsquare.common.crypto) PrivateNotification(io.bitsquare.alert.PrivateNotification) Version(io.bitsquare.app.Version) P2PServiceListener(io.bitsquare.p2p.P2PServiceListener) java.util(java.util) P2PService(io.bitsquare.p2p.P2PService) SetChangeListener(javafx.collections.SetChangeListener) FXCollections(javafx.collections.FXCollections) BitsquareApp(io.bitsquare.app.BitsquareApp) AddBitcoinNodesWindow(io.bitsquare.gui.main.overlays.windows.AddBitcoinNodesWindow) Connection(io.bitsquare.p2p.network.Connection) Timer(io.bitsquare.common.Timer) BalanceListener(io.bitsquare.btc.listeners.BalanceListener) OKPayAccount(io.bitsquare.payment.OKPayAccount) TradeManager(io.bitsquare.trade.TradeManager) User(io.bitsquare.user.User) WalletService(io.bitsquare.btc.WalletService) TacWindow(io.bitsquare.gui.main.overlays.windows.TacWindow) Alert(io.bitsquare.alert.Alert) DisplayAlertMessageWindow(io.bitsquare.gui.main.overlays.windows.DisplayAlertMessageWindow) Nullable(javax.annotation.Nullable) Log(io.bitsquare.app.Log) BSFormatter(io.bitsquare.gui.util.BSFormatter) javafx.beans.property(javafx.beans.property) Logger(org.slf4j.Logger) UserThread(io.bitsquare.common.UserThread) TxIdTextField(io.bitsquare.gui.components.TxIdTextField) Wallet(org.bitcoinj.core.Wallet) TimeUnit(java.util.concurrent.TimeUnit) EasyBind(org.fxmisc.easybind.EasyBind) OpenOfferManager(io.bitsquare.trade.offer.OpenOfferManager) ArbitratorManager(io.bitsquare.arbitration.ArbitratorManager) CloseConnectionReason(io.bitsquare.p2p.network.CloseConnectionReason) ChangeListener(javafx.beans.value.ChangeListener) AlertManager(io.bitsquare.alert.AlertManager) BalanceListener(io.bitsquare.btc.listeners.BalanceListener) PaymentAccount(io.bitsquare.payment.PaymentAccount) OpenOffer(io.bitsquare.trade.offer.OpenOffer) UserThread(io.bitsquare.common.UserThread) BitsquareApp(io.bitsquare.app.BitsquareApp) Trade(io.bitsquare.trade.Trade) Coin(org.bitcoinj.core.Coin) Transaction(org.bitcoinj.core.Transaction) Ping(io.bitsquare.p2p.peers.keepalive.messages.Ping) Popup(io.bitsquare.gui.main.overlays.popups.Popup) Dispute(io.bitsquare.arbitration.Dispute) Ping(io.bitsquare.p2p.peers.keepalive.messages.Ping)

Example 10 with Trade

use of io.bitsquare.trade.Trade in project bitsquare by bitsquare.

the class WithdrawalView method onWithdraw.

///////////////////////////////////////////////////////////////////////////////////////////
// UI handlers
///////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void onWithdraw() {
    if (areInputsValid()) {
        FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {

            @Override
            public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
                if (transaction != null) {
                    log.debug("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
                } else {
                    log.error("onWithdraw transaction is null");
                }
                List<Trade> trades = new ArrayList<>(tradeManager.getTrades());
                trades.stream().filter(trade -> trade.getState().getPhase() == Trade.Phase.PAYOUT_PAID).forEach(trade -> {
                    if (walletService.getBalanceForAddress(walletService.getOrCreateAddressEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT).getAddress()).isZero())
                        tradeManager.addTradeToClosedTrades(trade);
                });
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                log.error("onWithdraw onFailure");
            }
        };
        try {
            // We need to use the max. amount (amountOfSelectedItems) as the senderAmount might be less then
            // we have available and then the fee calculation would return 0
            // TODO Get a proper fee calculation from BitcoinJ directly
            Coin requiredFee = null;
            try {
                requiredFee = walletService.getRequiredFeeForMultipleAddresses(fromAddresses, withdrawToTextField.getText(), amountOfSelectedItems);
            } catch (InsufficientFundsException e) {
                try {
                    int txSize = walletService.getTransactionSize(fromAddresses, withdrawToTextField.getText(), senderAmountAsCoinProperty.get().subtract(FeePolicy.getNonTradeFeePerKb()));
                    new Popup<>().warning(e.getMessage() + "\n" + "Transaction size: " + (txSize / 1000d) + " Kb").show();
                } catch (InsufficientMoneyException e2) {
                    new Popup<>().warning(e.getMessage()).show();
                }
            } catch (Throwable t) {
                try {
                    // TODO Using amountOfSelectedItems caused problems if it exceeds the max size (in case of arbitrator)
                    log.warn("Error at getRequiredFeeForMultipleAddresses: " + t.toString() + "\n" + "We use the default fee instead to estimate tx size and then re-calculate fee.");
                    int tempTxSize = walletService.getTransactionSize(fromAddresses, withdrawToTextField.getText(), senderAmountAsCoinProperty.get().subtract(FeePolicy.getNonTradeFeePerKb()));
                    requiredFee = Coin.valueOf(FeePolicy.getNonTradeFeePerKb().value * tempTxSize / 1000);
                } catch (Throwable t2) {
                    t2.printStackTrace();
                    log.error(t2.toString());
                    new Popup<>().error("Error at creating transaction: " + t2.toString()).show();
                }
            }
            if (requiredFee != null) {
                Coin receiverAmount = senderAmountAsCoinProperty.get().subtract(requiredFee);
                int txSize = walletService.getTransactionSize(fromAddresses, withdrawToTextField.getText(), receiverAmount);
                log.info("Fee for tx with size {}: {} BTC", txSize, requiredFee.toPlainString());
                if (receiverAmount.isPositive()) {
                    if (DevFlags.DEV_MODE) {
                        doWithdraw(receiverAmount, callback);
                    } else {
                        double satPerByte = (double) requiredFee.value / (double) txSize;
                        new Popup().headLine("Confirm withdrawal request").confirmation("Sending: " + formatter.formatCoinWithCode(senderAmountAsCoinProperty.get()) + "\n" + "From address: " + withdrawFromTextField.getText() + "\n" + "To receiving address: " + withdrawToTextField.getText() + ".\n" + "Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + " (" + MathUtils.roundDouble(satPerByte, 2) + " Satoshis/byte)\n" + "Transaction size: " + (txSize / 1000d) + " Kb\n\n" + "The recipient will receive: " + formatter.formatCoinWithCode(receiverAmount) + "\n\n" + "Are you sure you want to withdraw that amount?").actionButtonText("Yes").onAction(() -> doWithdraw(receiverAmount, callback)).closeButtonText("Cancel").show();
                    }
                } else {
                    new Popup().warning("The amount you would like to send is too low as the bitcoin transaction fee will be deducted.\n" + "Please use a higher amount.").show();
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
            log.error(e.toString());
            new Popup().warning(e.getMessage()).show();
        }
    }
}
Also used : MathUtils(io.bitsquare.common.util.MathUtils) BtcAddressValidator(io.bitsquare.gui.util.validation.BtcAddressValidator) Popup(io.bitsquare.gui.main.overlays.popups.Popup) java.util(java.util) javafx.scene.control(javafx.scene.control) FXCollections(javafx.collections.FXCollections) Trade(io.bitsquare.trade.Trade) ActivatableView(io.bitsquare.gui.common.view.ActivatableView) VBox(javafx.scene.layout.VBox) BalanceListener(io.bitsquare.btc.listeners.BalanceListener) Tradable(io.bitsquare.trade.Tradable) StringUtils(org.apache.commons.lang3.StringUtils) GUIUtil(io.bitsquare.gui.util.GUIUtil) Inject(javax.inject.Inject) DevFlags(io.bitsquare.app.DevFlags) TradeManager(io.bitsquare.trade.TradeManager) FailedTradesManager(io.bitsquare.trade.failed.FailedTradesManager) ReadOnlyObjectWrapper(javafx.beans.property.ReadOnlyObjectWrapper) Callback(javafx.util.Callback) KeyParameter(org.spongycastle.crypto.params.KeyParameter) BSFormatter(io.bitsquare.gui.util.BSFormatter) SortedList(javafx.collections.transformation.SortedList) WalletPasswordWindow(io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow) ObjectProperty(javafx.beans.property.ObjectProperty) UserThread(io.bitsquare.common.UserThread) ClosedTradableManager(io.bitsquare.trade.closed.ClosedTradableManager) Collectors(java.util.stream.Collectors) FutureCallback(com.google.common.util.concurrent.FutureCallback) org.bitcoinj.core(org.bitcoinj.core) FXML(javafx.fxml.FXML) TimeUnit(java.util.concurrent.TimeUnit) Preferences(io.bitsquare.user.Preferences) HyperlinkWithIcon(io.bitsquare.gui.components.HyperlinkWithIcon) SimpleObjectProperty(javafx.beans.property.SimpleObjectProperty) io.bitsquare.btc(io.bitsquare.btc) ObservableList(javafx.collections.ObservableList) AwesomeIcon(de.jensd.fx.fontawesome.AwesomeIcon) FxmlView(io.bitsquare.gui.common.view.FxmlView) ChangeListener(javafx.beans.value.ChangeListener) NotNull(org.jetbrains.annotations.NotNull) NotNull(org.jetbrains.annotations.NotNull) Trade(io.bitsquare.trade.Trade) Popup(io.bitsquare.gui.main.overlays.popups.Popup) FutureCallback(com.google.common.util.concurrent.FutureCallback) FXML(javafx.fxml.FXML)

Aggregations

Trade (io.bitsquare.trade.Trade)14 TradeManager (io.bitsquare.trade.TradeManager)7 Popup (io.bitsquare.gui.main.overlays.popups.Popup)6 ObservableList (javafx.collections.ObservableList)6 BSFormatter (io.bitsquare.gui.util.BSFormatter)5 GUIUtil (io.bitsquare.gui.util.GUIUtil)5 Tradable (io.bitsquare.trade.Tradable)5 Preferences (io.bitsquare.user.Preferences)5 ListChangeListener (javafx.collections.ListChangeListener)5 Coin (org.bitcoinj.core.Coin)5 Dispute (io.bitsquare.arbitration.Dispute)4 UserThread (io.bitsquare.common.UserThread)4 FxmlView (io.bitsquare.gui.common.view.FxmlView)4 HyperlinkWithIcon (io.bitsquare.gui.components.HyperlinkWithIcon)4 ReadOnlyObjectWrapper (javafx.beans.property.ReadOnlyObjectWrapper)4 SortedList (javafx.collections.transformation.SortedList)4 javafx.scene.control (javafx.scene.control)4 Callback (javafx.util.Callback)4 Inject (javax.inject.Inject)4 Transaction (org.bitcoinj.core.Transaction)4