mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 01:41:11 +01:00
Add locktime to payout tx
This commit is contained in:
parent
f24ebb9038
commit
08dde43ffc
@ -17,6 +17,7 @@
|
||||
|
||||
package io.bitsquare.app.bootstrap;
|
||||
|
||||
import io.bitsquare.p2p.BootstrapNodes;
|
||||
import io.bitsquare.p2p.Node;
|
||||
|
||||
import net.tomp2p.connection.ChannelClientConfiguration;
|
||||
@ -52,7 +53,7 @@ public class BootstrapNode {
|
||||
|
||||
public void start() {
|
||||
String name = env.getRequiredProperty(Node.NAME_KEY);
|
||||
int port = env.getProperty(Node.PORT_KEY, Integer.class, Node.DEFAULT_PORT);
|
||||
int port = env.getProperty(Node.PORT_KEY, Integer.class, BootstrapNodes.DEFAULT_PORT);
|
||||
try {
|
||||
Number160 peerId = Number160.createHash(name);
|
||||
|
||||
|
@ -19,6 +19,7 @@ package io.bitsquare.app.bootstrap;
|
||||
|
||||
import io.bitsquare.app.BitsquareEnvironment;
|
||||
import io.bitsquare.app.BitsquareExecutable;
|
||||
import io.bitsquare.p2p.BootstrapNodes;
|
||||
import io.bitsquare.p2p.Node;
|
||||
|
||||
import joptsimple.OptionParser;
|
||||
@ -34,7 +35,7 @@ public class BootstrapNodeMain extends BitsquareExecutable {
|
||||
parser.accepts(Node.NAME_KEY, description("Name of this node", null))
|
||||
.withRequiredArg()
|
||||
.isRequired();
|
||||
parser.accepts(Node.PORT_KEY, description("Port to listen on", Node.DEFAULT_PORT))
|
||||
parser.accepts(Node.PORT_KEY, description("Port to listen on", BootstrapNodes.DEFAULT_PORT))
|
||||
.withRequiredArg()
|
||||
.ofType(int.class);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.*;
|
||||
@ -69,73 +70,80 @@ public class BitsquareApp extends Application {
|
||||
this.primaryStage = primaryStage;
|
||||
|
||||
log.trace("BitsquareApp.start");
|
||||
try {
|
||||
bitsquareAppModule = new BitsquareAppModule(env, primaryStage);
|
||||
injector = Guice.createInjector(bitsquareAppModule);
|
||||
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
|
||||
|
||||
bitsquareAppModule = new BitsquareAppModule(env, primaryStage);
|
||||
injector = Guice.createInjector(bitsquareAppModule);
|
||||
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
|
||||
|
||||
// route uncaught exceptions to a user-facing dialog
|
||||
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) ->
|
||||
Popups.handleUncaughtExceptions(Throwables.getRootCause(throwable)));
|
||||
// route uncaught exceptions to a user-facing dialog
|
||||
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) ->
|
||||
Popups.handleUncaughtExceptions(Throwables.getRootCause(throwable)));
|
||||
|
||||
|
||||
// load the main view and create the main scene
|
||||
log.trace("viewLoader.load(MainView.class)");
|
||||
CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class);
|
||||
View view = viewLoader.load(MainView.class);
|
||||
// load the main view and create the main scene
|
||||
log.trace("viewLoader.load(MainView.class)");
|
||||
CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class);
|
||||
View view = viewLoader.load(MainView.class);
|
||||
|
||||
scene = new Scene((Parent) view.getRoot(), 1000, 620);
|
||||
scene.getStylesheets().setAll(
|
||||
"/io/bitsquare/gui/bitsquare.css",
|
||||
"/io/bitsquare/gui/images.css");
|
||||
scene = new Scene((Parent) view.getRoot(), 1000, 620);
|
||||
scene.getStylesheets().setAll(
|
||||
"/io/bitsquare/gui/bitsquare.css",
|
||||
"/io/bitsquare/gui/images.css");
|
||||
|
||||
|
||||
// configure the system tray
|
||||
// configure the system tray
|
||||
|
||||
SystemTray.create(primaryStage, this::stop);
|
||||
primaryStage.setOnCloseRequest(e -> {
|
||||
e.consume();
|
||||
stop();
|
||||
});
|
||||
scene.setOnKeyReleased(keyEvent -> {
|
||||
// For now we exit when closing/quit the app.
|
||||
// Later we will only hide the window (systemTray.hideStage()) and use the exit item in the system tray for
|
||||
// shut down.
|
||||
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent) ||
|
||||
new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
|
||||
SystemTray.create(primaryStage, this::stop);
|
||||
primaryStage.setOnCloseRequest(e -> {
|
||||
e.consume();
|
||||
stop();
|
||||
else if (new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
|
||||
showDebugWindow();
|
||||
});
|
||||
});
|
||||
scene.setOnKeyReleased(keyEvent -> {
|
||||
// For now we exit when closing/quit the app.
|
||||
// Later we will only hide the window (systemTray.hideStage()) and use the exit item in the system tray for
|
||||
// shut down.
|
||||
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent) ||
|
||||
new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
|
||||
stop();
|
||||
else if (new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
|
||||
showDebugWindow();
|
||||
});
|
||||
|
||||
|
||||
// configure the primary stage
|
||||
// configure the primary stage
|
||||
|
||||
primaryStage.setTitle(env.getRequiredProperty(APP_NAME_KEY));
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinWidth(750);
|
||||
primaryStage.setMinHeight(620);
|
||||
primaryStage.setTitle(env.getRequiredProperty(APP_NAME_KEY));
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinWidth(750);
|
||||
primaryStage.setMinHeight(620);
|
||||
|
||||
// on windows the title icon is also used as task bar icon in a larger size
|
||||
// on Linux no title icon is supported but also a large task bar icon is derived form that title icon
|
||||
String iconPath;
|
||||
if (Utilities.isOSX())
|
||||
iconPath = ImageUtil.isRetina() ? "/images/window_icon@2x.png" : "/images/window_icon.png";
|
||||
else if (Utilities.isWindows())
|
||||
iconPath = "/images/task_bar_icon_windows.png";
|
||||
else
|
||||
iconPath = "/images/task_bar_icon_linux.png";
|
||||
// on windows the title icon is also used as task bar icon in a larger size
|
||||
// on Linux no title icon is supported but also a large task bar icon is derived form that title icon
|
||||
String iconPath;
|
||||
if (Utilities.isOSX())
|
||||
iconPath = ImageUtil.isRetina() ? "/images/window_icon@2x.png" : "/images/window_icon.png";
|
||||
else if (Utilities.isWindows())
|
||||
iconPath = "/images/task_bar_icon_windows.png";
|
||||
else
|
||||
iconPath = "/images/task_bar_icon_linux.png";
|
||||
|
||||
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream(iconPath)));
|
||||
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream(iconPath)));
|
||||
|
||||
|
||||
// make the UI visible
|
||||
// make the UI visible
|
||||
|
||||
log.trace("primaryStage.show");
|
||||
primaryStage.show();
|
||||
log.trace("primaryStage.show");
|
||||
primaryStage.show();
|
||||
|
||||
//TODO just temp.
|
||||
//showDebugWindow();
|
||||
//TODO just temp.
|
||||
//showDebugWindow();
|
||||
} catch (Throwable t) {
|
||||
if (t instanceof InvalidObjectException) {
|
||||
Popups.openErrorPopup("There is a problem with different version of persisted objects. " +
|
||||
"Please delete the db directory inside the app directory.");
|
||||
}
|
||||
log.error(t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void showDebugWindow() {
|
||||
|
@ -23,11 +23,13 @@ import io.bitsquare.btc.exceptions.WalletException;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.BlockChainListener;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.StoredBlock;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionInput;
|
||||
import org.bitcoinj.core.TransactionOutPoint;
|
||||
@ -118,11 +120,6 @@ public class TradeWalletService {
|
||||
return createOfferFeeTx;
|
||||
}
|
||||
|
||||
public void broadcastCreateOfferFeeTx(Transaction createOfferFeeTx, FutureCallback<Transaction> callback) {
|
||||
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(createOfferFeeTx).future();
|
||||
Futures.addCallback(future, callback);
|
||||
}
|
||||
|
||||
public Transaction createTakeOfferFeeTx(AddressEntry sellerAddressEntry) throws InsufficientMoneyException {
|
||||
Transaction takeOfferFeeTx = new Transaction(params);
|
||||
Coin fee = FeePolicy.TAKE_OFFER_FEE.subtract(FeePolicy.TX_FEE);
|
||||
@ -139,8 +136,8 @@ public class TradeWalletService {
|
||||
return takeOfferFeeTx;
|
||||
}
|
||||
|
||||
public void broadcastTakeOfferFeeTx(Transaction takeOfferFeeTx, FutureCallback<Transaction> callback) {
|
||||
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(takeOfferFeeTx).future();
|
||||
public void broadcastTx(Transaction tx, FutureCallback<Transaction> callback) {
|
||||
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(tx).future();
|
||||
Futures.addCallback(future, callback);
|
||||
}
|
||||
|
||||
@ -419,6 +416,7 @@ public class TradeWalletService {
|
||||
Coin sellerPayoutAmount,
|
||||
AddressEntry buyerAddressEntry,
|
||||
String sellerPayoutAddressString,
|
||||
long lockTimeDelta,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey)
|
||||
@ -438,6 +436,8 @@ public class TradeWalletService {
|
||||
sellerPayoutAmount,
|
||||
buyerAddressEntry.getAddressString(),
|
||||
sellerPayoutAddressString);
|
||||
preparedPayoutTx.setLockTime(wallet.getLastBlockSeenHeight() + lockTimeDelta);
|
||||
preparedPayoutTx.getInputs().stream().forEach(i -> i.setSequenceNumber(0));
|
||||
// MS redeemScript
|
||||
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||
@ -454,16 +454,16 @@ public class TradeWalletService {
|
||||
return buyerSignature.encodeToDER();
|
||||
}
|
||||
|
||||
public void signAndPublishPayoutTx(Transaction depositTx,
|
||||
byte[] buyerSignature,
|
||||
Coin buyerPayoutAmount,
|
||||
Coin sellerPayoutAmount,
|
||||
String buyerAddressString,
|
||||
AddressEntry sellerAddressEntry,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey,
|
||||
FutureCallback<Transaction> callback)
|
||||
public Transaction signAndFinalizePayoutTx(Transaction depositTx,
|
||||
byte[] buyerSignature,
|
||||
Coin buyerPayoutAmount,
|
||||
Coin sellerPayoutAmount,
|
||||
String buyerAddressString,
|
||||
AddressEntry sellerAddressEntry,
|
||||
long lockTimeDelta,
|
||||
byte[] buyerPubKey,
|
||||
byte[] sellerPubKey,
|
||||
byte[] arbitratorPubKey)
|
||||
throws AddressFormatException, TransactionVerificationException, WalletException, SigningException {
|
||||
log.trace("signAndPublishPayoutTx called");
|
||||
log.trace("depositTx " + depositTx.toString());
|
||||
@ -482,6 +482,8 @@ public class TradeWalletService {
|
||||
sellerPayoutAmount,
|
||||
buyerAddressString,
|
||||
sellerAddressEntry.getAddressString());
|
||||
payoutTx.setLockTime(wallet.getLastBlockSeenHeight() + lockTimeDelta);
|
||||
payoutTx.getInputs().stream().forEach(i -> i.setSequenceNumber(0));
|
||||
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||
ECKey.ECDSASignature sellerSignature = sellerAddressEntry.getKeyPair().sign(sigHash).toCanonicalised();
|
||||
@ -508,8 +510,25 @@ public class TradeWalletService {
|
||||
|
||||
printTxWithInputs("payoutTx", payoutTx);
|
||||
|
||||
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(payoutTx).future();
|
||||
Futures.addCallback(broadcastComplete, callback);
|
||||
// As we use lockTime the tx will not be relayed as it is not considered standard.
|
||||
// We need to broadcast on our own when we reahced the block height. Both peers will do the broadcast.
|
||||
return payoutTx;
|
||||
}
|
||||
|
||||
public ListenableFuture<StoredBlock> getBlockHeightFuture(Transaction transaction) {
|
||||
return walletAppKit.chain().getHeightFuture((int) transaction.getLockTime());
|
||||
}
|
||||
|
||||
public int getBestChainHeight() {
|
||||
return walletAppKit.chain().getBestChainHeight();
|
||||
}
|
||||
|
||||
public void addBlockChainListener(BlockChainListener blockChainListener) {
|
||||
walletAppKit.chain().addListener(blockChainListener);
|
||||
}
|
||||
|
||||
public void removeBlockChainListener(BlockChainListener blockChainListener) {
|
||||
walletAppKit.chain().removeListener(blockChainListener);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -639,9 +658,9 @@ public class TradeWalletService {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Inner classes
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Inner classes
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public class Result {
|
||||
private final List<TransactionOutput> connectedOutputsForAllInputs;
|
||||
|
@ -32,21 +32,27 @@ public class FiatAccount implements Serializable {
|
||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final long HOUR_IN_BLOCKS = 6;
|
||||
public static final long DAY_IN_BLOCKS = HOUR_IN_BLOCKS * 24;
|
||||
public static final long WEEK_IN_BLOCKS = DAY_IN_BLOCKS * 7;
|
||||
|
||||
public enum Type {
|
||||
IRC("", ""),
|
||||
SEPA("IBAN", "BIC"),
|
||||
WIRE("primary ID", "secondary ID"),
|
||||
INTERNATIONAL("primary ID", "secondary ID"),
|
||||
OK_PAY("primary ID", "secondary ID"),
|
||||
NET_TELLER("primary ID", "secondary ID"),
|
||||
PERFECT_MONEY("primary ID", "secondary ID");
|
||||
IRC("", "", 1),
|
||||
SEPA("IBAN", "BIC", WEEK_IN_BLOCKS),
|
||||
WIRE("primary ID", "secondary ID", WEEK_IN_BLOCKS),
|
||||
INTERNATIONAL("primary ID", "secondary ID", 2 * WEEK_IN_BLOCKS),
|
||||
OK_PAY("primary ID", "secondary ID", HOUR_IN_BLOCKS),
|
||||
NET_TELLER("primary ID", "secondary ID", HOUR_IN_BLOCKS),
|
||||
PERFECT_MONEY("primary ID", "secondary ID", HOUR_IN_BLOCKS);
|
||||
|
||||
public final String primaryId;
|
||||
public final String secondaryId;
|
||||
public final long lockTimeDelta;
|
||||
|
||||
Type(String primaryId, String secondaryId) {
|
||||
Type(String primaryId, String secondaryId, long lockTimeDelta) {
|
||||
this.primaryId = primaryId;
|
||||
this.secondaryId = secondaryId;
|
||||
this.lockTimeDelta = lockTimeDelta;
|
||||
}
|
||||
|
||||
public static ArrayList<Type> getAllBankAccountTypes() {
|
||||
|
@ -32,7 +32,7 @@ import io.bitsquare.trade.protocol.trade.BuyerAsOffererProtocol;
|
||||
import io.bitsquare.trade.protocol.trade.SellerAsTakerProtocol;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CreateAndSignPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CreateDepositTxInputs;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessPayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessPayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessRequestDepositTxInputsMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessRequestPublishDepositTxMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.SendDepositTxPublishedMessage;
|
||||
@ -46,9 +46,9 @@ import io.bitsquare.trade.protocol.trade.tasks.seller.CreateAndSignDepositTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessDepositTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessFiatTransferStartedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessRequestPayDepositMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendPayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendPayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendRequestDepositTxInputsMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SignAndPublishPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SignAndFinalizePayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.CreateTakeOfferFeeTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.VerifyOfferFeePayment;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.VerifyOffererAccount;
|
||||
@ -111,7 +111,7 @@ public class DebugView extends InitializableView {
|
||||
VerifyTakeOfferFeePayment.class,
|
||||
SendFiatTransferStartedMessage.class,
|
||||
|
||||
ProcessPayoutTxPublishedMessage.class,
|
||||
ProcessPayoutTxFinalizedMessage.class,
|
||||
Boolean.class, /* used as seperator*/
|
||||
|
||||
|
||||
@ -129,9 +129,9 @@ public class DebugView extends InitializableView {
|
||||
|
||||
ProcessFiatTransferStartedMessage.class,
|
||||
|
||||
SignAndPublishPayoutTx.class,
|
||||
SignAndFinalizePayoutTx.class,
|
||||
VerifyOfferFeePayment.class,
|
||||
SendPayoutTxPublishedMessage.class
|
||||
SendPayoutTxFinalizedMessage.class
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -255,7 +255,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
"Please try later again." + msg);
|
||||
takeOfferRequested = false;
|
||||
break;
|
||||
case PAYOUT_PUBLISHED:
|
||||
case PAYOUT_FINALIZED:
|
||||
break;
|
||||
case EXCEPTION:
|
||||
errorMessage.set(msg);
|
||||
@ -292,7 +292,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
"Please try later again." + msg);
|
||||
takeOfferRequested = false;
|
||||
break;
|
||||
case PAYOUT_PUBLISHED:
|
||||
case PAYOUT_FINALIZED:
|
||||
break;
|
||||
case EXCEPTION:
|
||||
errorMessage.set(msg);
|
||||
|
@ -22,6 +22,7 @@ import io.bitsquare.gui.main.portfolio.pendingtrades.steps.CompletedView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.StartFiatView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.WaitFiatReceivedView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.WaitPayoutLockTimeView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.WaitTxInBlockchainView;
|
||||
import io.bitsquare.locale.BSResources;
|
||||
|
||||
@ -34,6 +35,7 @@ public class BuyerSubView extends TradeSubView {
|
||||
private TradeWizardItem waitTxInBlockchain;
|
||||
private TradeWizardItem startFiat;
|
||||
private TradeWizardItem waitFiatReceived;
|
||||
private TradeWizardItem payoutUnlock;
|
||||
private TradeWizardItem completed;
|
||||
|
||||
|
||||
@ -60,9 +62,10 @@ public class BuyerSubView extends TradeSubView {
|
||||
waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation");
|
||||
startFiat = new TradeWizardItem(StartFiatView.class, "Start payment");
|
||||
waitFiatReceived = new TradeWizardItem(WaitFiatReceivedView.class, "Wait until payment has arrived");
|
||||
payoutUnlock = new TradeWizardItem(WaitPayoutLockTimeView.class, "Wait for payout unlock");
|
||||
completed = new TradeWizardItem(CompletedView.class, "Completed");
|
||||
|
||||
leftVBox.getChildren().addAll(waitTxInBlockchain, startFiat, waitFiatReceived, completed);
|
||||
leftVBox.getChildren().addAll(waitTxInBlockchain, startFiat, waitFiatReceived, payoutUnlock, completed);
|
||||
}
|
||||
|
||||
|
||||
@ -110,10 +113,20 @@ public class BuyerSubView extends TradeSubView {
|
||||
"the Bitcoin sellers payment account, the payout transaction will be published.",
|
||||
model.getCurrencyCode()));
|
||||
break;
|
||||
case BUYER_PAYOUT_FINALIZED:
|
||||
waitTxInBlockchain.done();
|
||||
startFiat.done();
|
||||
waitFiatReceived.done();
|
||||
showItem(payoutUnlock);
|
||||
|
||||
((WaitPayoutLockTimeView) tradeStepDetailsView).setInfoLabelText("The payout transaction is signed and finalized by both parties." +
|
||||
"\nFor reducing bank chargeback risks you need to wait until the payout gets unlocked to transfer your Bitcoin.");
|
||||
break;
|
||||
case BUYER_COMPLETED:
|
||||
waitTxInBlockchain.done();
|
||||
startFiat.done();
|
||||
waitFiatReceived.done();
|
||||
payoutUnlock.done();
|
||||
showItem(completed);
|
||||
|
||||
CompletedView completedView = (CompletedView) tradeStepDetailsView;
|
||||
|
@ -18,6 +18,7 @@
|
||||
package io.bitsquare.gui.main.portfolio.pendingtrades;
|
||||
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.viewfx.model.Activatable;
|
||||
import io.bitsquare.common.viewfx.model.DataModel;
|
||||
@ -35,6 +36,7 @@ import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.trade.states.TradeState;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import org.bitcoinj.core.BlockChainListener;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@ -60,6 +62,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||
|
||||
private final TradeManager tradeManager;
|
||||
private final WalletService walletService;
|
||||
private TradeWalletService tradeWalletService;
|
||||
private final User user;
|
||||
private Navigation navigation;
|
||||
|
||||
@ -80,9 +83,11 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user, Navigation navigation) {
|
||||
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, TradeWalletService tradeWalletService, User user, Navigation
|
||||
navigation) {
|
||||
this.tradeManager = tradeManager;
|
||||
this.walletService = walletService;
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
this.user = user;
|
||||
this.navigation = navigation;
|
||||
|
||||
@ -281,5 +286,24 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||
return txId;
|
||||
}
|
||||
|
||||
String getPayoutTxId() {
|
||||
return trade.getPayoutTx().getHashAsString();
|
||||
}
|
||||
|
||||
void addBlockChainListener(BlockChainListener blockChainListener) {
|
||||
tradeWalletService.addBlockChainListener(blockChainListener);
|
||||
}
|
||||
|
||||
void removeBlockChainListener(BlockChainListener blockChainListener) {
|
||||
tradeWalletService.removeBlockChainListener(blockChainListener);
|
||||
}
|
||||
|
||||
public long getLockTime() {
|
||||
return trade.getPayoutTx().getLockTime();
|
||||
}
|
||||
|
||||
public int getBestChainHeight() {
|
||||
return tradeWalletService.getBestChainHeight();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.states.OffererTradeState;
|
||||
import io.bitsquare.trade.states.TakerTradeState;
|
||||
|
||||
import org.bitcoinj.core.BlockChainListener;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
@ -58,11 +59,13 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
SELLER_WAIT_PAYMENT_STARTED,
|
||||
SELLER_CONFIRM_RECEIVE_PAYMENT,
|
||||
SELLER_SEND_PUBLISHED_MSG,
|
||||
SELLER_PAYOUT_FINALIZED,
|
||||
SELLER_COMPLETED,
|
||||
|
||||
BUYER_WAIT_TX_CONF,
|
||||
BUYER_START_PAYMENT,
|
||||
BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED,
|
||||
BUYER_PAYOUT_FINALIZED,
|
||||
BUYER_COMPLETED,
|
||||
|
||||
MESSAGE_SENDING_FAILED,
|
||||
@ -135,6 +138,10 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
return txId;
|
||||
}
|
||||
|
||||
public String getPayoutTxId() {
|
||||
return dataModel.getPayoutTxId();
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty getWithdrawalButtonDisable() {
|
||||
return withdrawalButtonDisable;
|
||||
}
|
||||
@ -224,6 +231,26 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
return formatter.formatDateTime(value);
|
||||
}
|
||||
|
||||
public void addBlockChainListener(BlockChainListener blockChainListener) {
|
||||
dataModel.addBlockChainListener(blockChainListener);
|
||||
}
|
||||
|
||||
public void removeBlockChainListener(BlockChainListener blockChainListener) {
|
||||
dataModel.removeBlockChainListener(blockChainListener);
|
||||
}
|
||||
|
||||
public long getLockTime() {
|
||||
return dataModel.getLockTime();
|
||||
}
|
||||
|
||||
public int getBestChainHeight() {
|
||||
return dataModel.getBestChainHeight();
|
||||
}
|
||||
|
||||
public String getUnlockDate(long missingBlocks) {
|
||||
return formatter.getUnlockDate(missingBlocks);
|
||||
}
|
||||
|
||||
// payment
|
||||
public String getPaymentMethod() {
|
||||
assert dataModel.getContract() != null;
|
||||
@ -304,12 +331,18 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
|
||||
case FIAT_PAYMENT_RECEIVED:
|
||||
break;
|
||||
case PAYOUT_PUBLISHED:
|
||||
case PAYOUT_FINALIZED:
|
||||
viewState.set(ViewState.SELLER_SEND_PUBLISHED_MSG);
|
||||
break;
|
||||
case PAYOUT_PUBLISHED_MSG_SENT:
|
||||
case PAYOUT_FINALIZED_MSG_SENT:
|
||||
viewState.set(ViewState.SELLER_PAYOUT_FINALIZED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
viewState.set(ViewState.SELLER_COMPLETED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED_FAILED:
|
||||
viewState.set(ViewState.EXCEPTION);
|
||||
break;
|
||||
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
|
||||
@ -345,12 +378,18 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
|
||||
case FIAT_PAYMENT_RECEIVED:
|
||||
break;
|
||||
case PAYOUT_PUBLISHED:
|
||||
case PAYOUT_FINALIZED:
|
||||
viewState.set(ViewState.SELLER_SEND_PUBLISHED_MSG);
|
||||
break;
|
||||
case PAYOUT_PUBLISHED_MSG_SENT:
|
||||
case PAYOUT_FINALIZED_MSG_SENT:
|
||||
viewState.set(ViewState.SELLER_PAYOUT_FINALIZED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
viewState.set(ViewState.SELLER_COMPLETED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED_FAILED:
|
||||
viewState.set(ViewState.EXCEPTION);
|
||||
break;
|
||||
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
|
||||
@ -393,9 +432,16 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
break;
|
||||
|
||||
case FIAT_PAYMENT_RECEIVED:
|
||||
case PAYOUT_PUBLISHED:
|
||||
case PAYOUT_FINALIZED:
|
||||
case PAYOUT_FINALIZED_MSG_SENT:
|
||||
viewState.set(ViewState.BUYER_PAYOUT_FINALIZED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
viewState.set(ViewState.BUYER_COMPLETED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED_FAILED:
|
||||
viewState.set(ViewState.EXCEPTION);
|
||||
break;
|
||||
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
|
||||
@ -432,9 +478,16 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
break;
|
||||
|
||||
case FIAT_PAYMENT_RECEIVED:
|
||||
case PAYOUT_PUBLISHED:
|
||||
case PAYOUT_FINALIZED:
|
||||
case PAYOUT_FINALIZED_MSG_SENT:
|
||||
viewState.set(ViewState.BUYER_PAYOUT_FINALIZED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
viewState.set(ViewState.BUYER_COMPLETED);
|
||||
break;
|
||||
case PAYOUT_BROAD_CASTED_FAILED:
|
||||
viewState.set(ViewState.EXCEPTION);
|
||||
break;
|
||||
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
|
||||
|
@ -21,6 +21,7 @@ import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.CompletedView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.ConfirmFiatReceivedView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.WaitPayoutLockTimeView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.WaitTxInBlockchainView;
|
||||
import io.bitsquare.locale.BSResources;
|
||||
|
||||
@ -33,6 +34,7 @@ public class SellerSubView extends TradeSubView {
|
||||
private TradeWizardItem waitTxInBlockchain;
|
||||
private TradeWizardItem waitFiatStarted;
|
||||
private TradeWizardItem confirmFiatReceived;
|
||||
private TradeWizardItem payoutUnlock;
|
||||
private TradeWizardItem completed;
|
||||
|
||||
|
||||
@ -59,9 +61,10 @@ public class SellerSubView extends TradeSubView {
|
||||
waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation");
|
||||
waitFiatStarted = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for payment started");
|
||||
confirmFiatReceived = new TradeWizardItem(ConfirmFiatReceivedView.class, "Confirm payment received");
|
||||
payoutUnlock = new TradeWizardItem(WaitPayoutLockTimeView.class, "Wait for payout unlock");
|
||||
completed = new TradeWizardItem(CompletedView.class, "Completed");
|
||||
|
||||
leftVBox.getChildren().addAll(waitTxInBlockchain, waitFiatStarted, confirmFiatReceived, completed);
|
||||
leftVBox.getChildren().addAll(waitTxInBlockchain, waitFiatStarted, confirmFiatReceived, payoutUnlock, completed);
|
||||
}
|
||||
|
||||
|
||||
@ -76,6 +79,7 @@ public class SellerSubView extends TradeSubView {
|
||||
waitTxInBlockchain.inactive();
|
||||
waitFiatStarted.inactive();
|
||||
confirmFiatReceived.inactive();
|
||||
payoutUnlock.inactive();
|
||||
completed.inactive();
|
||||
|
||||
if (tradeStepDetailsView != null)
|
||||
@ -129,14 +133,23 @@ public class SellerSubView extends TradeSubView {
|
||||
waitTxInBlockchain.done();
|
||||
waitFiatStarted.done();
|
||||
showItem(confirmFiatReceived);
|
||||
((ConfirmFiatReceivedView) tradeStepDetailsView).setStatusText("Sending message to trading peer transaction...");
|
||||
}
|
||||
break;
|
||||
case SELLER_PAYOUT_FINALIZED:
|
||||
waitTxInBlockchain.done();
|
||||
waitFiatStarted.done();
|
||||
confirmFiatReceived.done();
|
||||
showItem(payoutUnlock);
|
||||
|
||||
((ConfirmFiatReceivedView) tradeStepDetailsView).setStatusText("Sending message to trading peer transaction...");
|
||||
((WaitPayoutLockTimeView) tradeStepDetailsView).setInfoLabelText("The payout transaction is signed and finalized by both parties." +
|
||||
"\nFor reducing bank chargeback risks you need to wait until the payout gets unlocked to transfer your Bitcoin.");
|
||||
break;
|
||||
case SELLER_COMPLETED:
|
||||
waitTxInBlockchain.done();
|
||||
waitFiatStarted.done();
|
||||
confirmFiatReceived.done();
|
||||
payoutUnlock.done();
|
||||
showItem(completed);
|
||||
|
||||
CompletedView completedView = (CompletedView) tradeStepDetailsView;
|
||||
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.gui.main.portfolio.pendingtrades.steps;
|
||||
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
|
||||
import org.bitcoinj.core.AbstractBlockChain;
|
||||
import org.bitcoinj.core.BlockChainListener;
|
||||
import org.bitcoinj.core.ScriptException;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.StoredBlock;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.VerificationException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javafx.scene.control.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.bitsquare.gui.util.ComponentBuilder.*;
|
||||
|
||||
public class WaitPayoutLockTimeView extends TradeStepDetailsView {
|
||||
private static final Logger log = LoggerFactory.getLogger(WaitPayoutLockTimeView.class);
|
||||
|
||||
private final BlockChainListener blockChainListener;
|
||||
|
||||
private TextField blockTextField;
|
||||
private Label infoLabel;
|
||||
private TextField timeTextField;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, Initialisation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public WaitPayoutLockTimeView(PendingTradesViewModel model) {
|
||||
super(model);
|
||||
|
||||
blockChainListener = new BlockChainListener() {
|
||||
@Override
|
||||
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
|
||||
setLockTime(block.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks) throws VerificationException {
|
||||
setLockTime(model.getBestChainHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionRelevant(Transaction tx) throws ScriptException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveFromBlock(Transaction tx, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset) throws
|
||||
VerificationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset)
|
||||
throws VerificationException {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
super.activate();
|
||||
|
||||
model.addBlockChainListener(blockChainListener);
|
||||
setLockTime(model.getBestChainHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
super.deactivate();
|
||||
|
||||
model.removeBlockChainListener(blockChainListener);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setInfoLabelText(String text) {
|
||||
if (infoLabel != null)
|
||||
infoLabel.setText(text);
|
||||
}
|
||||
|
||||
private void setLockTime(int bestBlocKHeight) {
|
||||
long missingBlocks = model.getLockTime() - (long) bestBlocKHeight;
|
||||
blockTextField.setText(String.valueOf(missingBlocks));
|
||||
timeTextField.setText(model.getUnlockDate(missingBlocks));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Build view
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void buildGridEntries() {
|
||||
getAndAddTitledGroupBg(gridPane, gridRow, 2, "Payout transaction lock time");
|
||||
blockTextField = getAndAddLabelTextFieldPair(gridPane, gridRow++, "Block(s) to wait until unlock:", Layout.FIRST_ROW_DISTANCE).textField;
|
||||
timeTextField = getAndAddLabelTextFieldPair(gridPane, gridRow++, "Approx. date when payout gets unlocked:").textField;
|
||||
|
||||
getAndAddTitledGroupBg(gridPane, gridRow, 1, "Information", Layout.GROUP_DISTANCE);
|
||||
infoLabel = getAndAddInfoLabel(gridPane, gridRow++, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,4 +356,11 @@ public class BSFormatter {
|
||||
Double.parseDouble(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
public String getUnlockDate(long missingBlocks) {
|
||||
DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
|
||||
DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
|
||||
Date unlockDate = new Date(new Date().getTime() + missingBlocks * 10 * 60 * 1000);
|
||||
return dateFormatter.format(unlockDate) + " " + timeFormatter.format(unlockDate);
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
public class OfferBook {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(OfferBook.class);
|
||||
private static final int POLLING_INTERVAL = 5000; // in ms
|
||||
private static final int POLLING_INTERVAL = 2000; // in ms
|
||||
|
||||
private final OfferBookService offerBookService;
|
||||
private final User user;
|
||||
|
@ -252,7 +252,7 @@ public class FileManager<T> {
|
||||
private void saveNowInternal(T serializable) {
|
||||
long now = System.currentTimeMillis();
|
||||
saveToFile(serializable, dir, storageFile);
|
||||
log.info("Save {} completed in {}msec", storageFile, System.currentTimeMillis() - now);
|
||||
Platform.runLater(() -> log.info("Save {} completed in {}msec", storageFile, System.currentTimeMillis() - now));
|
||||
}
|
||||
|
||||
private void saveToFile(T serializable, File dir, File storageFile) {
|
||||
@ -289,7 +289,6 @@ public class FileManager<T> {
|
||||
renameTempFileToFile(tempFile, storageFile);
|
||||
} catch (Throwable t) {
|
||||
log.debug("storageFile " + storageFile.toString());
|
||||
log.debug("currentThread " + Thread.currentThread());
|
||||
t.printStackTrace();
|
||||
log.error("Error at saveToFile: " + t.getMessage());
|
||||
} finally {
|
||||
|
@ -169,10 +169,11 @@ abstract public class Trade implements Model, Serializable {
|
||||
createProtocol();
|
||||
|
||||
if (mailboxMessage != null) {
|
||||
tradeProtocol.applyMailboxMessage(mailboxMessage);
|
||||
tradeProtocol.applyMailboxMessage(mailboxMessage, this);
|
||||
// After applied to protocol we remove it
|
||||
mailboxMessage = null;
|
||||
}
|
||||
tradeProtocol.checkPayoutTxTimeLock(this);
|
||||
}
|
||||
|
||||
protected void initStateProperties() {
|
||||
@ -333,6 +334,11 @@ abstract public class Trade implements Model, Serializable {
|
||||
tradeVolumeProperty.set(getTradeVolume());
|
||||
}
|
||||
|
||||
// TODO support case of multiple fiat accounts
|
||||
public long getLockTimeDelta() {
|
||||
return getOffer().getFiatAccountType().lockTimeDelta;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Coin getTradeAmount() {
|
||||
return tradeAmount;
|
||||
|
@ -54,7 +54,7 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
|
||||
Coin balance = model.walletService.getBalanceForAddress(addressEntry.getAddress());
|
||||
if (balance.compareTo(totalsNeeded) >= 0) {
|
||||
|
||||
model.tradeWalletService.broadcastCreateOfferFeeTx(model.getTransaction(), new FutureCallback<Transaction>() {
|
||||
model.tradeWalletService.broadcastTx(model.getTransaction(), new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString());
|
||||
|
@ -22,16 +22,17 @@ import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.Peer;
|
||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||
import io.bitsquare.trade.BuyerAsOffererTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
||||
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CommitPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CreateAndSignPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CreateDepositTxInputs;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessPayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessPayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessRequestDepositTxInputsMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessRequestPublishDepositTxMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.SendDepositTxPublishedMessage;
|
||||
@ -41,6 +42,7 @@ import io.bitsquare.trade.protocol.trade.tasks.buyer.SignAndPublishDepositTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.VerifyAndSignContract;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakeOfferFeePayment;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.offerer.VerifyTakerAccount;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||
import io.bitsquare.trade.states.OffererTradeState;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -72,13 +74,16 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage) {
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage, Trade trade) {
|
||||
if (trade == null)
|
||||
this.trade = trade;
|
||||
|
||||
log.debug("setMailboxMessage " + mailboxMessage);
|
||||
// Might be called twice, so check that its only processed once
|
||||
if (!processModel.isMailboxMessageProcessed()) {
|
||||
processModel.mailboxMessageProcessed();
|
||||
if (mailboxMessage instanceof PayoutTxPublishedMessage) {
|
||||
handle((PayoutTxPublishedMessage) mailboxMessage);
|
||||
if (mailboxMessage instanceof PayoutTxFinalizedMessage) {
|
||||
handle((PayoutTxFinalizedMessage) mailboxMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,7 +184,7 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||
// Incoming message handling
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void handle(PayoutTxPublishedMessage tradeMessage) {
|
||||
private void handle(PayoutTxFinalizedMessage tradeMessage) {
|
||||
processModel.setTradeMessage(tradeMessage);
|
||||
|
||||
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsOffererTrade,
|
||||
@ -190,8 +195,11 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||
},
|
||||
this::handleTaskRunnerFault);
|
||||
|
||||
taskRunner.addTasks(ProcessPayoutTxPublishedMessage.class);
|
||||
taskRunner.addTasks(CommitPayoutTx.class);
|
||||
taskRunner.addTasks(
|
||||
ProcessPayoutTxFinalizedMessage.class,
|
||||
CommitPayoutTx.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class
|
||||
);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
@ -216,8 +224,8 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||
else if (tradeMessage instanceof RequestPublishDepositTxMessage) {
|
||||
handle((RequestPublishDepositTxMessage) tradeMessage);
|
||||
}
|
||||
else if (tradeMessage instanceof PayoutTxPublishedMessage) {
|
||||
handle((PayoutTxPublishedMessage) tradeMessage);
|
||||
else if (tradeMessage instanceof PayoutTxFinalizedMessage) {
|
||||
handle((PayoutTxFinalizedMessage) tradeMessage);
|
||||
}
|
||||
else {
|
||||
log.error("Incoming tradeMessage not supported. " + tradeMessage);
|
||||
|
@ -21,19 +21,21 @@ import io.bitsquare.p2p.MailboxMessage;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.Peer;
|
||||
import io.bitsquare.trade.BuyerAsTakerTrade;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.RequestPublishDepositTxMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CommitPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CreateAndSignPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.CreateDepositTxInputs;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessPayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessPayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.ProcessRequestPublishDepositTxMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.SendDepositTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.SendFiatTransferStartedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.SendRequestPayDepositMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.SignAndPublishDepositTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.buyer.VerifyAndSignContract;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.BroadcastTakeOfferFeeTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.CreateTakeOfferFeeTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.VerifyOfferFeePayment;
|
||||
@ -69,13 +71,16 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage) {
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage, Trade trade) {
|
||||
if (trade == null)
|
||||
this.trade = trade;
|
||||
|
||||
log.debug("setMailboxMessage " + mailboxMessage);
|
||||
// Might be called twice, so check that its only processed once
|
||||
if (!processModel.isMailboxMessageProcessed()) {
|
||||
processModel.mailboxMessageProcessed();
|
||||
if (mailboxMessage instanceof PayoutTxPublishedMessage) {
|
||||
handle((PayoutTxPublishedMessage) mailboxMessage);
|
||||
if (mailboxMessage instanceof PayoutTxFinalizedMessage) {
|
||||
handle((PayoutTxFinalizedMessage) mailboxMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,7 +147,7 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
|
||||
// After peer has received Fiat tx
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void handle(PayoutTxPublishedMessage tradeMessage) {
|
||||
private void handle(PayoutTxFinalizedMessage tradeMessage) {
|
||||
processModel.setTradeMessage(tradeMessage);
|
||||
|
||||
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsTakerTrade,
|
||||
@ -154,8 +159,9 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
|
||||
this::handleTaskRunnerFault);
|
||||
|
||||
taskRunner.addTasks(
|
||||
ProcessPayoutTxPublishedMessage.class,
|
||||
CommitPayoutTx.class);
|
||||
ProcessPayoutTxFinalizedMessage.class,
|
||||
CommitPayoutTx.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
@ -174,8 +180,8 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
|
||||
if (tradeMessage instanceof RequestPublishDepositTxMessage) {
|
||||
handle((RequestPublishDepositTxMessage) tradeMessage);
|
||||
}
|
||||
else if (tradeMessage instanceof PayoutTxPublishedMessage) {
|
||||
handle((PayoutTxPublishedMessage) tradeMessage);
|
||||
else if (tradeMessage instanceof PayoutTxFinalizedMessage) {
|
||||
handle((PayoutTxFinalizedMessage) tradeMessage);
|
||||
}
|
||||
else {
|
||||
log.error("Incoming message not supported. " + tradeMessage);
|
||||
|
@ -69,7 +69,6 @@ public class ProcessModel implements Model, Serializable {
|
||||
transient private boolean mailboxMessageProcessed;
|
||||
transient private TradeMessage tradeMessage;
|
||||
private String takeOfferFeeTxId;
|
||||
private Transaction payoutTx;
|
||||
private List<TransactionOutput> connectedOutputsForAllInputs;
|
||||
private Coin payoutAmount;
|
||||
private Transaction preparedDepositTx;
|
||||
@ -166,15 +165,6 @@ public class ProcessModel implements Model, Serializable {
|
||||
return mailboxMessageProcessed;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Transaction getPayoutTx() {
|
||||
return payoutTx;
|
||||
}
|
||||
|
||||
public void setPayoutTx(Transaction payoutTx) {
|
||||
this.payoutTx = payoutTx;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Transaction getTakeOfferFeeTx() {
|
||||
return takeOfferFeeTx;
|
||||
|
@ -22,6 +22,7 @@ import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.Peer;
|
||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||
import io.bitsquare.trade.SellerAsOffererTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
||||
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
||||
@ -36,9 +37,10 @@ import io.bitsquare.trade.protocol.trade.tasks.seller.CreateAndSignDepositTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessDepositTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessFiatTransferStartedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessRequestPayDepositMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendPayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendPayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendRequestPublishDepositTxMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SignAndPublishPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SignAndFinalizePayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||
import io.bitsquare.trade.states.OffererTradeState;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -71,7 +73,10 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage) {
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage, Trade trade) {
|
||||
if (trade == null)
|
||||
this.trade = trade;
|
||||
|
||||
log.debug("setMailboxMessage " + mailboxMessage);
|
||||
// Might be called twice, so check that its only processed once
|
||||
if (!processModel.isMailboxMessageProcessed()) {
|
||||
@ -201,8 +206,9 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
||||
|
||||
taskRunner.addTasks(
|
||||
VerifyTakeOfferFeePayment.class,
|
||||
SignAndPublishPayoutTx.class,
|
||||
SendPayoutTxPublishedMessage.class
|
||||
SignAndFinalizePayoutTx.class,
|
||||
SendPayoutTxFinalizedMessage.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class
|
||||
);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import io.bitsquare.p2p.MailboxMessage;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.Peer;
|
||||
import io.bitsquare.trade.SellerAsTakerTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.RequestPayDepositMessage;
|
||||
@ -31,10 +32,11 @@ import io.bitsquare.trade.protocol.trade.tasks.seller.CreateAndSignDepositTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessDepositTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessFiatTransferStartedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.ProcessRequestPayDepositMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendPayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendPayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendRequestDepositTxInputsMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SendRequestPublishDepositTxMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SignAndPublishPayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.seller.SignAndFinalizePayoutTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.BroadcastTakeOfferFeeTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.CreateTakeOfferFeeTx;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.taker.VerifyOfferFeePayment;
|
||||
@ -71,7 +73,10 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage) {
|
||||
public void applyMailboxMessage(MailboxMessage mailboxMessage, Trade trade) {
|
||||
if (trade == null)
|
||||
this.trade = trade;
|
||||
|
||||
log.debug("setMailboxMessage " + mailboxMessage);
|
||||
// Might be called twice, so check that its only processed once
|
||||
if (!processModel.isMailboxMessageProcessed()) {
|
||||
@ -177,8 +182,9 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc
|
||||
|
||||
taskRunner.addTasks(
|
||||
VerifyOfferFeePayment.class,
|
||||
SignAndPublishPayoutTx.class,
|
||||
SendPayoutTxPublishedMessage.class
|
||||
SignAndFinalizePayoutTx.class,
|
||||
SendPayoutTxFinalizedMessage.class,
|
||||
SetupPayoutTxLockTimeReachedListener.class
|
||||
);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
@ -19,8 +19,10 @@ package io.bitsquare.trade.protocol.trade;
|
||||
|
||||
import io.bitsquare.p2p.MailboxMessage;
|
||||
import io.bitsquare.p2p.MessageHandler;
|
||||
import io.bitsquare.trade.OffererTrade;
|
||||
import io.bitsquare.trade.TakerTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.shared.SetupPayoutTxLockTimeReachedListener;
|
||||
import io.bitsquare.trade.states.OffererTradeState;
|
||||
import io.bitsquare.trade.states.TakerTradeState;
|
||||
|
||||
@ -51,7 +53,32 @@ public abstract class TradeProtocol {
|
||||
processModel.getMessageService().removeMessageHandler(messageHandler);
|
||||
}
|
||||
|
||||
abstract public void applyMailboxMessage(MailboxMessage mailboxMessage);
|
||||
abstract public void applyMailboxMessage(MailboxMessage mailboxMessage, Trade trade);
|
||||
|
||||
public void checkPayoutTxTimeLock(Trade trade) {
|
||||
if (trade == null)
|
||||
this.trade = trade;
|
||||
|
||||
boolean needPayoutTxBroadcast = false;
|
||||
if (trade instanceof TakerTrade)
|
||||
needPayoutTxBroadcast = trade.processStateProperty().get() == TakerTradeState.ProcessState.PAYOUT_FINALIZED
|
||||
|| trade.processStateProperty().get() == TakerTradeState.ProcessState.PAYOUT_FINALIZED_MSG_SENT;
|
||||
else if (trade instanceof OffererTrade)
|
||||
needPayoutTxBroadcast = trade.processStateProperty().get() == OffererTradeState.ProcessState.PAYOUT_FINALIZED
|
||||
|| trade.processStateProperty().get() == OffererTradeState.ProcessState.PAYOUT_FINALIZED_MSG_SENT;
|
||||
|
||||
if (needPayoutTxBroadcast) {
|
||||
TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
log.debug("taskRunner needPayoutTxBroadcast completed");
|
||||
processModel.onComplete();
|
||||
},
|
||||
this::handleTaskRunnerFault);
|
||||
|
||||
taskRunner.addTasks(SetupPayoutTxLockTimeReachedListener.class);
|
||||
taskRunner.run();
|
||||
}
|
||||
}
|
||||
|
||||
protected void startTimeout() {
|
||||
log.debug("startTimeout");
|
||||
|
@ -26,13 +26,13 @@ import java.io.Serializable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
public class PayoutTxPublishedMessage extends TradeMessage implements MailboxMessage, Serializable {
|
||||
public class PayoutTxFinalizedMessage extends TradeMessage implements MailboxMessage, Serializable {
|
||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public final Transaction payoutTx;
|
||||
|
||||
public PayoutTxPublishedMessage(String tradeId, Transaction payoutTx) {
|
||||
public PayoutTxFinalizedMessage(String tradeId, Transaction payoutTx) {
|
||||
super(tradeId);
|
||||
this.payoutTx = payoutTx;
|
||||
}
|
@ -47,6 +47,7 @@ public class CreateAndSignPayoutTx extends TradeTask {
|
||||
sellerPayoutAmount,
|
||||
processModel.getAddressEntry(),
|
||||
processModel.tradingPeer.getPayoutAddressString(),
|
||||
trade.getLockTimeDelta(),
|
||||
processModel.getTradeWalletPubKey(),
|
||||
processModel.tradingPeer.getTradeWalletPubKey(),
|
||||
processModel.getArbitratorPubKey());
|
||||
|
@ -22,7 +22,7 @@ import io.bitsquare.trade.OffererTrade;
|
||||
import io.bitsquare.trade.TakerTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.TradeTask;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.states.OffererTradeState;
|
||||
import io.bitsquare.trade.states.TakerTradeState;
|
||||
|
||||
@ -32,26 +32,26 @@ import org.slf4j.LoggerFactory;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.bitsquare.util.Validator.checkTradeId;
|
||||
|
||||
public class ProcessPayoutTxPublishedMessage extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(ProcessPayoutTxPublishedMessage.class);
|
||||
public class ProcessPayoutTxFinalizedMessage extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(ProcessPayoutTxFinalizedMessage.class);
|
||||
|
||||
public ProcessPayoutTxPublishedMessage(TaskRunner taskHandler, Trade trade) {
|
||||
public ProcessPayoutTxFinalizedMessage(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRun() {
|
||||
try {
|
||||
PayoutTxPublishedMessage message = (PayoutTxPublishedMessage) processModel.getTradeMessage();
|
||||
PayoutTxFinalizedMessage message = (PayoutTxFinalizedMessage) processModel.getTradeMessage();
|
||||
checkTradeId(processModel.getId(), message);
|
||||
checkNotNull(message);
|
||||
|
||||
trade.setPayoutTx(checkNotNull(message.payoutTx));
|
||||
|
||||
if (trade instanceof OffererTrade)
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_PUBLISHED);
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_FINALIZED);
|
||||
else if (trade instanceof TakerTrade)
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_PUBLISHED);
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_FINALIZED);
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
@ -23,7 +23,7 @@ import io.bitsquare.trade.OffererTrade;
|
||||
import io.bitsquare.trade.TakerTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.TradeTask;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxFinalizedMessage;
|
||||
import io.bitsquare.trade.states.OffererTradeState;
|
||||
import io.bitsquare.trade.states.StateUtil;
|
||||
import io.bitsquare.trade.states.TakerTradeState;
|
||||
@ -31,17 +31,17 @@ import io.bitsquare.trade.states.TakerTradeState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SendPayoutTxPublishedMessage extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxPublishedMessage.class);
|
||||
public class SendPayoutTxFinalizedMessage extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxFinalizedMessage.class);
|
||||
|
||||
public SendPayoutTxPublishedMessage(TaskRunner taskHandler, Trade trade) {
|
||||
public SendPayoutTxFinalizedMessage(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRun() {
|
||||
try {
|
||||
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(processModel.getId(), processModel.getPayoutTx());
|
||||
PayoutTxFinalizedMessage tradeMessage = new PayoutTxFinalizedMessage(processModel.getId(), trade.getPayoutTx());
|
||||
processModel.getMessageService().sendMessage(trade.getTradingPeer(),
|
||||
tradeMessage,
|
||||
processModel.tradingPeer.getP2pSigPubKey(),
|
||||
@ -52,9 +52,9 @@ public class SendPayoutTxPublishedMessage extends TradeTask {
|
||||
log.trace("PayoutTxPublishedMessage successfully arrived at peer");
|
||||
|
||||
if (trade instanceof TakerTrade)
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_PUBLISHED_MSG_SENT);
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_FINALIZED_MSG_SENT);
|
||||
else if (trade instanceof OffererTrade)
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_PUBLISHED_MSG_SENT);
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_FINALIZED_MSG_SENT);
|
||||
|
||||
complete();
|
||||
}
|
@ -27,53 +27,39 @@ import io.bitsquare.trade.states.TakerTradeState;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SignAndPublishPayoutTx extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
|
||||
public class SignAndFinalizePayoutTx extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(SignAndFinalizePayoutTx.class);
|
||||
|
||||
public SignAndPublishPayoutTx(TaskRunner taskHandler, Trade trade) {
|
||||
public SignAndFinalizePayoutTx(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRun() {
|
||||
try {
|
||||
processModel.getTradeWalletService().signAndPublishPayoutTx(
|
||||
Transaction transaction = processModel.getTradeWalletService().signAndFinalizePayoutTx(
|
||||
trade.getDepositTx(),
|
||||
processModel.tradingPeer.getSignature(),
|
||||
processModel.tradingPeer.getPayoutAmount(),
|
||||
processModel.getPayoutAmount(),
|
||||
processModel.tradingPeer.getPayoutAddressString(),
|
||||
processModel.getAddressEntry(),
|
||||
trade.getLockTimeDelta(),
|
||||
processModel.tradingPeer.getTradeWalletPubKey(),
|
||||
processModel.getTradeWalletPubKey(),
|
||||
processModel.getArbitratorPubKey(),
|
||||
new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
processModel.setPayoutTx(transaction);
|
||||
processModel.getArbitratorPubKey()
|
||||
);
|
||||
|
||||
if (trade instanceof TakerTrade)
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_PUBLISHED);
|
||||
else if (trade instanceof OffererTrade)
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_PUBLISHED);
|
||||
trade.setPayoutTx(transaction);
|
||||
if (trade instanceof TakerTrade)
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_FINALIZED);
|
||||
else if (trade instanceof OffererTrade)
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_FINALIZED);
|
||||
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
t.printStackTrace();
|
||||
trade.setThrowable(t);
|
||||
failed(t);
|
||||
}
|
||||
});
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
trade.setThrowable(t);
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade.protocol.trade.tasks.shared;
|
||||
|
||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||
import io.bitsquare.trade.OffererTrade;
|
||||
import io.bitsquare.trade.TakerTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.TradeTask;
|
||||
import io.bitsquare.trade.states.OffererTradeState;
|
||||
import io.bitsquare.trade.states.TakerTradeState;
|
||||
|
||||
import org.bitcoinj.core.StoredBlock;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javafx.application.Platform;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SetupPayoutTxLockTimeReachedListener extends TradeTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(SetupPayoutTxLockTimeReachedListener.class);
|
||||
|
||||
public SetupPayoutTxLockTimeReachedListener(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRun() {
|
||||
try {
|
||||
if (processModel.getTradeWalletService().getBestChainHeight() >= trade.getPayoutTx().getLockTime()) {
|
||||
broadcastTx();
|
||||
}
|
||||
else {
|
||||
ListenableFuture<StoredBlock> blockHeightFuture = processModel.getTradeWalletService().getBlockHeightFuture(trade.getPayoutTx());
|
||||
blockHeightFuture.addListener(
|
||||
() -> {
|
||||
try {
|
||||
log.debug("Block height reached " + blockHeightFuture.get().getHeight());
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
broadcastTx();
|
||||
},
|
||||
Platform::runLater);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
trade.setThrowable(t);
|
||||
failed(t);
|
||||
}
|
||||
}
|
||||
|
||||
protected void broadcastTx() {
|
||||
processModel.getTradeWalletService().broadcastTx(trade.getPayoutTx(), new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
log.debug("BroadcastTx succeeded. Transaction:" + transaction);
|
||||
|
||||
if (trade instanceof TakerTrade)
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_BROAD_CASTED);
|
||||
else if (trade instanceof OffererTrade)
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_BROAD_CASTED);
|
||||
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
t.printStackTrace();
|
||||
trade.setThrowable(t);
|
||||
|
||||
if (trade instanceof TakerTrade)
|
||||
trade.setProcessState(TakerTradeState.ProcessState.PAYOUT_BROAD_CASTED_FAILED);
|
||||
else if (trade instanceof OffererTrade)
|
||||
trade.setProcessState(OffererTradeState.ProcessState.PAYOUT_BROAD_CASTED_FAILED);
|
||||
|
||||
|
||||
failed(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ public class BroadcastTakeOfferFeeTx extends TradeTask {
|
||||
@Override
|
||||
protected void doRun() {
|
||||
try {
|
||||
processModel.getTradeWalletService().broadcastTakeOfferFeeTx(processModel.getTakeOfferFeeTx(),
|
||||
processModel.getTradeWalletService().broadcastTx(processModel.getTakeOfferFeeTx(),
|
||||
new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
|
@ -40,9 +40,11 @@ public class OffererTradeState {
|
||||
FIAT_PAYMENT_STARTED,
|
||||
|
||||
FIAT_PAYMENT_RECEIVED,
|
||||
PAYOUT_PUBLISHED,
|
||||
PAYOUT_PUBLISHED_MSG_SENT,
|
||||
|
||||
PAYOUT_FINALIZED,
|
||||
PAYOUT_FINALIZED_MSG_SENT,
|
||||
PAYOUT_BROAD_CASTED,
|
||||
PAYOUT_BROAD_CASTED_FAILED,
|
||||
|
||||
MESSAGE_SENDING_FAILED,
|
||||
TIMEOUT,
|
||||
EXCEPTION
|
||||
|
@ -41,8 +41,10 @@ public class TakerTradeState {
|
||||
FIAT_PAYMENT_STARTED,
|
||||
|
||||
FIAT_PAYMENT_RECEIVED,
|
||||
PAYOUT_PUBLISHED,
|
||||
PAYOUT_PUBLISHED_MSG_SENT,
|
||||
PAYOUT_FINALIZED,
|
||||
PAYOUT_FINALIZED_MSG_SENT,
|
||||
PAYOUT_BROAD_CASTED,
|
||||
PAYOUT_BROAD_CASTED_FAILED,
|
||||
|
||||
MESSAGE_SENDING_FAILED,
|
||||
TIMEOUT,
|
||||
|
@ -34,12 +34,13 @@
|
||||
<logger name="io.bitsquare.gui.util.Profiler" level="ERROR"/>
|
||||
<logger name="io.bitsquare.locale.BSResources" level="ERROR"/>
|
||||
|
||||
<logger name="org.bitcoinj" level="INFO"/>
|
||||
<logger name="net.tomp2p" level="INFO"/>
|
||||
<logger name="org.bitcoinj" level="WARN"/>
|
||||
<logger name="net.tomp2p" level="WARN"/>
|
||||
|
||||
<logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/>
|
||||
<logger name="org.bitcoinj.core.Peer" level="WARN"/>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
<logger name="com.vinumeris.updatefx" level="OFF"/>
|
||||
<logger name="io.netty" level="OFF"/>
|
||||
|
Loading…
Reference in New Issue
Block a user