mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-09-27 03:50:54 -04:00
Change handling of pending trades, add more logs
This commit is contained in:
parent
ab8c7d47ce
commit
984cdc80ed
21 changed files with 134 additions and 108 deletions
|
@ -31,12 +31,13 @@ import java.util.Arrays;
|
||||||
*/
|
*/
|
||||||
public class AddressEntry implements Serializable {
|
public class AddressEntry implements Serializable {
|
||||||
private static final long serialVersionUID = 5501603992599920416L;
|
private static final long serialVersionUID = 5501603992599920416L;
|
||||||
private transient DeterministicKey keyPair;
|
|
||||||
private final NetworkParameters params;
|
|
||||||
private final AddressContext addressContext;
|
|
||||||
private final String offerId;
|
private final String offerId;
|
||||||
|
private final AddressContext addressContext;
|
||||||
|
private transient DeterministicKey keyPair;
|
||||||
private final byte[] pubKey;
|
private final byte[] pubKey;
|
||||||
private final byte[] pubKeyHash;
|
private final byte[] pubKeyHash;
|
||||||
|
private final NetworkParameters params;
|
||||||
|
|
||||||
public AddressEntry(DeterministicKey keyPair, NetworkParameters params, @SuppressWarnings("SameParameterValue") AddressContext addressContext) {
|
public AddressEntry(DeterministicKey keyPair, NetworkParameters params, @SuppressWarnings("SameParameterValue") AddressContext addressContext) {
|
||||||
this(keyPair, params, addressContext, null);
|
this(keyPair, params, addressContext, null);
|
||||||
|
@ -93,12 +94,12 @@ public class AddressEntry implements Serializable {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "AddressEntry{" +
|
return "AddressEntry{" +
|
||||||
"addressString=" + getAddress().toString() +
|
"offerId='" + offerId +
|
||||||
"key=" + keyPair +
|
|
||||||
", params=" + params +
|
|
||||||
", addressContext=" + addressContext +
|
", addressContext=" + addressContext +
|
||||||
", offerId='" + offerId + '\'' +
|
", keyPair=" + keyPair +
|
||||||
|
", pubKey=" + Arrays.toString(pubKey) +
|
||||||
", pubKeyHash=" + Arrays.toString(pubKeyHash) +
|
", pubKeyHash=" + Arrays.toString(pubKeyHash) +
|
||||||
|
", params=" + params +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,8 @@ public class FeePolicy {
|
||||||
takeOfferFeeAddress = "1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7";
|
takeOfferFeeAddress = "1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7";
|
||||||
break;
|
break;
|
||||||
case REGTEST:
|
case REGTEST:
|
||||||
createOfferFeeAddress = "mmdXHjPSmLCAShckfQ1jwnLYpbP2pKKF7y";
|
createOfferFeeAddress = "mwjWBMW3tcvSDQWooybzumY8RFm4BkKSxZ";
|
||||||
takeOfferFeeAddress = "mmdXHjPSmLCAShckfQ1jwnLYpbP2pKKF7y";
|
takeOfferFeeAddress = "mwjWBMW3tcvSDQWooybzumY8RFm4BkKSxZ";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new BitsquareException("Unknown bitcoin network: %s", bitcoinNetwork);
|
throw new BitsquareException("Unknown bitcoin network: %s", bitcoinNetwork);
|
||||||
|
|
|
@ -142,6 +142,9 @@ public class TradeWalletService {
|
||||||
|
|
||||||
public TransactionDataResult createOffererDepositTxInputs(Coin inputAmount, AddressEntry offererAddressEntry) throws
|
public TransactionDataResult createOffererDepositTxInputs(Coin inputAmount, AddressEntry offererAddressEntry) throws
|
||||||
TransactionVerificationException, WalletException {
|
TransactionVerificationException, WalletException {
|
||||||
|
log.trace("createOffererDepositTxInputs called");
|
||||||
|
log.trace("inputAmount " + inputAmount.toFriendlyString());
|
||||||
|
log.trace("offererAddressEntry " + offererAddressEntry.toString());
|
||||||
|
|
||||||
// We pay the tx fee 2 times to the deposit tx:
|
// We pay the tx fee 2 times to the deposit tx:
|
||||||
// 1. Will be spent when publishing the deposit tx (paid by offerer)
|
// 1. Will be spent when publishing the deposit tx (paid by offerer)
|
||||||
|
@ -205,6 +208,15 @@ public class TradeWalletService {
|
||||||
byte[] takerPubKey,
|
byte[] takerPubKey,
|
||||||
byte[] arbitratorPubKey) throws SigningException,
|
byte[] arbitratorPubKey) throws SigningException,
|
||||||
TransactionVerificationException, WalletException {
|
TransactionVerificationException, WalletException {
|
||||||
|
log.trace("takerCreatesAndSignsDepositTx called");
|
||||||
|
log.trace("takerInputAmount " + takerInputAmount.toFriendlyString());
|
||||||
|
log.trace("msOutputAmount " + msOutputAmount.toFriendlyString());
|
||||||
|
log.trace("offererConnectedOutputsForAllInputs " + offererConnectedOutputsForAllInputs.toString());
|
||||||
|
log.trace("offererOutputs " + offererOutputs.toString());
|
||||||
|
log.trace("takerAddressInfo " + takerAddressInfo.toString());
|
||||||
|
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
|
||||||
|
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
|
||||||
|
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
|
||||||
|
|
||||||
checkArgument(offererConnectedOutputsForAllInputs.size() > 0);
|
checkArgument(offererConnectedOutputsForAllInputs.size() > 0);
|
||||||
|
|
||||||
|
@ -288,6 +300,15 @@ public class TradeWalletService {
|
||||||
byte[] takerPubKey,
|
byte[] takerPubKey,
|
||||||
byte[] arbitratorPubKey,
|
byte[] arbitratorPubKey,
|
||||||
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException, WalletException {
|
FutureCallback<Transaction> callback) throws SigningException, TransactionVerificationException, WalletException {
|
||||||
|
log.trace("offererSignsAndPublishTx called");
|
||||||
|
log.trace("takersDepositTx " + takersDepositTx.toString());
|
||||||
|
log.trace("offererConnectedOutputsForAllInputs " + offererConnectedOutputsForAllInputs.toString());
|
||||||
|
log.trace("takerConnectedOutputsForAllInputs " + takerConnectedOutputsForAllInputs.toString());
|
||||||
|
log.trace("offererOutputs " + offererOutputs.toString());
|
||||||
|
log.trace("offererInputAmount " + offererInputAmount.toFriendlyString());
|
||||||
|
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
|
||||||
|
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
|
||||||
|
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
|
||||||
|
|
||||||
checkArgument(offererConnectedOutputsForAllInputs.size() > 0);
|
checkArgument(offererConnectedOutputsForAllInputs.size() > 0);
|
||||||
checkArgument(takerConnectedOutputsForAllInputs.size() > 0);
|
checkArgument(takerConnectedOutputsForAllInputs.size() > 0);
|
||||||
|
@ -355,6 +376,9 @@ public class TradeWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void takerCommitsDepositTx(Transaction depositTx) throws WalletException {
|
public void takerCommitsDepositTx(Transaction depositTx) throws WalletException {
|
||||||
|
log.trace("takerCommitsDepositTx called");
|
||||||
|
log.trace("depositTx " + depositTx.toString());
|
||||||
|
|
||||||
// We need to recreate the tx we get a null pointer otherwise
|
// We need to recreate the tx we get a null pointer otherwise
|
||||||
depositTx = new Transaction(params, depositTx.bitcoinSerialize());
|
depositTx = new Transaction(params, depositTx.bitcoinSerialize());
|
||||||
|
|
||||||
|
@ -370,22 +394,34 @@ public class TradeWalletService {
|
||||||
public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx,
|
public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx,
|
||||||
Coin offererPayoutAmount,
|
Coin offererPayoutAmount,
|
||||||
Coin takerPayoutAmount,
|
Coin takerPayoutAmount,
|
||||||
String takerAddressString,
|
AddressEntry offererAddressEntry,
|
||||||
AddressEntry addressEntry,
|
String takerPayoutAddressString,
|
||||||
byte[] offererPubKey,
|
byte[] offererPubKey,
|
||||||
byte[] takerPubKey,
|
byte[] takerPubKey,
|
||||||
byte[] arbitratorPubKey)
|
byte[] arbitratorPubKey)
|
||||||
throws AddressFormatException, TransactionVerificationException {
|
throws AddressFormatException, TransactionVerificationException {
|
||||||
|
log.trace("offererCreatesAndSignsPayoutTx called");
|
||||||
|
log.trace("depositTx " + depositTx.toString());
|
||||||
|
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
|
||||||
|
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
|
||||||
|
log.trace("takerPayoutAddressString " + takerPayoutAddressString);
|
||||||
|
log.trace("offererAddressEntry " + offererAddressEntry.toString());
|
||||||
|
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
|
||||||
|
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
|
||||||
|
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
|
||||||
|
|
||||||
Transaction preparedPayoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, addressEntry.getAddressString(), takerAddressString);
|
Transaction preparedPayoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, offererAddressEntry.getAddressString(),
|
||||||
// We need MS script not the P2SH
|
takerPayoutAddressString);
|
||||||
Script multiSigScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
|
// MS redeemScript
|
||||||
Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
|
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
|
||||||
ECKey.ECDSASignature offererSignature = addressEntry.getKeyPair().sign(sigHash).toCanonicalised();
|
Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||||
|
ECKey.ECDSASignature offererSignature = offererAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
|
||||||
|
|
||||||
verifyTransaction(preparedPayoutTx);
|
verifyTransaction(preparedPayoutTx);
|
||||||
|
|
||||||
printTxWithInputs("preparedPayoutTx", depositTx);
|
printTxWithInputs("preparedPayoutTx", preparedPayoutTx);
|
||||||
|
log.trace("offererSignature r " + offererSignature.toCanonicalised().r.toString());
|
||||||
|
log.trace("offererSignature s " + offererSignature.toCanonicalised().s.toString());
|
||||||
return offererSignature.encodeToDER();
|
return offererSignature.encodeToDER();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,16 +436,27 @@ public class TradeWalletService {
|
||||||
byte[] arbitratorPubKey,
|
byte[] arbitratorPubKey,
|
||||||
FutureCallback<Transaction> callback)
|
FutureCallback<Transaction> callback)
|
||||||
throws AddressFormatException, TransactionVerificationException, WalletException {
|
throws AddressFormatException, TransactionVerificationException, WalletException {
|
||||||
|
log.trace("takerSignsAndPublishPayoutTx called");
|
||||||
|
log.trace("depositTx " + depositTx.toString());
|
||||||
|
log.trace("offererSignature r " + ECKey.ECDSASignature.decodeFromDER(offererSignature).toCanonicalised().r.toString());
|
||||||
|
log.trace("offererSignature s " + ECKey.ECDSASignature.decodeFromDER(offererSignature).toCanonicalised().s.toString());
|
||||||
|
log.trace("offererPayoutAmount " + offererPayoutAmount.toFriendlyString());
|
||||||
|
log.trace("takerPayoutAmount " + takerPayoutAmount.toFriendlyString());
|
||||||
|
log.trace("offererAddressString " + offererAddressString);
|
||||||
|
log.trace("takerAddressEntry " + takerAddressEntry);
|
||||||
|
log.trace("offererPubKey " + ECKey.fromPublicOnly(offererPubKey).toString());
|
||||||
|
log.trace("takerPubKey " + ECKey.fromPublicOnly(takerPubKey).toString());
|
||||||
|
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
|
||||||
|
|
||||||
Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, offererAddressString, takerAddressEntry.getAddressString());
|
Transaction payoutTx = createPayoutTx(depositTx, offererPayoutAmount, takerPayoutAmount, offererAddressString, takerAddressEntry.getAddressString());
|
||||||
// We need MS script not the P2SH
|
// MS redeemScript
|
||||||
Script multiSigScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
|
Script redeemScript = getMultiSigRedeemScript(offererPubKey, takerPubKey, arbitratorPubKey);
|
||||||
Sha256Hash sigHash = payoutTx.hashForSignature(0, multiSigScript, Transaction.SigHash.ALL, false);
|
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||||
ECKey.ECDSASignature takerSignature = takerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
|
ECKey.ECDSASignature takerSignature = takerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
|
||||||
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
|
|
||||||
TransactionSignature offererTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(offererSignature).toCanonicalised(),
|
TransactionSignature offererTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(offererSignature).toCanonicalised(),
|
||||||
Transaction.SigHash.ALL, false);
|
Transaction.SigHash.ALL, false);
|
||||||
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(offererTxSig, takerTxSig), multiSigScript);
|
TransactionSignature takerTxSig = new TransactionSignature(takerSignature, Transaction.SigHash.ALL, false);
|
||||||
|
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(offererTxSig, takerTxSig), redeemScript);
|
||||||
TransactionInput input = payoutTx.getInput(0);
|
TransactionInput input = payoutTx.getInput(0);
|
||||||
input.setScriptSig(inputScript);
|
input.setScriptSig(inputScript);
|
||||||
|
|
||||||
|
|
|
@ -299,6 +299,7 @@ public class WalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddressEntry getAddressEntry(String offerId) {
|
public AddressEntry getAddressEntry(String offerId) {
|
||||||
|
log.trace("getAddressEntry called with offerId " + offerId);
|
||||||
Optional<AddressEntry> addressEntry = getAddressEntryList().stream().filter(e ->
|
Optional<AddressEntry> addressEntry = getAddressEntryList().stream().filter(e ->
|
||||||
offerId.equals(e.getOfferId())).findFirst();
|
offerId.equals(e.getOfferId())).findFirst();
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
|
||||||
setDateColumnCellFactory();
|
setDateColumnCellFactory();
|
||||||
|
|
||||||
//TODO just temp for testing
|
//TODO just temp for testing
|
||||||
withdrawAddressTextField.setText("muZkzie5UCaH51P1U9WGWsgejTJQweamai");
|
withdrawAddressTextField.setText("mwjWBMW3tcvSDQWooybzumY8RFm4BkKSxZ");
|
||||||
|
|
||||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
table.setPlaceholder(new Label("No pending trades available"));
|
table.setPlaceholder(new Label("No pending trades available"));
|
||||||
|
|
|
@ -242,7 +242,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
takeOfferRequested = false;
|
takeOfferRequested = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.error("Unhandled trade state: " + newValue);
|
log.warn("Unhandled trade state: " + newValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,21 +269,23 @@ public class Offer implements Serializable {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Offer{" +
|
return "Offer{" +
|
||||||
"direction=" + direction +
|
"id='" + id + '\'' +
|
||||||
|
", state=" + state +
|
||||||
|
", direction=" + direction +
|
||||||
", currency=" + currency +
|
", currency=" + currency +
|
||||||
", uid='" + id + '\'' +
|
", creationDate=" + creationDate +
|
||||||
", fiatPrice=" + fiatPrice +
|
", fiatPrice=" + fiatPrice +
|
||||||
", amount=" + amount +
|
", amount=" + amount +
|
||||||
", minAmount=" + minAmount +
|
", minAmount=" + minAmount +
|
||||||
", messagePubKey=" + messagePublicKey.hashCode() +
|
", messagePublicKey=" + messagePublicKey +
|
||||||
", bankAccountTypeEnum=" + fiatAccountType +
|
", fiatAccountType=" + fiatAccountType +
|
||||||
", bankAccountCountryLocale=" + bankAccountCountry +
|
", bankAccountCountry=" + bankAccountCountry +
|
||||||
", securityDeposit=" + securityDeposit +
|
", securityDeposit=" + securityDeposit +
|
||||||
", acceptedCountryLocales=" + acceptedCountries +
|
", acceptedCountries=" + acceptedCountries +
|
||||||
", acceptedLanguageLocales=" + acceptedLanguageLocales +
|
", acceptedLanguageLocales=" + acceptedLanguageLocales +
|
||||||
", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' +
|
|
||||||
", bankAccountUID='" + bankAccountUID + '\'' +
|
", bankAccountUID='" + bankAccountUID + '\'' +
|
||||||
", arbitrator=" + arbitrators +
|
", arbitrators=" + arbitrators +
|
||||||
|
", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class Trade implements Serializable {
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
date = new Date();
|
date = new Date();
|
||||||
|
|
||||||
state = State.OPEN;
|
setState(State.OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,11 @@ public class TradeManager {
|
||||||
createBuyerAcceptsOfferProtocol(entry.getValue());
|
createBuyerAcceptsOfferProtocol(entry.getValue());
|
||||||
}
|
}
|
||||||
for (Map.Entry<String, Trade> entry : pendingTrades.entrySet()) {
|
for (Map.Entry<String, Trade> entry : pendingTrades.entrySet()) {
|
||||||
createBuyerAcceptsOfferProtocol(entry.getValue().getOffer());
|
Trade trade = entry.getValue();
|
||||||
|
if (trade.getState() == Trade.State.FAULT)
|
||||||
|
closeTrade(trade);
|
||||||
|
|
||||||
|
createBuyerAcceptsOfferProtocol(trade.getOffer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,10 +240,10 @@ public class TradeManager {
|
||||||
break;
|
break;
|
||||||
case MESSAGE_SENDING_FAILED:
|
case MESSAGE_SENDING_FAILED:
|
||||||
case FAULT:
|
case FAULT:
|
||||||
removeFailedTrade(trade);
|
closeTrade(trade);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.error("Unhandled trade state: " + newValue);
|
log.warn("Unhandled trade state: " + newValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -273,9 +277,25 @@ public class TradeManager {
|
||||||
sellerAsTakerProtocolMap.get(tradeId).onFiatPaymentReceived();
|
sellerAsTakerProtocolMap.get(tradeId).onFiatPaymentReceived();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void closeTrade(Trade trade) {
|
public void closeTrade(Trade trade) {
|
||||||
closeTrade(trade, false);
|
if (pendingTrades.containsKey(trade.getId())) {
|
||||||
|
pendingTrades.remove(trade.getId());
|
||||||
|
persistPendingTrades();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sellerAsTakerProtocolMap.containsKey(trade.getId())) {
|
||||||
|
sellerAsTakerProtocolMap.get(trade.getId()).cleanup();
|
||||||
|
sellerAsTakerProtocolMap.remove(trade.getId());
|
||||||
|
}
|
||||||
|
else if (buyerAcceptsOfferProtocolMap.containsKey(trade.getId())) {
|
||||||
|
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
|
||||||
|
buyerAcceptsOfferProtocolMap.remove(trade.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!closedTrades.containsKey(trade.getId())) {
|
||||||
|
closedTrades.put(trade.getId(), trade);
|
||||||
|
persistClosedTrades();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -360,17 +380,14 @@ public class TradeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createBuyerAcceptsOfferProtocol(Offer offer) {
|
private void createBuyerAcceptsOfferProtocol(Offer offer) {
|
||||||
|
|
||||||
|
|
||||||
Trade trade;
|
Trade trade;
|
||||||
if (pendingTrades.containsKey(offer.getId())) {
|
if (pendingTrades.containsKey(offer.getId())) {
|
||||||
trade = pendingTrades.get(offer.getId());
|
trade = pendingTrades.get(offer.getId());
|
||||||
|
currentPendingTrade = trade;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
trade = new Trade(offer);
|
trade = new Trade(offer);
|
||||||
pendingTrades.put(trade.getId(), trade);
|
// don't save it in pendingTrades. It is only a potential trade
|
||||||
persistPendingTrades();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BuyerAsOffererModel model = new BuyerAsOffererModel(
|
BuyerAsOffererModel model = new BuyerAsOffererModel(
|
||||||
|
@ -381,7 +398,7 @@ public class TradeManager {
|
||||||
signatureService,
|
signatureService,
|
||||||
user,
|
user,
|
||||||
persistence);
|
persistence);
|
||||||
currentPendingTrade = trade;
|
|
||||||
|
|
||||||
// TODO check, remove listener
|
// TODO check, remove listener
|
||||||
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
|
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
|
||||||
|
@ -397,6 +414,11 @@ public class TradeManager {
|
||||||
() -> log.debug("remove offer was successful"),
|
() -> log.debug("remove offer was successful"),
|
||||||
(message) -> log.error(message),
|
(message) -> log.error(message),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
// after we have published the deposit tx we add that trade to the pendingTrades
|
||||||
|
if (pendingTrades.containsKey(trade.getId()))
|
||||||
|
log.error("That must never happen: Trades contains already an trade with the ID " + trade.getId());
|
||||||
|
pendingTrades.put(trade.getId(), trade);
|
||||||
persistPendingTrades();
|
persistPendingTrades();
|
||||||
break;
|
break;
|
||||||
case DEPOSIT_CONFIRMED:
|
case DEPOSIT_CONFIRMED:
|
||||||
|
@ -408,11 +430,11 @@ public class TradeManager {
|
||||||
case TAKE_OFFER_FEE_PUBLISH_FAILED:
|
case TAKE_OFFER_FEE_PUBLISH_FAILED:
|
||||||
case MESSAGE_SENDING_FAILED:
|
case MESSAGE_SENDING_FAILED:
|
||||||
case FAULT:
|
case FAULT:
|
||||||
removeFailedTrade(trade);
|
closeTrade(trade);
|
||||||
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
|
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.error("Unhandled trade state: " + newValue);
|
log.warn("Unhandled trade state: " + newValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -421,36 +443,6 @@ public class TradeManager {
|
||||||
buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol);
|
buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFailedTrade(Trade trade) {
|
|
||||||
closeTrade(trade, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeTrade(Trade trade, boolean failed) {
|
|
||||||
if (pendingTrades.containsKey(trade.getId())) {
|
|
||||||
pendingTrades.remove(trade.getId());
|
|
||||||
persistPendingTrades();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sellerAsTakerProtocolMap.containsKey(trade.getId())) {
|
|
||||||
sellerAsTakerProtocolMap.get(trade.getId()).cleanup();
|
|
||||||
sellerAsTakerProtocolMap.remove(trade.getId());
|
|
||||||
}
|
|
||||||
else if (buyerAcceptsOfferProtocolMap.containsKey(trade.getId())) {
|
|
||||||
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
|
|
||||||
buyerAcceptsOfferProtocolMap.remove(trade.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!failed) {
|
|
||||||
if (!closedTrades.containsKey(trade.getId())) {
|
|
||||||
closedTrades.put(trade.getId(), trade);
|
|
||||||
persistClosedTrades();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*else {
|
|
||||||
// TODO add failed trades to history
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
|
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
|
||||||
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
||||||
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
|
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
|
||||||
|
|
|
@ -18,27 +18,23 @@
|
||||||
package io.bitsquare.trade.protocol.trade.messages;
|
package io.bitsquare.trade.protocol.trade.messages;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.Transaction;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class BankTransferStartedMessage extends TradeMessage implements Serializable {
|
public class BankTransferStartedMessage extends TradeMessage implements Serializable {
|
||||||
private static final long serialVersionUID = -3479634129543632523L;
|
private static final long serialVersionUID = -3479634129543632523L;
|
||||||
|
|
||||||
public final Transaction depositTx;
|
|
||||||
public final byte[] offererSignature;
|
public final byte[] offererSignature;
|
||||||
public final Coin offererPayoutAmount;
|
public final Coin offererPayoutAmount;
|
||||||
public final Coin takerPayoutAmount;
|
public final Coin takerPayoutAmount;
|
||||||
public final String offererPayoutAddress;
|
public final String offererPayoutAddress;
|
||||||
|
|
||||||
public BankTransferStartedMessage(String tradeId,
|
public BankTransferStartedMessage(String tradeId,
|
||||||
Transaction depositTx,
|
|
||||||
byte[] offererSignature,
|
byte[] offererSignature,
|
||||||
Coin offererPayoutAmount,
|
Coin offererPayoutAmount,
|
||||||
Coin takerPayoutAmount,
|
Coin takerPayoutAmount,
|
||||||
String offererPayoutAddress) {
|
String offererPayoutAddress) {
|
||||||
this.tradeId = tradeId;
|
this.tradeId = tradeId;
|
||||||
this.depositTx = depositTx;
|
|
||||||
this.offererSignature = offererSignature;
|
this.offererSignature = offererSignature;
|
||||||
this.offererPayoutAmount = offererPayoutAmount;
|
this.offererPayoutAmount = offererPayoutAmount;
|
||||||
this.takerPayoutAmount = takerPayoutAmount;
|
this.takerPayoutAmount = takerPayoutAmount;
|
||||||
|
|
|
@ -43,6 +43,6 @@ public class TakerModel implements Serializable {
|
||||||
public Coin payoutAmount;
|
public Coin payoutAmount;
|
||||||
public Transaction depositTx;
|
public Transaction depositTx;
|
||||||
public List<TransactionOutput> connectedOutputsForAllInputs;
|
public List<TransactionOutput> connectedOutputsForAllInputs;
|
||||||
public String payoutAddress;
|
public String payoutAddressString;
|
||||||
public byte[] pubKey;
|
public byte[] pubKey;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOf
|
||||||
model.taker.messagePublicKey = checkNotNull(message.takerMessagePublicKey);
|
model.taker.messagePublicKey = checkNotNull(message.takerMessagePublicKey);
|
||||||
model.taker.contractAsJson = nonEmptyStringOf(message.takerContractAsJson);
|
model.taker.contractAsJson = nonEmptyStringOf(message.takerContractAsJson);
|
||||||
model.taker.contractSignature = nonEmptyStringOf(message.takerContractSignature);
|
model.taker.contractSignature = nonEmptyStringOf(message.takerContractSignature);
|
||||||
model.taker.payoutAddress = nonEmptyStringOf(message.takerPayoutAddress);
|
model.taker.payoutAddressString = nonEmptyStringOf(message.takerPayoutAddress);
|
||||||
model.taker.depositTx = checkNotNull(message.takersDepositTx);
|
model.taker.depositTx = checkNotNull(message.takersDepositTx);
|
||||||
model.taker.connectedOutputsForAllInputs = checkNotNull(message.takerConnectedOutputsForAllInputs);
|
model.taker.connectedOutputsForAllInputs = checkNotNull(message.takerConnectedOutputsForAllInputs);
|
||||||
checkArgument(message.takerConnectedOutputsForAllInputs.size() > 0);
|
checkArgument(message.takerConnectedOutputsForAllInputs.size() > 0);
|
||||||
|
|
|
@ -37,7 +37,6 @@ public class SendBankTransferStartedMessage extends Task<BuyerAsOffererModel> {
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
BankTransferStartedMessage tradeMessage = new BankTransferStartedMessage(
|
BankTransferStartedMessage tradeMessage = new BankTransferStartedMessage(
|
||||||
model.id,
|
model.id,
|
||||||
model.getPublishedDepositTx(),
|
|
||||||
model.offerer.payoutTxSignature,
|
model.offerer.payoutTxSignature,
|
||||||
model.offerer.payoutAmount,
|
model.offerer.payoutAmount,
|
||||||
model.taker.payoutAmount,
|
model.taker.payoutAmount,
|
||||||
|
|
|
@ -46,8 +46,8 @@ public class SignPayoutTx extends Task<BuyerAsOffererModel> {
|
||||||
trade.getDepositTx(),
|
trade.getDepositTx(),
|
||||||
offererPayoutAmount,
|
offererPayoutAmount,
|
||||||
takerPayoutAmount,
|
takerPayoutAmount,
|
||||||
model.taker.payoutAddress,
|
model.offerer.addressEntry,
|
||||||
model.walletService.getAddressEntry(trade.getId()),
|
model.taker.payoutAddressString,
|
||||||
model.offerer.pubKey,
|
model.offerer.pubKey,
|
||||||
model.taker.pubKey,
|
model.taker.pubKey,
|
||||||
model.arbitratorPubKey);
|
model.arbitratorPubKey);
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class OffererModel implements Serializable {
|
||||||
// written by tasks
|
// written by tasks
|
||||||
public byte[] pubKey;
|
public byte[] pubKey;
|
||||||
public Coin payoutAmount;
|
public Coin payoutAmount;
|
||||||
public String payoutAddress;
|
public String payoutAddressString;
|
||||||
public List<TransactionOutput> connectedOutputsForAllInputs;
|
public List<TransactionOutput> connectedOutputsForAllInputs;
|
||||||
public List<TransactionOutput> outputs;
|
public List<TransactionOutput> outputs;
|
||||||
public byte[] signature;
|
public byte[] signature;
|
||||||
|
|
|
@ -43,7 +43,6 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||||
public final OffererModel offerer;
|
public final OffererModel offerer;
|
||||||
|
|
||||||
// written by tasks
|
// written by tasks
|
||||||
private Transaction publishedDepositTx;
|
|
||||||
private Transaction takeOfferFeeTx;
|
private Transaction takeOfferFeeTx;
|
||||||
private Transaction payoutTx;
|
private Transaction payoutTx;
|
||||||
|
|
||||||
|
@ -69,7 +68,6 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||||
SellerAsTakerModel persistedModel = (SellerAsTakerModel) serializable;
|
SellerAsTakerModel persistedModel = (SellerAsTakerModel) serializable;
|
||||||
log.debug("Model reconstructed form persisted model.");
|
log.debug("Model reconstructed form persisted model.");
|
||||||
|
|
||||||
setPublishedDepositTx(persistedModel.getPublishedDepositTx());
|
|
||||||
setTakeOfferFeeTx(persistedModel.getTakeOfferFeeTx());
|
setTakeOfferFeeTx(persistedModel.getTakeOfferFeeTx());
|
||||||
setPayoutTx(persistedModel.payoutTx);
|
setPayoutTx(persistedModel.payoutTx);
|
||||||
|
|
||||||
|
@ -98,14 +96,6 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||||
persistence.write(this, "SellerAsTakerModel_" + id, this);
|
persistence.write(this, "SellerAsTakerModel_" + id, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transaction getPublishedDepositTx() {
|
|
||||||
return publishedDepositTx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublishedDepositTx(Transaction publishedDepositTx) {
|
|
||||||
this.publishedDepositTx = publishedDepositTx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Transaction getTakeOfferFeeTx() {
|
public Transaction getTakeOfferFeeTx() {
|
||||||
return takeOfferFeeTx;
|
return takeOfferFeeTx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,11 +41,10 @@ public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel>
|
||||||
checkTradeId(model.id, model.getTradeMessage());
|
checkTradeId(model.id, model.getTradeMessage());
|
||||||
BankTransferStartedMessage message = (BankTransferStartedMessage) model.getTradeMessage();
|
BankTransferStartedMessage message = (BankTransferStartedMessage) model.getTradeMessage();
|
||||||
|
|
||||||
model.setPublishedDepositTx(checkNotNull(message.depositTx));
|
|
||||||
model.offerer.signature = checkNotNull(message.offererSignature);
|
model.offerer.signature = checkNotNull(message.offererSignature);
|
||||||
model.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount));
|
model.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount));
|
||||||
model.taker.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount));
|
model.taker.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount));
|
||||||
model.offerer.payoutAddress = nonEmptyStringOf(message.offererPayoutAddress);
|
model.offerer.payoutAddressString = nonEmptyStringOf(message.offererPayoutAddress);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.Task;
|
import io.bitsquare.common.taskrunner.Task;
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
||||||
|
|
||||||
|
@ -41,8 +42,9 @@ public class ProcessDepositTxPublishedMessage extends Task<SellerAsTakerModel> {
|
||||||
checkTradeId(model.id, model.getTradeMessage());
|
checkTradeId(model.id, model.getTradeMessage());
|
||||||
|
|
||||||
DepositTxPublishedMessage message = (DepositTxPublishedMessage) model.getTradeMessage();
|
DepositTxPublishedMessage message = (DepositTxPublishedMessage) model.getTradeMessage();
|
||||||
model.setPublishedDepositTx(checkNotNull(message.depositTx));
|
model.trade.setDepositTx(checkNotNull(message.depositTx));
|
||||||
|
model.trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
failed(t);
|
failed(t);
|
||||||
|
|
|
@ -42,11 +42,11 @@ public class SignAndPublishPayoutTx extends Task<SellerAsTakerModel> {
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
model.tradeWalletService.takerSignsAndPublishPayoutTx(
|
model.tradeWalletService.takerSignsAndPublishPayoutTx(
|
||||||
model.getPublishedDepositTx(),
|
model.trade.getDepositTx(),
|
||||||
model.offerer.signature,
|
model.offerer.signature,
|
||||||
model.offerer.payoutAmount,
|
model.offerer.payoutAmount,
|
||||||
model.taker.payoutAmount,
|
model.taker.payoutAmount,
|
||||||
model.offerer.payoutAddress,
|
model.offerer.payoutAddressString,
|
||||||
model.taker.addressEntry,
|
model.taker.addressEntry,
|
||||||
model.offerer.pubKey,
|
model.offerer.pubKey,
|
||||||
model.taker.pubKey,
|
model.taker.pubKey,
|
||||||
|
|
|
@ -19,7 +19,6 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.Task;
|
import io.bitsquare.common.taskrunner.Task;
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
import io.bitsquare.trade.Trade;
|
|
||||||
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -35,9 +34,7 @@ public class TakerCommitDepositTx extends Task<SellerAsTakerModel> {
|
||||||
@Override
|
@Override
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
model.tradeWalletService.takerCommitsDepositTx(model.getPublishedDepositTx());
|
model.tradeWalletService.takerCommitsDepositTx(model.trade.getDepositTx());
|
||||||
model.trade.setDepositTx(model.getPublishedDepositTx());
|
|
||||||
model.trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ createOffer.fundsBox.showAdvanced=Show advanced settings
|
||||||
createOffer.fundsBox.hideAdvanced=Hide advanced settings
|
createOffer.fundsBox.hideAdvanced=Hide advanced settings
|
||||||
createOffer.fundsBox.placeOffer=Place offer
|
createOffer.fundsBox.placeOffer=Place offer
|
||||||
createOffer.fundsBox.placeOfferSpinnerInfo=Offer fee payment is in progress...
|
createOffer.fundsBox.placeOfferSpinnerInfo=Offer fee payment is in progress...
|
||||||
createOffer.fundsBox.paymentLabel=Bitsquare trade ({0})
|
createOffer.fundsBox.paymentLabel=Bitsquare trade with ID {0}
|
||||||
|
|
||||||
createOffer.advancedBox.title=Advanced settings
|
createOffer.advancedBox.title=Advanced settings
|
||||||
createOffer.advancedBox.countries=Accepted countries:
|
createOffer.advancedBox.countries=Accepted countries:
|
||||||
|
@ -111,7 +111,7 @@ takeOffer.fundsBox.showAdvanced=Show advanced settings
|
||||||
takeOffer.fundsBox.hideAdvanced=Hide advanced settings
|
takeOffer.fundsBox.hideAdvanced=Hide advanced settings
|
||||||
takeOffer.fundsBox.takeOffer=Take offer
|
takeOffer.fundsBox.takeOffer=Take offer
|
||||||
takeOffer.fundsBox.takeOfferSpinnerInfo=Take offer in progress...
|
takeOffer.fundsBox.takeOfferSpinnerInfo=Take offer in progress...
|
||||||
takeOffer.fundsBox.paymentLabel=Bitsquare trade ({0})
|
takeOffer.fundsBox.paymentLabel=Bitsquare trade with ID {0}
|
||||||
|
|
||||||
takeOffer.advancedBox.title=Advanced settings
|
takeOffer.advancedBox.title=Advanced settings
|
||||||
takeOffer.advancedBox.countries=Accepted countries:
|
takeOffer.advancedBox.countries=Accepted countries:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue