Search in sources :

Example 1 with Contract

use of bisq.core.trade.Contract in project bisq-core by bisq-network.

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.getDisputeResult();
    if (!isArbitrator(disputeResult)) {
        final String tradeId = disputeResult.getTradeId();
        Optional<Dispute> disputeOptional = findDispute(tradeId, disputeResult.getTraderId());
        final String uid = disputeResultMessage.getUid();
        if (disputeOptional.isPresent()) {
            cleanupRetryMap(uid);
            Dispute dispute = disputeOptional.get();
            DisputeCommunicationMessage disputeCommunicationMessage = disputeResult.getDisputeCommunicationMessage();
            if (!dispute.getDisputeCommunicationMessages().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)) {
                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 ");
                            byte[] multiSigPubKey = isBuyer ? contract.getBuyerMultiSigPubKey() : contract.getSellerMultiSigPubKey();
                            DeterministicKey multiSigKeyPair = walletService.getMultiSigKeyPair(dispute.getTradeId(), multiSigPubKey);
                            Transaction signedDisputedPayoutTx = tradeWalletService.traderSignAndFinalizeDisputedPayoutTx(dispute.getDepositTxSerialized(), disputeResult.getArbitratorSignature(), disputeResult.getBuyerPayoutAmount(), disputeResult.getSellerPayoutAmount(), contract.getBuyerPayoutAddressString(), contract.getSellerPayoutAddressString(), multiSigKeyPair, contract.getBuyerMultiSigPubKey(), contract.getSellerMultiSigPubKey(), disputeResult.getArbitratorPubKey());
                            Transaction committedDisputedPayoutTx = tradeWalletService.addTxToWallet(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());
                                }
                            }, 15);
                        } catch (AddressFormatException | WalletException | TransactionVerificationException e) {
                            e.printStackTrace();
                            log.error("Error at traderSignAndFinalizeDisputedPayoutTx " + e.getMessage());
                            throw new RuntimeException("Error at traderSignAndFinalizeDisputedPayoutTx " + e.toString());
                        }
                    } 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 : Tradable(bisq.core.trade.Tradable) Trade(bisq.core.trade.Trade) DisputeCommunicationMessage(bisq.core.arbitration.messages.DisputeCommunicationMessage) WalletException(bisq.core.btc.exceptions.WalletException) AddressFormatException(org.bitcoinj.core.AddressFormatException) Optional(java.util.Optional) TransactionVerificationException(bisq.core.btc.exceptions.TransactionVerificationException) Transaction(org.bitcoinj.core.Transaction) Timer(bisq.common.Timer) Contract(bisq.core.trade.Contract) DeterministicKey(org.bitcoinj.crypto.DeterministicKey)

Example 2 with Contract

use of bisq.core.trade.Contract in project bisq-core by bisq-network.

the class DisputeManager method sendPeerOpenedDisputeMessage.

// arbitrator sends that to trading peer when he received openDispute request
private void sendPeerOpenedDisputeMessage(Dispute disputeFromOpener) {
    Contract contractFromOpener = disputeFromOpener.getContract();
    PubKeyRing pubKeyRing = disputeFromOpener.isDisputeOpenerIsBuyer() ? contractFromOpener.getSellerPubKeyRing() : contractFromOpener.getBuyerPubKeyRing();
    Dispute dispute = new Dispute(disputeStorage, disputeFromOpener.getTradeId(), pubKeyRing.hashCode(), !disputeFromOpener.isDisputeOpenerIsBuyer(), !disputeFromOpener.isDisputeOpenerIsMaker(), pubKeyRing, disputeFromOpener.getTradeDate().getTime(), contractFromOpener, disputeFromOpener.getContractHash(), disputeFromOpener.getDepositTxSerialized(), disputeFromOpener.getPayoutTxSerialized(), disputeFromOpener.getDepositTxId(), disputeFromOpener.getPayoutTxId(), disputeFromOpener.getContractAsJson(), disputeFromOpener.getMakerContractSignature(), disputeFromOpener.getTakerContractSignature(), disputeFromOpener.getArbitratorPubKeyRing(), disputeFromOpener.isSupportTicket());
    final Optional<Dispute> storedDisputeOptional = findDispute(dispute.getTradeId(), dispute.getTraderId());
    if (!storedDisputeOptional.isPresent()) {
        String sysMsg = dispute.isSupportTicket() ? Res.get("support.peerOpenedTicket") : Res.get("support.peerOpenedDispute", disputeInfo);
        DisputeCommunicationMessage disputeCommunicationMessage = new DisputeCommunicationMessage(dispute.getTradeId(), keyRing.getPubKeyRing().hashCode(), false, Res.get("support.systemMsg", sysMsg), null, p2PService.getAddress(), new Date().getTime(), false, false, UUID.randomUUID().toString());
        disputeCommunicationMessage.setSystemMessage(true);
        dispute.addDisputeMessage(disputeCommunicationMessage);
        disputes.add(dispute);
        // we mirrored dispute already!
        Contract contract = dispute.getContract();
        PubKeyRing peersPubKeyRing = dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerPubKeyRing() : contract.getSellerPubKeyRing();
        NodeAddress peerNodeAddress = dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerNodeAddress() : contract.getSellerNodeAddress();
        log.trace("sendPeerOpenedDisputeMessage to peerAddress " + peerNodeAddress);
        p2PService.sendEncryptedMailboxMessage(peerNodeAddress, peersPubKeyRing, new PeerOpenedDisputeMessage(dispute, p2PService.getAddress(), UUID.randomUUID().toString()), new SendMailboxMessageListener() {

            @Override
            public void onArrived() {
                log.info("Message arrived at peer. tradeId={}", disputeCommunicationMessage.getTradeId());
                disputeCommunicationMessage.setArrived(true);
            }

            @Override
            public void onStoredInMailbox() {
                log.info("Message stored in mailbox. tradeId={}", disputeCommunicationMessage.getTradeId());
                disputeCommunicationMessage.setStoredInMailbox(true);
            }

            @Override
            public void onFault(String errorMessage) {
                log.error("sendEncryptedMailboxMessage failed. disputeCommunicationMessage=" + disputeCommunicationMessage);
            }
        });
    } else {
        log.warn("We got a dispute already open for that trade and trading peer.\n" + "TradeId = " + dispute.getTradeId());
    }
}
Also used : PubKeyRing(bisq.common.crypto.PubKeyRing) PeerOpenedDisputeMessage(bisq.core.arbitration.messages.PeerOpenedDisputeMessage) NodeAddress(bisq.network.p2p.NodeAddress) SendMailboxMessageListener(bisq.network.p2p.SendMailboxMessageListener) Contract(bisq.core.trade.Contract) DisputeCommunicationMessage(bisq.core.arbitration.messages.DisputeCommunicationMessage) Date(java.util.Date)

Example 3 with Contract

use of bisq.core.trade.Contract in project bisq-core by bisq-network.

the class MakerCreateAndSignContract method run.

@Override
protected void run() {
    try {
        runInterceptHook();
        Preconditions.checkNotNull(trade.getTakerFeeTxId(), "trade.getTakeOfferFeeTxId() must not be null");
        TradingPeer taker = processModel.getTradingPeer();
        PaymentAccountPayload makerPaymentAccountPayload = processModel.getPaymentAccountPayload(trade);
        checkNotNull(makerPaymentAccountPayload, "makerPaymentAccountPayload must not be null");
        PaymentAccountPayload takerPaymentAccountPayload = taker.getPaymentAccountPayload();
        boolean isBuyerMakerAndSellerTaker = trade instanceof BuyerAsMakerTrade;
        NodeAddress buyerNodeAddress = isBuyerMakerAndSellerTaker ? processModel.getMyNodeAddress() : processModel.getTempTradingPeerNodeAddress();
        NodeAddress sellerNodeAddress = isBuyerMakerAndSellerTaker ? processModel.getTempTradingPeerNodeAddress() : processModel.getMyNodeAddress();
        BtcWalletService walletService = processModel.getBtcWalletService();
        String id = processModel.getOffer().getId();
        checkArgument(!walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG).isPresent(), "addressEntry must not be set here.");
        AddressEntry makerAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.MULTI_SIG);
        byte[] makerMultiSigPubKey = makerAddressEntry.getPubKey();
        AddressEntry takerAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.TRADE_PAYOUT);
        checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
        Contract contract = new Contract(processModel.getOffer().getOfferPayload(), trade.getTradeAmount().value, trade.getTradePrice().getValue(), trade.getTakerFeeTxId(), buyerNodeAddress, sellerNodeAddress, trade.getArbitratorNodeAddress(), trade.getMediatorNodeAddress(), isBuyerMakerAndSellerTaker, processModel.getAccountId(), taker.getAccountId(), makerPaymentAccountPayload, takerPaymentAccountPayload, processModel.getPubKeyRing(), taker.getPubKeyRing(), takerAddressEntry.getAddressString(), taker.getPayoutAddressString(), makerMultiSigPubKey, taker.getMultiSigPubKey());
        String contractAsJson = Utilities.objectToJson(contract);
        log.trace("Contract as json:{}", contractAsJson);
        String signature = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), contractAsJson);
        trade.setContract(contract);
        trade.setContractAsJson(contractAsJson);
        trade.setMakerContractSignature(signature);
        processModel.setMyMultiSigPubKey(makerMultiSigPubKey);
        complete();
    } catch (Throwable t) {
        failed(t);
    }
}
Also used : TradingPeer(bisq.core.trade.protocol.TradingPeer) BuyerAsMakerTrade(bisq.core.trade.BuyerAsMakerTrade) BtcWalletService(bisq.core.btc.wallet.BtcWalletService) AddressEntry(bisq.core.btc.AddressEntry) PaymentAccountPayload(bisq.core.payment.payload.PaymentAccountPayload) NodeAddress(bisq.network.p2p.NodeAddress) Contract(bisq.core.trade.Contract)

Example 4 with Contract

use of bisq.core.trade.Contract in project bisq-core by bisq-network.

the class SellerAsTakerSignAndPublishDepositTx method run.

@Override
protected void run() {
    try {
        runInterceptHook();
        log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n");
        byte[] contractHash = Hash.getSha256Hash(trade.getContractAsJson());
        trade.setContractHash(contractHash);
        List<RawTransactionInput> sellerInputs = checkNotNull(processModel.getRawTransactionInputs(), "sellerInputs must not be null");
        BtcWalletService walletService = processModel.getBtcWalletService();
        String id = processModel.getOffer().getId();
        Optional<AddressEntry> addressEntryOptional = walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG);
        checkArgument(addressEntryOptional.isPresent(), "addressEntryOptional must be present");
        AddressEntry sellerMultiSigAddressEntry = addressEntryOptional.get();
        byte[] sellerMultiSigPubKey = processModel.getMyMultiSigPubKey();
        checkArgument(Arrays.equals(sellerMultiSigPubKey, sellerMultiSigAddressEntry.getPubKey()), "sellerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id);
        Coin sellerInput = Coin.valueOf(sellerInputs.stream().mapToLong(input -> input.value).sum());
        sellerMultiSigAddressEntry.setCoinLockedInMultiSig(sellerInput.subtract(trade.getTxFee().multiply(2)));
        walletService.saveAddressEntryList();
        TradingPeer tradingPeer = processModel.getTradingPeer();
        Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(true, contractHash, processModel.getPreparedDepositTx(), tradingPeer.getRawTransactionInputs(), sellerInputs, tradingPeer.getMultiSigPubKey(), sellerMultiSigPubKey, trade.getArbitratorBtcPubKey(), new FutureCallback<Transaction>() {

            @Override
            public void onSuccess(Transaction transaction) {
                if (!completed) {
                    log.trace("takerSignAndPublishTx succeeded " + transaction);
                    trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
                    walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE);
                    complete();
                } else {
                    log.warn("We got the onSuccess callback called after the timeout has been triggered a complete().");
                }
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                if (!completed) {
                    failed(t);
                } else {
                    log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
                }
            }
        });
        // We set the deposit tx in case we get the onFailure called.
        trade.setDepositTx(depositTx);
    } catch (Throwable t) {
        final Contract contract = trade.getContract();
        if (contract != null)
            contract.printDiff(processModel.getTradingPeer().getContractAsJson());
        failed(t);
    }
}
Also used : AddressEntry(bisq.core.btc.AddressEntry) RawTransactionInput(bisq.core.btc.data.RawTransactionInput) Coin(org.bitcoinj.core.Coin) TradingPeer(bisq.core.trade.protocol.TradingPeer) Transaction(org.bitcoinj.core.Transaction) BtcWalletService(bisq.core.btc.wallet.BtcWalletService) Contract(bisq.core.trade.Contract)

Example 5 with Contract

use of bisq.core.trade.Contract in project bisq-desktop by bisq-network.

the class DisputeSummaryWindow method isPayoutAmountValid.

private boolean isPayoutAmountValid() {
    Coin buyerAmount = formatter.parseToCoin(buyerPayoutAmountInputTextField.getText());
    Coin sellerAmount = formatter.parseToCoin(sellerPayoutAmountInputTextField.getText());
    Contract contract = dispute.getContract();
    Coin tradeAmount = contract.getTradeAmount();
    Offer offer = new Offer(contract.getOfferPayload());
    Coin available = tradeAmount.add(offer.getBuyerSecurityDeposit()).add(offer.getSellerSecurityDeposit());
    Coin totalAmount = buyerAmount.add(sellerAmount);
    return (totalAmount.compareTo(available) == 0);
}
Also used : Coin(org.bitcoinj.core.Coin) Offer(bisq.core.offer.Offer) Contract(bisq.core.trade.Contract)

Aggregations

Contract (bisq.core.trade.Contract)17 Offer (bisq.core.offer.Offer)7 Coin (org.bitcoinj.core.Coin)6 PaymentAccountPayload (bisq.core.payment.payload.PaymentAccountPayload)5 NodeAddress (bisq.network.p2p.NodeAddress)5 DisputeCommunicationMessage (bisq.core.arbitration.messages.DisputeCommunicationMessage)4 AddressEntry (bisq.core.btc.AddressEntry)3 BtcWalletService (bisq.core.btc.wallet.BtcWalletService)3 TradingPeer (bisq.core.trade.protocol.TradingPeer)3 SendMailboxMessageListener (bisq.network.p2p.SendMailboxMessageListener)3 Date (java.util.Date)3 Button (javafx.scene.control.Button)3 Tooltip (javafx.scene.control.Tooltip)3 PubKeyRing (bisq.common.crypto.PubKeyRing)2 Trade (bisq.core.trade.Trade)2 TextFieldWithCopyIcon (bisq.desktop.components.TextFieldWithCopyIcon)2 Scene (javafx.scene.Scene)2 TextArea (javafx.scene.control.TextArea)2 TextField (javafx.scene.control.TextField)2 Stage (javafx.stage.Stage)2