Move password check at startup before init rest of app. cleanup, wording improvements

This commit is contained in:
Manfred Karrer 2016-04-07 01:45:48 +02:00
parent cc46a81644
commit 5af70848a7
16 changed files with 142 additions and 114 deletions

View file

@ -383,11 +383,6 @@ public class WalletService {
return ImmutableList.copyOf(addressEntryList); return ImmutableList.copyOf(addressEntryList);
} }
public void swapTradeToSavings(String offerId) {
getOrCreateAddressEntry(offerId, AddressEntry.Context.OFFER_FUNDING);
addressEntryList.swapTradeToSavings(offerId);
}
public void swapTradeEntryToAvailableEntry(String offerId, AddressEntry.Context context) { public void swapTradeEntryToAvailableEntry(String offerId, AddressEntry.Context context) {
Optional<AddressEntry> addressEntryOptional = getAddressEntryListAsImmutableList().stream() Optional<AddressEntry> addressEntryOptional = getAddressEntryListAsImmutableList().stream()
.filter(e -> offerId.equals(e.getOfferId())) .filter(e -> offerId.equals(e.getOfferId()))

View file

@ -58,9 +58,9 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
@JsonExclude @JsonExclude
private static final Logger log = LoggerFactory.getLogger(Offer.class); private static final Logger log = LoggerFactory.getLogger(Offer.class);
public static final long TTL = TimeUnit.SECONDS.toMillis(4 * 60); public static final long TTL = TimeUnit.SECONDS.toMillis(4 * 60);
public final static String TAC_OFFERER = "With placing that offer I accept to trade " + public final static String TAC_OFFERER = "With placing that offer I agree to trade " +
"with anyone who fulfills the conditions as defined above."; "with any trader who fulfills the conditions as defined above.";
public static final String TAC_TAKER = "With taking that offer I commit to the trade conditions as defined above."; public static final String TAC_TAKER = "With taking that offer I agree to the trade conditions as defined above.";
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -76,7 +76,7 @@ import static io.bitsquare.app.BitsquareEnvironment.APP_NAME_KEY;
public class BitsquareApp extends Application { public class BitsquareApp extends Application {
private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BitsquareApp.class); private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BitsquareApp.class);
public static final boolean DEV_MODE = true; public static final boolean DEV_MODE = false;
public static final boolean IS_RELEASE_VERSION = !DEV_MODE && true; public static final boolean IS_RELEASE_VERSION = !DEV_MODE && true;
private static Environment env; private static Environment env;

View file

@ -409,6 +409,26 @@ public class MainViewModel implements ViewModel {
} }
private void onAllServicesInitialized() { private void onAllServicesInitialized() {
// In case we have any offers open or a pending trade we need to unlock our trading wallet so a trade can be executed automatically
// Otherwise we delay the password request to create offer, or take offer.
// When the password is set it will be stored to the tradeWalletService as well, so its only needed after a restart.
if (walletService.getWallet().isEncrypted() &&
(openOfferManager.getOpenOffers().size() > 0
|| tradeManager.getTrades().size() > 0
|| disputeManager.getDisputesAsObservableList().size() > 0)) {
walletPasswordWindow
.onAesKey(aesKey -> {
tradeWalletService.setAesKey(aesKey);
onAllServicesInitializedAndUnlocked();
})
.hideCloseButton()
.show();
} else {
onAllServicesInitializedAndUnlocked();
}
}
private void onAllServicesInitializedAndUnlocked() {
Log.traceCall(); Log.traceCall();
clock.start(); clock.start();
@ -435,15 +455,6 @@ public class MainViewModel implements ViewModel {
}); });
// walletService // walletService
// In case we have any offers open or a pending trade we need to unlock our trading wallet so a trade can be executed automatically
// Otherwise we delay the password request to create offer, or take offer.
// When the password is set it will be stored to the tradeWalletService as well, so its only needed after a restart.
if (walletService.getWallet().isEncrypted() &&
(openOfferManager.getOpenOffers().size() > 0
|| tradeManager.getTrades().size() > 0
|| disputeManager.getDisputesAsObservableList().size() > 0)) {
walletPasswordWindow.onAesKey(aesKey -> tradeWalletService.setAesKey(aesKey)).show();
}
walletService.addBalanceListener(new BalanceListener() { walletService.addBalanceListener(new BalanceListener() {
@Override @Override
public void onBalanceChanged(Coin balance, Transaction tx) { public void onBalanceChanged(Coin balance, Transaction tx) {
@ -463,6 +474,7 @@ public class MainViewModel implements ViewModel {
updateBalance(); updateBalance();
setupDevDummyPaymentAccount(); setupDevDummyPaymentAccount();
setupMarketPriceFeed(); setupMarketPriceFeed();
swapPendingOfferFundingEntries();
showAppScreen.set(true); showAppScreen.set(true);
@ -677,6 +689,12 @@ public class MainViewModel implements ViewModel {
} }
} }
private void swapPendingOfferFundingEntries() {
tradeManager.getAddressEntriesForAvailableBalanceStream()
.filter(addressEntry -> addressEntry.getOfferId() != null)
.forEach(addressEntry -> walletService.swapTradeEntryToAvailableEntry(addressEntry.getOfferId(), AddressEntry.Context.OFFER_FUNDING));
}
private void updateBalance() { private void updateBalance() {
updateAvailableBalance(); updateAvailableBalance();
updateReservedBalance(); updateReservedBalance();

View file

@ -147,7 +147,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
" withdrawing bitcoin out of your wallet or " + " withdrawing bitcoin out of your wallet or " +
"if you want to view or restore a wallet from seed words.\n" + "if you want to view or restore a wallet from seed words.\n" +
"For the transactions used in the trade process we don't support password protection as that would make automatic offer " + "For the transactions used in the trade process we don't support password protection as that would make automatic offer " +
"execution impossible.", "execution impossible, but you need to provide the password at application startup if you have open offer, trades or disputes.",
Layout.FIRST_ROW_AND_GROUP_DISTANCE); Layout.FIRST_ROW_AND_GROUP_DISTANCE);
} }

View file

@ -91,6 +91,7 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
addTitledGroupBg(root, gridRow, 2, "Backup your wallet seed words"); addTitledGroupBg(root, gridRow, 2, "Backup your wallet seed words");
displaySeedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_DISTANCE).second; displaySeedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_DISTANCE).second;
displaySeedWordsTextArea.setPrefHeight(60); displaySeedWordsTextArea.setPrefHeight(60);
displaySeedWordsTextArea.setEditable(false);
datePicker = addLabelDatePicker(root, ++gridRow, "Creation Date:").second; datePicker = addLabelDatePicker(root, ++gridRow, "Creation Date:").second;
datePicker.setMouseTransparent(true); datePicker.setMouseTransparent(true);

View file

@ -240,19 +240,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
if (item != null && !empty) { if (item != null && !empty) {
Optional<Tradable> tradableOptional = getTradable(item); Optional<Tradable> tradableOptional = getTradable(item);
if (tradableOptional.isPresent()) { if (tradableOptional.isPresent()) {
AddressEntry addressEntry = item.getAddressEntry(); field = new HyperlinkWithIcon("Locked in MultiSig for trade with ID: " + item.getAddressEntry().getShortOfferId(),
String details;
if (addressEntry.isTrade()) {
details = "Trade ID: " + addressEntry.getShortOfferId();
} else if (addressEntry.isOpenOffer()) {
details = "Offer ID: " + addressEntry.getShortOfferId();
} else if (addressEntry.getContext() == AddressEntry.Context.ARBITRATOR) {
details = "Arbitration fee";
} else {
details = "-";
}
field = new HyperlinkWithIcon("Locked in trade with ID: " + details + " (MultiSig)",
AwesomeIcon.INFO_SIGN); AwesomeIcon.INFO_SIGN);
field.setOnAction(event -> openDetailPopup(item)); field.setOnAction(event -> openDetailPopup(item));
field.setTooltip(new Tooltip("Open popup for details")); field.setTooltip(new Tooltip("Open popup for details"));

View file

@ -240,19 +240,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
if (item != null && !empty) { if (item != null && !empty) {
Optional<Tradable> tradableOptional = getTradable(item); Optional<Tradable> tradableOptional = getTradable(item);
if (tradableOptional.isPresent()) { if (tradableOptional.isPresent()) {
AddressEntry addressEntry = item.getAddressEntry(); field = new HyperlinkWithIcon("Reserved in local wallet for offer with ID: " + item.getAddressEntry().getShortOfferId(),
String details;
if (addressEntry.isTrade()) {
details = "Trade ID: " + addressEntry.getShortOfferId();
} else if (addressEntry.isOpenOffer()) {
details = "Offer ID: " + addressEntry.getShortOfferId();
} else if (addressEntry.getContext() == AddressEntry.Context.ARBITRATOR) {
details = "Arbitration fee";
} else {
details = "-";
}
field = new HyperlinkWithIcon("Reserved in offer with ID: " + details + " (local wallet)",
AwesomeIcon.INFO_SIGN); AwesomeIcon.INFO_SIGN);
field.setOnAction(event -> openDetailPopup(item)); field.setOnAction(event -> openDetailPopup(item));
field.setTooltip(new Tooltip("Open popup for details")); field.setTooltip(new Tooltip("Open popup for details"));

View file

@ -290,17 +290,28 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
.show(); .show();
key = "createOfferFundWalletInfo"; key = "createOfferFundWalletInfo";
String tradeAmountText = model.isSellOffer() ? "the trade amount, " : ""; String tradeAmountText = model.isSellOffer() ? "- Trade amount: " + model.tradeAmount.get() + "\n" : "";
new Popup().headLine("Fund your trading wallet").instruction("You need to pay in " +
model.totalToPay.get() + " to your local Bitsquare trading wallet.\n" + new Popup().headLine("Fund your offer").instruction("You need to deposit " +
"The amount is the sum of " + tradeAmountText + "the security deposit, the trading fee and " + model.totalToPay.get() + " to this offer.\n\n" +
"the bitcoin mining fee.\n\n" +
"You can choose between 2 options:\n" + "Those funds are reserved in your local wallet and will get locked into the Multisig " +
"Either you transfer from your Bitsquare wallet the funds or if you prefer better privacy by " + "deposit address once someone takes your offer.\n\n" +
"separating all trade transactions you can send from your external Bitcoin wallet the exact amount to the address: " +
model.getAddressAsString() + "\n" + "The amount is the sum of:\n" +
"(you can copy the address in the screen below after closing that popup)\n\n" + tradeAmountText +
"You can see the status of your incoming payment and all the details in the screen below.") "- Security deposit: " + model.getSecurityDeposit() + "\n" +
"- Trading fee: " + model.getOfferFee() + "\n" +
"- Bitcoin mining fee: " + model.getNetworkFee() + "\n\n" +
"For funding you can choose between 2 options:\n" +
"- Transfer fund from your Bitsquare wallet OR\n" +
"- Transfer fund from any external wallet\n\n" +
"If you prefer a higher level of privacy you should use for each trade a distinct funding transaction using the external wallet option.\n" +
"If you prefer convenience using the Bitsquare wallet for several trades might be your preferred option.\n\n" +
"You can see all the details for funding when you close that popup.")
.dontShowAgainId(key, preferences) .dontShowAgainId(key, preferences)
.show(); .show();
} }

View file

@ -302,18 +302,24 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
.show(); .show();
key = "takeOfferFundWalletInfo"; key = "takeOfferFundWalletInfo";
String tradeAmountText = model.isSeller() ? "the trade amount, " : ""; String tradeAmountText = model.isSeller() ? "- Trade amount: " + model.getAmount() + "\n" : "";
new Popup().headLine("Fund your trading wallet") new Popup().headLine("Fund your trade").instruction("You need to deposit " +
.instruction("You need to pay in " + model.totalToPay.get() + " for taking this offer.\n\n" +
model.totalToPay.get() + " to your local Bitsquare trading wallet.\n" +
"The amount is the sum of " + tradeAmountText + "the security deposit, the trading fee and " + "The amount is the sum of:\n" +
"the bitcoin mining fee.\n\n" + tradeAmountText +
"You can choose between 2 options:\n" + "- Security deposit: " + model.getSecurityDeposit() + "\n" +
"Either you transfer from your Bitsquare wallet the funds or if you prefer better privacy by " + "- Trading fee: " + model.getTakerFee() + "\n" +
"separating all trade transactions you can send from your external Bitcoin wallet the exact amount to the address: " + "- Bitcoin mining fee: " + model.getNetworkFee() + "\n\n" +
model.dataModel.getAddressEntry().getAddressString() + "\n" +
"(you can copy the address in the screen below after closing that popup)\n\n" + "For funding you can choose between 2 options:\n" +
"You can see the status of your incoming payment and all the details in the screen below.") "- Transfer fund from your Bitsquare wallet OR\n" +
"- Transfer fund from any external wallet\n\n" +
"If you prefer a higher level of privacy you should use for each trade a distinct funding transaction using the external wallet option.\n" +
"If you prefer convenience using the Bitsquare wallet for several trades might be your preferred option.\n\n" +
"You can see all the details for funding when you close that popup.")
.dontShowAgainId(key, preferences) .dontShowAgainId(key, preferences)
.show(); .show();
} }

View file

@ -57,6 +57,7 @@ import static io.bitsquare.gui.util.FormBuilder.addCheckBox;
public abstract class Overlay<T extends Overlay> { public abstract class Overlay<T extends Overlay> {
protected final Logger log = LoggerFactory.getLogger(this.getClass()); protected final Logger log = LoggerFactory.getLogger(this.getClass());
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Enum // Enum
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -128,6 +129,7 @@ public abstract class Overlay<T extends Overlay> {
protected Timer centerTime; protected Timer centerTime;
protected double buttonDistance = 20; protected double buttonDistance = 20;
protected Type type = Type.Undefined; protected Type type = Type.Undefined;
protected boolean hideCloseButton;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -334,6 +336,11 @@ public abstract class Overlay<T extends Overlay> {
return (T) this; return (T) this;
} }
public T hideCloseButton() {
this.hideCloseButton = true;
return (T) this;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Protected // Protected
@ -715,7 +722,7 @@ public abstract class Overlay<T extends Overlay> {
GridPane.setColumnSpan(hBox, 2); GridPane.setColumnSpan(hBox, 2);
GridPane.setMargin(hBox, new Insets(buttonDistance, 0, 0, 0)); GridPane.setMargin(hBox, new Insets(buttonDistance, 0, 0, 0));
gridPane.getChildren().add(hBox); gridPane.getChildren().add(hBox);
} else { } else if (!hideCloseButton) {
closeButton.setDefaultButton(true); closeButton.setDefaultButton(true);
GridPane.setHalignment(closeButton, HPos.RIGHT); GridPane.setHalignment(closeButton, HPos.RIGHT);
if (!showReportErrorButtons) if (!showReportErrorButtons)

View file

@ -84,7 +84,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
rowIndex = -1; rowIndex = -1;
width = 850; width = 900;
createGridPane(); createGridPane();
addContent(); addContent();
display(); display();
@ -93,7 +93,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
public void show(Offer offer) { public void show(Offer offer) {
this.offer = offer; this.offer = offer;
rowIndex = -1; rowIndex = -1;
width = 850; width = 900;
createGridPane(); createGridPane();
addContent(); addContent();
display(); display();
@ -222,7 +222,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
if (placeOfferHandlerOptional.isPresent()) { if (placeOfferHandlerOptional.isPresent()) {
addTitledGroupBg(gridPane, ++rowIndex, 1, "Commitment", Layout.GROUP_DISTANCE); addTitledGroupBg(gridPane, ++rowIndex, 1, "Commitment", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Please note:", Offer.TAC_OFFERER, Layout.FIRST_ROW_AND_GROUP_DISTANCE); addLabelTextField(gridPane, rowIndex, "I agree:", Offer.TAC_OFFERER, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addConfirmAndCancelButtons(true); addConfirmAndCancelButtons(true);
} else if (takeOfferHandlerOptional.isPresent()) { } else if (takeOfferHandlerOptional.isPresent()) {

View file

@ -92,7 +92,6 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
display(); display();
} }
public WalletPasswordWindow onAesKey(AesKeyHandler aesKeyHandler) { public WalletPasswordWindow onAesKey(AesKeyHandler aesKeyHandler) {
this.aesKeyHandler = aesKeyHandler; this.aesKeyHandler = aesKeyHandler;
return this; return this;
@ -137,7 +136,10 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
hBox.setSpacing(10); hBox.setSpacing(10);
GridPane.setRowIndex(hBox, ++rowIndex); GridPane.setRowIndex(hBox, ++rowIndex);
GridPane.setColumnIndex(hBox, 1); GridPane.setColumnIndex(hBox, 1);
hBox.getChildren().addAll(unlockButton, cancelButton); if (hideCloseButton)
hBox.getChildren().add(unlockButton);
else
hBox.getChildren().addAll(unlockButton, cancelButton);
gridPane.getChildren().add(hBox); gridPane.getChildren().add(hBox);
} }

View file

@ -71,7 +71,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
private final KeyRing keyRing; private final KeyRing keyRing;
public final DisputeManager disputeManager; public final DisputeManager disputeManager;
public final Navigation navigation; public final Navigation navigation;
private final WalletPasswordWindow walletPasswordWindow; public final WalletPasswordWindow walletPasswordWindow;
private final NotificationCenter notificationCenter; private final NotificationCenter notificationCenter;
final ObservableList<PendingTradesListItem> list = FXCollections.observableArrayList(); final ObservableList<PendingTradesListItem> list = FXCollections.observableArrayList();
@ -147,12 +147,26 @@ public class PendingTradesDataModel extends ActivatableDataModel {
((SellerTrade) getTrade()).onFiatPaymentReceived(resultHandler, errorMessageHandler); ((SellerTrade) getTrade()).onFiatPaymentReceived(resultHandler, errorMessageHandler);
} }
public void onWithdrawRequest(String toAddress, Coin receiverAmount, ResultHandler resultHandler, FaultHandler faultHandler) { public void onWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) {
checkNotNull(getTrade(), "trade must not be null"); checkNotNull(getTrade(), "trade must not be null");
if (walletService.getWallet().isEncrypted()) {
walletPasswordWindow.onAesKey(aesKey -> doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler)).show(); if (toAddress != null && toAddress.length() > 0) {
} else tradeManager.onWithdrawRequest(
doWithdrawRequest(toAddress, receiverAmount, null, resultHandler, faultHandler); toAddress,
receiverAmount,
aesKey,
getTrade(),
() -> {
resultHandler.handleResult();
selectBestItem();
},
(errorMessage, throwable) -> {
log.error(errorMessage);
faultHandler.handleFault(errorMessage, throwable);
});
} else {
faultHandler.handleFault("No receiver address defined", null);
}
} }
public void onOpenDispute() { public void onOpenDispute() {
@ -279,26 +293,6 @@ public class PendingTradesDataModel extends ActivatableDataModel {
selectedItemProperty.set(item); selectedItemProperty.set(item);
} }
private void doWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) {
if (toAddress != null && toAddress.length() > 0) {
tradeManager.onWithdrawRequest(
toAddress,
receiverAmount,
aesKey,
getTrade(),
() -> {
resultHandler.handleResult();
selectBestItem();
},
(errorMessage, throwable) -> {
log.error(errorMessage);
faultHandler.handleFault(errorMessage, throwable);
});
} else {
faultHandler.handleFault("No receiver address defined", null);
}
}
private void tryOpenDispute(boolean isSupportTicket) { private void tryOpenDispute(boolean isSupportTicket) {
if (getTrade() != null) { if (getTrade() != null) {
Transaction depositTx = getTrade().getDepositTx(); Transaction depositTx = getTrade().getDepositTx();

View file

@ -23,6 +23,8 @@ import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException; import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.components.InputTextField; import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
@ -43,6 +45,7 @@ import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.spongycastle.crypto.params.KeyParameter;
import static io.bitsquare.gui.util.FormBuilder.*; import static io.bitsquare.gui.util.FormBuilder.*;
@ -150,7 +153,7 @@ public class BuyerStep5View extends TradeStepView {
if (!BitsquareApp.DEV_MODE && preferences.showAgain(key)) { if (!BitsquareApp.DEV_MODE && preferences.showAgain(key)) {
preferences.dontShowAgain(key, true); preferences.dontShowAgain(key, true);
new Notification().headLine("Trade completed") new Notification().headLine("Trade completed")
.notification("You can withdraw your funds now to your external Bitcoin wallet.") .notification("You can withdraw your funds now to your external Bitcoin wallet or transfer it to the Bitsquare wallet.")
.autoClose() .autoClose()
.show(); .show();
} }
@ -222,18 +225,33 @@ public class BuyerStep5View extends TradeStepView {
private void doWithdrawal(Coin receiverAmount) { private void doWithdrawal(Coin receiverAmount) {
useSavingsWalletButton.setDisable(true); useSavingsWalletButton.setDisable(true);
withdrawToExternalWalletButton.setDisable(true); withdrawToExternalWalletButton.setDisable(true);
String toAddress = withdrawAddressTextField.getText();
ResultHandler resultHandler = this::handleTradeCompleted;
FaultHandler faultHandler = (errorMessage, throwable) -> {
useSavingsWalletButton.setDisable(false);
withdrawToExternalWalletButton.setDisable(false);
if (throwable != null && throwable.getMessage() != null)
new Popup().error(errorMessage + "\n\n" + throwable.getMessage()).show();
else
new Popup().error(errorMessage).show();
};
if (model.dataModel.walletService.getWallet().isEncrypted()) {
model.dataModel.walletPasswordWindow.onAesKey(aesKey -> doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler))
.onClose(() -> {
useSavingsWalletButton.setDisable(false);
withdrawToExternalWalletButton.setDisable(false);
})
.show();
} else
doWithdrawRequest(toAddress, receiverAmount, null, resultHandler, faultHandler);
}
model.dataModel.onWithdrawRequest(withdrawAddressTextField.getText(), private void doWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) {
model.dataModel.onWithdrawRequest(toAddress,
receiverAmount, receiverAmount,
this::handleTradeCompleted, aesKey,
(errorMessage, throwable) -> { resultHandler,
useSavingsWalletButton.setDisable(false); faultHandler);
withdrawToExternalWalletButton.setDisable(false);
if (throwable != null && throwable.getMessage() != null)
new Popup().error(errorMessage + "\n\n" + throwable.getMessage()).show();
else
new Popup().error(errorMessage).show();
});
} }
private void handleTradeCompleted() { private void handleTradeCompleted() {

View file

@ -49,7 +49,7 @@ createOffer.amountPriceBox.error.message=An error occurred when placing the offe
createOffer.validation.amountSmallerThanMinAmount=Amount cannot be smaller than minimum amount. createOffer.validation.amountSmallerThanMinAmount=Amount cannot be smaller than minimum amount.
createOffer.validation.minAmountLargerThanAmount=Minimum amount cannot be larger than amount. createOffer.validation.minAmountLargerThanAmount=Minimum amount cannot be larger than amount.
createOffer.fundsBox.title=Fund your trade wallet createOffer.fundsBox.title=Fund your offer
createOffer.fundsBox.totalsNeeded=Funds needed: createOffer.fundsBox.totalsNeeded=Funds needed:
createOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above createOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above
createOffer.fundsBox.address=Trade wallet address: createOffer.fundsBox.address=Trade wallet address:
@ -103,7 +103,7 @@ takeOffer.validation.amountSmallerThanMinAmount=Amount cannot be smaller than mi
takeOffer.validation.amountLargerThanOfferAmount=Input amount cannot be higher than the amount defined in the offer. takeOffer.validation.amountLargerThanOfferAmount=Input amount cannot be higher than the amount defined in the offer.
takeOffer.validation.amountLargerThanOfferAmountMinusFee=That input amount would create a dust change for the seller. takeOffer.validation.amountLargerThanOfferAmountMinusFee=That input amount would create a dust change for the seller.
takeOffer.fundsBox.title=Fund your trade wallet takeOffer.fundsBox.title=Fund your trade
takeOffer.fundsBox.isOfferAvailable=Check if offer is available... takeOffer.fundsBox.isOfferAvailable=Check if offer is available...
takeOffer.fundsBox.totalsNeeded=Funds needed: takeOffer.fundsBox.totalsNeeded=Funds needed:
takeOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above takeOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above