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);
});
}
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.");
}
}
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());
}
// }
}
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();
}
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();
}
}
}
Aggregations