mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 23:06:39 +01:00
Add tool for manually creating the payout tx. Change shortcuts
This commit is contained in:
parent
a87b855164
commit
7acfdb23de
11 changed files with 365 additions and 26 deletions
|
@ -827,6 +827,137 @@ public class TradeWalletService {
|
|||
}
|
||||
|
||||
|
||||
// Emergency payout tool. Used only in cased when the payput from the arbitrator does not work because some data
|
||||
// in the trade/dispute are messed up.
|
||||
public Transaction emergencySignAndPublishPayoutTx(String depositTxHex,
|
||||
Coin buyerPayoutAmount,
|
||||
Coin sellerPayoutAmount,
|
||||
Coin arbitratorPayoutAmount,
|
||||
String buyerAddressString,
|
||||
String sellerAddressString,
|
||||
String arbitratorAddressString,
|
||||
@Nullable String buyerPrivateKeyAsHex,
|
||||
@Nullable String sellerPrivateKeyAsHex,
|
||||
String arbitratorPrivateKeyAsHex,
|
||||
String buyerPubKeyAsHex,
|
||||
String sellerPubKeyAsHex,
|
||||
String arbitratorPubKeyAsHex,
|
||||
String P2SHMultiSigOutputScript,
|
||||
List<String> buyerPubKeys,
|
||||
List<String> sellerPubKeys,
|
||||
FutureCallback<Transaction> callback)
|
||||
throws AddressFormatException, TransactionVerificationException, WalletException {
|
||||
log.trace("signAndPublishPayoutTx called");
|
||||
log.trace("depositTxHex " + depositTxHex);
|
||||
log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
|
||||
log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
|
||||
log.trace("arbitratorPayoutAmount " + arbitratorPayoutAmount.toFriendlyString());
|
||||
log.trace("buyerAddressString " + buyerAddressString);
|
||||
log.trace("sellerAddressString " + sellerAddressString);
|
||||
log.trace("arbitratorAddressString " + arbitratorAddressString);
|
||||
log.trace("buyerPrivateKeyAsHex " + buyerPrivateKeyAsHex);
|
||||
log.trace("sellerPrivateKeyAsHex " + sellerPrivateKeyAsHex);
|
||||
log.trace("arbitratorPrivateKeyAsHex " + arbitratorPrivateKeyAsHex);
|
||||
log.trace("buyerPubKeyAsHex " + buyerPubKeyAsHex);
|
||||
log.trace("sellerPubKeyAsHex " + sellerPubKeyAsHex);
|
||||
log.trace("arbitratorPubKeyAsHex " + arbitratorPubKeyAsHex);
|
||||
|
||||
log.trace("P2SHMultiSigOutputScript " + P2SHMultiSigOutputScript);
|
||||
log.trace("buyerPubKeys " + buyerPubKeys);
|
||||
log.trace("sellerPubKeys " + sellerPubKeys);
|
||||
|
||||
checkNotNull((buyerPrivateKeyAsHex != null || sellerPrivateKeyAsHex != null), "either buyerPrivateKeyAsHex or sellerPrivateKeyAsHex must not be null");
|
||||
|
||||
byte[] buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(buyerPubKeyAsHex)).getPubKey();
|
||||
byte[] sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(sellerPubKeyAsHex)).getPubKey();
|
||||
final byte[] arbitratorPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(arbitratorPubKeyAsHex)).getPubKey();
|
||||
|
||||
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
|
||||
if (!p2SHMultiSigOutputScript.toString().contains(P2SHMultiSigOutputScript)) {
|
||||
if (buyerPubKeys.isEmpty())
|
||||
buyerPubKeys.add(buyerPubKeyAsHex);
|
||||
if (sellerPubKeys.isEmpty())
|
||||
sellerPubKeys.add(sellerPubKeyAsHex);
|
||||
|
||||
boolean found = false;
|
||||
for (String b : buyerPubKeys) {
|
||||
if (found)
|
||||
break;
|
||||
byte[] bk = ECKey.fromPublicOnly(Utils.HEX.decode(b)).getPubKey();
|
||||
for (String s : sellerPubKeys) {
|
||||
byte[] sk = ECKey.fromPublicOnly(Utils.HEX.decode(s)).getPubKey();
|
||||
p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(bk, sk, arbitratorPubKey);
|
||||
if (p2SHMultiSigOutputScript.toString().contains(P2SHMultiSigOutputScript)) {
|
||||
log.trace("Found buyers pub key " + b);
|
||||
log.trace("Found sellers pub key " + s);
|
||||
buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(b)).getPubKey();
|
||||
sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(s)).getPubKey();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
log.warn("We did not find any matching pub keys for generating the required p2SHMultiSigOutputScript");
|
||||
}
|
||||
|
||||
Coin msOutput = buyerPayoutAmount.add(sellerPayoutAmount).add(arbitratorPayoutAmount).add(FeePolicy.getFixedTxFeeForTrades());
|
||||
TransactionOutput p2SHMultiSigOutput = new TransactionOutput(params, null, msOutput, p2SHMultiSigOutputScript.getProgram());
|
||||
Transaction depositTx = new Transaction(params);
|
||||
depositTx.addOutput(p2SHMultiSigOutput);
|
||||
|
||||
Transaction payoutTx = new Transaction(params);
|
||||
Sha256Hash spendTxHash = Sha256Hash.wrap(depositTxHex);
|
||||
payoutTx.addInput(new TransactionInput(params, depositTx, p2SHMultiSigOutputScript.getProgram(), new TransactionOutPoint(params, 0, spendTxHash), msOutput));
|
||||
|
||||
if (buyerPayoutAmount.isGreaterThan(Coin.ZERO))
|
||||
payoutTx.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString));
|
||||
if (sellerPayoutAmount.isGreaterThan(Coin.ZERO))
|
||||
payoutTx.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString));
|
||||
if (arbitratorPayoutAmount.isGreaterThan(Coin.ZERO))
|
||||
payoutTx.addOutput(arbitratorPayoutAmount, new Address(params, arbitratorAddressString));
|
||||
|
||||
// take care of sorting!
|
||||
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||
|
||||
ECKey.ECDSASignature tradersSignature;
|
||||
if (buyerPrivateKeyAsHex != null && !buyerPrivateKeyAsHex.isEmpty()) {
|
||||
final ECKey buyerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(buyerPrivateKeyAsHex));
|
||||
checkNotNull(buyerPrivateKey, "buyerPrivateKey must not be null");
|
||||
tradersSignature = buyerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
|
||||
} else {
|
||||
checkNotNull(sellerPrivateKeyAsHex, "sellerPrivateKeyAsHex must not be null");
|
||||
final ECKey sellerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(sellerPrivateKeyAsHex));
|
||||
checkNotNull(sellerPrivateKey, "sellerPrivateKey must not be null");
|
||||
tradersSignature = sellerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
|
||||
}
|
||||
final ECKey key = ECKey.fromPrivate(Utils.HEX.decode(arbitratorPrivateKeyAsHex));
|
||||
checkNotNull(key, "key must not be null");
|
||||
ECKey.ECDSASignature arbitratorSignature = key.sign(sigHash, aesKey).toCanonicalised();
|
||||
|
||||
TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
|
||||
TransactionSignature arbitratorTxSig = new TransactionSignature(arbitratorSignature, Transaction.SigHash.ALL, false);
|
||||
// Take care of order of signatures. See comment below at getMultiSigRedeemScript (sort order needed here: arbitrator, seller, buyer)
|
||||
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(arbitratorTxSig, tradersTxSig), redeemScript);
|
||||
TransactionInput input = payoutTx.getInput(0);
|
||||
input.setScriptSig(inputScript);
|
||||
|
||||
printTxWithInputs("payoutTx", payoutTx);
|
||||
|
||||
verifyTransaction(payoutTx);
|
||||
checkWalletConsistency();
|
||||
|
||||
if (walletAppKit != null) {
|
||||
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(payoutTx).future();
|
||||
Futures.addCallback(future, callback);
|
||||
}
|
||||
|
||||
return payoutTx;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -172,6 +172,7 @@ public class WalletService {
|
|||
|
||||
addressEntryList.onWalletReady(wallet);
|
||||
|
||||
|
||||
walletAppKit.peerGroup().addEventListener(new PeerEventListener() {
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
|
@ -385,7 +386,9 @@ public class WalletService {
|
|||
return "BitcoinJ wallet:\n" +
|
||||
wallet.toString(includePrivKeys, true, true, walletAppKit.chain()) + "\n\n" +
|
||||
"Bitsquare address entry list:\n" +
|
||||
addressEntryListData.toString();
|
||||
addressEntryListData.toString() +
|
||||
"All pubkeys as hex:\n" +
|
||||
wallet.printAllPubKeysAsHex();
|
||||
}
|
||||
|
||||
public void restoreSeedWords(DeterministicSeed seed, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
|
|
|
@ -110,7 +110,7 @@ public abstract class TradeProtocol {
|
|||
stopTimeout();
|
||||
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
log.error("Timeout reached");
|
||||
log.error("Timeout reached. TradeID=" + trade.getId());
|
||||
trade.setErrorMessage("A timeout occurred.");
|
||||
cleanupTradable();
|
||||
cleanup();
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.google.inject.Guice;
|
|||
import com.google.inject.Injector;
|
||||
import io.bitsquare.alert.AlertManager;
|
||||
import io.bitsquare.arbitration.ArbitratorManager;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.CommonOptionKeys;
|
||||
import io.bitsquare.common.UserThread;
|
||||
|
@ -41,10 +42,7 @@ import io.bitsquare.gui.main.MainView;
|
|||
import io.bitsquare.gui.main.MainViewModel;
|
||||
import io.bitsquare.gui.main.debug.DebugView;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.main.overlays.windows.EmptyWalletWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.FilterWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.SendAlertMessageWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.ShowWalletDataWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.*;
|
||||
import io.bitsquare.gui.util.ImageUtil;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
@ -197,27 +195,33 @@ public class BitsquareApp extends Application {
|
|||
stop();
|
||||
});
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEvent -> {
|
||||
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.W, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
|
||||
stop();
|
||||
} else if (new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
|
||||
stop();
|
||||
} else if (new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || new KeyCodeCombination(KeyCode.E, KeyCombination.CONTROL_DOWN).match(keyEvent)) {
|
||||
showEmptyWalletPopup();
|
||||
} else if (new KeyCodeCombination(KeyCode.M, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.M, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
showSendAlertMessagePopup();
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
showFilterPopup();
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
showFPSWindow();
|
||||
} else if (new KeyCodeCombination(KeyCode.J, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.J, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
WalletService walletService = injector.getInstance(WalletService.class);
|
||||
if (walletService.getWallet() != null)
|
||||
new ShowWalletDataWindow(walletService).information("Wallet raw data").show();
|
||||
else
|
||||
new Popup<>().warning("The wallet is not initialized yet").show();
|
||||
} else if (DevFlags.DEV_MODE) {
|
||||
if (new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
|
||||
showDebugWindow();
|
||||
} else if (DevFlags.DEV_MODE && new KeyCodeCombination(KeyCode.G, KeyCombination.ALT_DOWN).match(keyEvent)) {
|
||||
TradeWalletService tradeWalletService = injector.getInstance(TradeWalletService.class);
|
||||
WalletService walletService = injector.getInstance(WalletService.class);
|
||||
if (walletService.getWallet() != null)
|
||||
new SpendFromDepositTxWindow(tradeWalletService).information("Emergency wallet tool").show();
|
||||
else
|
||||
new Popup<>().warning("The wallet is not initialized yet").show();
|
||||
} else if (DevFlags.DEV_MODE && new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) {
|
||||
showDebugWindow();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -256,9 +260,14 @@ public class BitsquareApp extends Application {
|
|||
|
||||
UserThread.runPeriodically(() -> Profiler.printSystemLoad(log), LOG_MEMORY_PERIOD_MIN, TimeUnit.MINUTES);
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
} catch (
|
||||
Throwable throwable
|
||||
)
|
||||
|
||||
{
|
||||
showErrorPopup(throwable, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void showSendAlertMessagePopup() {
|
||||
|
|
|
@ -79,7 +79,7 @@ public class AccountView extends ActivatableView<TabPane, AccountViewModel> {
|
|||
};
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event) &&
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event) &&
|
||||
arbitratorRegistrationTab == null) {
|
||||
arbitratorRegistrationTab = new Tab("Arbitrator registration");
|
||||
arbitratorRegistrationTab.setClosable(false);
|
||||
|
|
|
@ -208,7 +208,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
disputeDirectMessageListListener = c -> scrollToBottom();
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.L, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
if (new KeyCodeCombination(KeyCode.L, KeyCombination.ALT_DOWN).match(event)) {
|
||||
Map<String, List<Dispute>> map = new HashMap<>();
|
||||
disputeManager.getDisputesAsObservableList().stream().forEach(dispute -> {
|
||||
String tradeId = dispute.getTradeId();
|
||||
|
@ -269,14 +269,14 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
.actionButtonText("Copy")
|
||||
.onAction(() -> Utilities.copyToClipboard(message))
|
||||
.show();
|
||||
} else if (new KeyCodeCombination(KeyCode.U, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.U, KeyCombination.ALT_DOWN).match(event)) {
|
||||
// Hidden shortcut to re-open a dispute. Allow it also for traders not only arbitrator.
|
||||
if (selectedDispute != null) {
|
||||
if (selectedDisputeClosedPropertyListener != null)
|
||||
selectedDispute.isClosedProperty().removeListener(selectedDisputeClosedPropertyListener);
|
||||
selectedDispute.setIsClosed(false);
|
||||
}
|
||||
} else if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
} else if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event)) {
|
||||
if (selectedDispute != null) {
|
||||
PubKeyRing pubKeyRing = selectedDispute.getTraderPubKeyRing();
|
||||
NodeAddress nodeAddress;
|
||||
|
|
|
@ -184,9 +184,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
};
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event))
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event))
|
||||
revertTxColumn.setVisible(!revertTxColumn.isVisible());
|
||||
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN).match(event))
|
||||
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.ALT_DOWN).match(event))
|
||||
showStatisticsPopup();
|
||||
};
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ public class PeerInfoWithTagEditor extends Overlay<PeerInfoWithTagEditor> {
|
|||
inputTextField.setText(tag);
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
if (new KeyCodeCombination(KeyCode.R, KeyCombination.ALT_DOWN).match(event)) {
|
||||
new SendPrivateNotificationWindow(offer.getPubKeyRing(), offer.getOffererNodeAddress())
|
||||
.onAddAlertMessage(privateNotificationManager::sendPrivateNotificationMessageIfKeyIsValid)
|
||||
.show();
|
||||
|
|
|
@ -177,7 +177,10 @@ public class ContractWindow extends Overlay<ContractWindow> {
|
|||
viewContractButton.setDefaultButton(false);
|
||||
viewContractButton.setOnAction(e -> {
|
||||
TextArea textArea = new TextArea();
|
||||
textArea.setText(dispute.getContractAsJson());
|
||||
String contractAsJson = dispute.getContractAsJson();
|
||||
contractAsJson += "\n\nBuyerPubKeyHex: " + Utils.HEX.encode(dispute.getContract().getBuyerBtcPubKey());
|
||||
contractAsJson += "\nSellerPubKeyHex: " + Utils.HEX.encode(dispute.getContract().getSellerBtcPubKey());
|
||||
textArea.setText(contractAsJson);
|
||||
textArea.setPrefHeight(50);
|
||||
textArea.setEditable(false);
|
||||
textArea.setWrapText(true);
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* 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.overlays.windows;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
||||
import io.bitsquare.btc.exceptions.WalletException;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.gui.components.InputTextField;
|
||||
import io.bitsquare.gui.main.overlays.Overlay;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static io.bitsquare.gui.util.FormBuilder.addLabelInputTextField;
|
||||
|
||||
public class SpendFromDepositTxWindow extends Overlay<SpendFromDepositTxWindow> {
|
||||
private static final Logger log = LoggerFactory.getLogger(SpendFromDepositTxWindow.class);
|
||||
private TradeWalletService tradeWalletService;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public SpendFromDepositTxWindow(TradeWalletService tradeWalletService) {
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
type = Type.Attention;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (headLine == null)
|
||||
headLine = "Emergency MS payout tool";
|
||||
|
||||
width = 1000;
|
||||
createGridPane();
|
||||
addHeadLine();
|
||||
addSeparator();
|
||||
addContent();
|
||||
addCloseButton();
|
||||
applyStyles();
|
||||
display();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void setupKeyHandler(Scene scene) {
|
||||
if (!hideCloseButton) {
|
||||
scene.setOnKeyPressed(e -> {
|
||||
if (e.getCode() == KeyCode.ESCAPE) {
|
||||
e.consume();
|
||||
doClose();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addContent() {
|
||||
InputTextField depositTxHex = addLabelInputTextField(gridPane, ++rowIndex, "depositTxHex:").second;
|
||||
|
||||
InputTextField buyerPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "buyerPayoutAmount:").second;
|
||||
InputTextField sellerPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "sellerPayoutAmount:").second;
|
||||
InputTextField arbitratorPayoutAmount = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPayoutAmount:").second;
|
||||
|
||||
InputTextField buyerAddressString = addLabelInputTextField(gridPane, ++rowIndex, "buyerAddressString:").second;
|
||||
InputTextField sellerAddressString = addLabelInputTextField(gridPane, ++rowIndex, "sellerAddressString:").second;
|
||||
InputTextField arbitratorAddressString = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorAddressString:").second;
|
||||
|
||||
InputTextField buyerPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "buyerPrivateKeyAsHex:").second;
|
||||
InputTextField sellerPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "sellerPrivateKeyAsHex:").second;
|
||||
InputTextField arbitratorPrivateKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPrivateKeyAsHex:").second;
|
||||
|
||||
InputTextField buyerPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "buyerPubKeyAsHex:").second;
|
||||
InputTextField sellerPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "sellerPubKeyAsHex:").second;
|
||||
InputTextField arbitratorPubKeyAsHex = addLabelInputTextField(gridPane, ++rowIndex, "arbitratorPubKeyAsHex:").second;
|
||||
|
||||
InputTextField P2SHMultiSigOutputScript = addLabelInputTextField(gridPane, ++rowIndex, "P2SHMultiSigOutputScript:").second;
|
||||
InputTextField buyerPubKeysInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "buyerPubKeys:").second;
|
||||
InputTextField sellerPubKeysInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "sellerPubKeys:").second;
|
||||
|
||||
List<String> buyerPubKeys = Arrays.asList(buyerPubKeysInputTextField.getText().split(","));
|
||||
List<String> sellerPubKeys = Arrays.asList(sellerPubKeysInputTextField.getText().split(","));
|
||||
|
||||
/*
|
||||
depositTxHex.setText("");
|
||||
|
||||
buyerPayoutAmount.setText("1.01");
|
||||
sellerPayoutAmount.setText("0.01");
|
||||
arbitratorPayoutAmount.setText("0");
|
||||
|
||||
buyerAddressString.setText("");
|
||||
buyerPubKeyAsHex.setText("");
|
||||
buyerPrivateKeyAsHex.setText("");
|
||||
|
||||
sellerAddressString.setText("");
|
||||
sellerPubKeyAsHex.setText("");
|
||||
sellerPrivateKeyAsHex.setText("");
|
||||
|
||||
arbitratorAddressString.setText("19xdeiQM2Hn2M2wbpT5imcYWzqhiSDHPy4");
|
||||
arbitratorPubKeyAsHex.setText("02c62e794fe67f3a2115e2de4757143ff7f27bdf38aa4ae58a3595baa6d676875b");
|
||||
|
||||
arbitratorAddressString.setText("1FdFzBazmHQxbUbdCUJwuCtR37DrZrEobu");
|
||||
arbitratorPubKeyAsHex.setText("030fdc2ebc297df4047442f6079f1ce3b7d1938a41f88bd11497545cc94fcfd315");
|
||||
|
||||
P2SHMultiSigOutputScript.setText("");
|
||||
|
||||
sellerPubKeys = Arrays.asList();
|
||||
*/
|
||||
|
||||
|
||||
actionButtonText("Sign and publish transaction");
|
||||
|
||||
final List<String> finalSellerPubKeys = sellerPubKeys;
|
||||
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Transaction result) {
|
||||
log.error("onSuccess");
|
||||
UserThread.execute(() -> {
|
||||
String txId = result != null ? result.getHashAsString() : "null";
|
||||
new Popup<>()
|
||||
.information("Transaction successful published. Transaction ID: " + txId)
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error(t.toString());
|
||||
log.error("onFailure");
|
||||
UserThread.execute(() -> new Popup<>().warning(t.toString()).show());
|
||||
}
|
||||
};
|
||||
onAction(() -> {
|
||||
try {
|
||||
tradeWalletService.emergencySignAndPublishPayoutTx(depositTxHex.getText(),
|
||||
Coin.parseCoin(buyerPayoutAmount.getText()),
|
||||
Coin.parseCoin(sellerPayoutAmount.getText()),
|
||||
Coin.parseCoin(arbitratorPayoutAmount.getText()),
|
||||
buyerAddressString.getText(),
|
||||
sellerAddressString.getText(),
|
||||
arbitratorAddressString.getText(),
|
||||
buyerPrivateKeyAsHex.getText(),
|
||||
sellerPrivateKeyAsHex.getText(),
|
||||
arbitratorPrivateKeyAsHex.getText(),
|
||||
buyerPubKeyAsHex.getText(),
|
||||
sellerPubKeyAsHex.getText(),
|
||||
arbitratorPubKeyAsHex.getText(),
|
||||
P2SHMultiSigOutputScript.getText(),
|
||||
buyerPubKeys,
|
||||
finalSellerPubKeys,
|
||||
callback);
|
||||
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
UserThread.execute(() -> new Popup<>().warning(e.toString()).show());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addCloseButton() {
|
||||
super.addCloseButton();
|
||||
actionButton.setOnAction(event -> actionHandlerOptional.ifPresent(Runnable::run));
|
||||
}
|
||||
}
|
|
@ -126,7 +126,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
// we use a hidden emergency shortcut to open support ticket
|
||||
keyEventEventHandler = event -> {
|
||||
if (new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
if (new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN).match(event) || new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN).match(event)) {
|
||||
Popup popup = new Popup();
|
||||
popup.headLine("Open support ticket")
|
||||
.message("Please use that only in emergency case if you don't get displayed a \"Open support\" or \"Open dispute\" button.\n\n" +
|
||||
|
|
Loading…
Add table
Reference in a new issue