mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-06-07 06:32:47 -04:00
Savings wallet, fixed wrong access to trade wallet (WIP)
This commit is contained in:
parent
59b41c7a4f
commit
f07aa9ba6a
8 changed files with 161 additions and 109 deletions
|
@ -24,11 +24,10 @@ import org.bitcoinj.wallet.CoinSelector;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
import java.util.stream.Collectors;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
@ -39,13 +38,100 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
class SavingsWalletCoinSelector implements CoinSelector {
|
class SavingsWalletCoinSelector implements CoinSelector {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SavingsWalletCoinSelector.class);
|
private static final Logger log = LoggerFactory.getLogger(SavingsWalletCoinSelector.class);
|
||||||
protected final NetworkParameters params;
|
protected final NetworkParameters params;
|
||||||
|
@Nullable
|
||||||
|
private AddressEntryList addressEntryList;
|
||||||
|
@Nullable
|
||||||
|
private Set<Address> savingsWalletAddressSet;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public SavingsWalletCoinSelector(NetworkParameters params) {
|
public SavingsWalletCoinSelector(NetworkParameters params, AddressEntryList addressEntryList) {
|
||||||
this.params = params;
|
this.params = params;
|
||||||
|
this.addressEntryList = addressEntryList;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SavingsWalletCoinSelector(NetworkParameters params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean matchesRequirement(TransactionOutput transactionOutput) {
|
||||||
|
if (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash()) {
|
||||||
|
Address addressOutput = transactionOutput.getScriptPubKey().getToAddress(params);
|
||||||
|
log.trace("only lookup in savings wallet address entries");
|
||||||
|
log.trace(addressOutput.toString());
|
||||||
|
|
||||||
|
if (savingsWalletAddressSet != null && savingsWalletAddressSet.contains(addressOutput)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.trace("No match found at matchesRequiredAddress addressOutput / addressEntry " +
|
||||||
|
addressOutput.toString() + " / " + addressOutput.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isInBlockChainOrPending(Transaction tx) {
|
||||||
|
// Pick chain-included transactions and transactions that are pending.
|
||||||
|
TransactionConfidence confidence = tx.getConfidence();
|
||||||
|
TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();
|
||||||
|
|
||||||
|
log.debug("numBroadcastPeers = " + confidence.numBroadcastPeers());
|
||||||
|
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
|
||||||
|
type.equals(TransactionConfidence.ConfidenceType.PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sub-classes can override this to just customize whether transactions are usable, but keep age sorting.
|
||||||
|
*/
|
||||||
|
protected boolean shouldSelect(Transaction tx) {
|
||||||
|
return isInBlockChainOrPending(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
|
||||||
|
log.trace("candidates.size: " + candidates.size());
|
||||||
|
long targetAsLong = target.longValue();
|
||||||
|
log.trace("value needed: " + targetAsLong);
|
||||||
|
HashSet<TransactionOutput> selected = new HashSet<>();
|
||||||
|
// Sort the inputs by age*value so we get the highest "coindays" spent.
|
||||||
|
ArrayList<TransactionOutput> sortedOutputs = new ArrayList<>(candidates);
|
||||||
|
// When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
|
||||||
|
// them in order to improve performance.
|
||||||
|
if (!target.equals(NetworkParameters.MAX_MONEY)) {
|
||||||
|
sortOutputs(sortedOutputs);
|
||||||
|
}
|
||||||
|
// Now iterate over the sorted outputs until we have got as close to the target as possible or a little
|
||||||
|
// bit over (excessive value will be change).
|
||||||
|
long total = 0;
|
||||||
|
if (addressEntryList != null) {
|
||||||
|
savingsWalletAddressSet = addressEntryList.stream()
|
||||||
|
.filter(addressEntry1 -> addressEntry1.getContext() == AddressEntry.Context.SAVINGS)
|
||||||
|
.map(AddressEntry::getAddress)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
for (TransactionOutput output : sortedOutputs) {
|
||||||
|
if (total >= targetAsLong) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Only pick chain-included transactions, or transactions that are ours and pending.
|
||||||
|
// Only select outputs from our defined address(es)
|
||||||
|
if (!shouldSelect(output.getParentTransaction()) || !matchesRequirement(output)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
selected.add(output);
|
||||||
|
total += output.getValue().longValue();
|
||||||
|
|
||||||
|
log.debug("adding up outputs: output/total: " + output.getValue().longValue() + "/" + total);
|
||||||
|
}
|
||||||
|
// Total may be lower than target here, if the given candidates were insufficient to create to requested
|
||||||
|
// transaction.
|
||||||
|
return new CoinSelection(Coin.valueOf(total), selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
@ -71,61 +157,4 @@ class SavingsWalletCoinSelector implements CoinSelector {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInBlockChainOrPending(Transaction tx) {
|
|
||||||
// Pick chain-included transactions and transactions that are pending.
|
|
||||||
TransactionConfidence confidence = tx.getConfidence();
|
|
||||||
TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();
|
|
||||||
|
|
||||||
log.debug("numBroadcastPeers = " + confidence.numBroadcastPeers());
|
|
||||||
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
|
|
||||||
type.equals(TransactionConfidence.ConfidenceType.PENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sub-classes can override this to just customize whether transactions are usable, but keep age sorting.
|
|
||||||
*/
|
|
||||||
protected boolean shouldSelect(Transaction tx) {
|
|
||||||
return isInBlockChainOrPending(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean matchesRequirement(TransactionOutput transactionOutput) {
|
|
||||||
return (transactionOutput.getScriptPubKey().isSentToAddress() || transactionOutput.getScriptPubKey().isPayToScriptHash());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
|
|
||||||
log.trace("candidates.size: " + candidates.size());
|
|
||||||
long targetAsLong = target.longValue();
|
|
||||||
log.trace("value needed: " + targetAsLong);
|
|
||||||
HashSet<TransactionOutput> selected = new HashSet<>();
|
|
||||||
// Sort the inputs by age*value so we get the highest "coindays" spent.
|
|
||||||
ArrayList<TransactionOutput> sortedOutputs = new ArrayList<>(candidates);
|
|
||||||
// When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
|
|
||||||
// them in order to improve performance.
|
|
||||||
if (!target.equals(NetworkParameters.MAX_MONEY)) {
|
|
||||||
sortOutputs(sortedOutputs);
|
|
||||||
}
|
|
||||||
// Now iterate over the sorted outputs until we have got as close to the target as possible or a little
|
|
||||||
// bit over (excessive value will be change).
|
|
||||||
long total = 0;
|
|
||||||
for (TransactionOutput output : sortedOutputs) {
|
|
||||||
if (total >= targetAsLong) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Only pick chain-included transactions, or transactions that are ours and pending.
|
|
||||||
// Only select outputs from our defined address(es)
|
|
||||||
if (!shouldSelect(output.getParentTransaction()) || !matchesRequirement(output)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
selected.add(output);
|
|
||||||
total += output.getValue().longValue();
|
|
||||||
|
|
||||||
log.debug("adding up outputs: output/total: " + output.getValue().longValue() + "/" + total);
|
|
||||||
}
|
|
||||||
// Total may be lower than target here, if the given candidates were insufficient to create to requested
|
|
||||||
// transaction.
|
|
||||||
return new CoinSelection(Coin.valueOf(total), selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,7 @@ public class TradeWalletService {
|
||||||
private WalletAppKit walletAppKit;
|
private WalletAppKit walletAppKit;
|
||||||
@Nullable
|
@Nullable
|
||||||
private KeyParameter aesKey;
|
private KeyParameter aesKey;
|
||||||
|
private AddressEntryList addressEntryList;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -158,7 +159,7 @@ public class TradeWalletService {
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
if (useSavingsWallet)
|
if (useSavingsWallet)
|
||||||
sendRequest.coinSelector = new SavingsWalletCoinSelector(params);
|
sendRequest.coinSelector = new SavingsWalletCoinSelector(params, addressEntryList);
|
||||||
else
|
else
|
||||||
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry);
|
sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry);
|
||||||
// We use a fixed fee
|
// We use a fixed fee
|
||||||
|
@ -1064,4 +1065,8 @@ public class TradeWalletService {
|
||||||
throw new WalletException(t);
|
throw new WalletException(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAddressEntryList(AddressEntryList addressEntryList) {
|
||||||
|
this.addressEntryList = addressEntryList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,6 +188,7 @@ public class WalletService {
|
||||||
|
|
||||||
// set after wallet is ready
|
// set after wallet is ready
|
||||||
tradeWalletService.setWalletAppKit(walletAppKit);
|
tradeWalletService.setWalletAppKit(walletAppKit);
|
||||||
|
tradeWalletService.setAddressEntryList(addressEntryList);
|
||||||
timeoutTimer.stop();
|
timeoutTimer.stop();
|
||||||
|
|
||||||
// onSetupCompleted in walletAppKit is not the called on the last invocations, so we add a bit of delay
|
// onSetupCompleted in walletAppKit is not the called on the last invocations, so we add a bit of delay
|
||||||
|
|
|
@ -205,25 +205,6 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Coin getAmountAsCoin() {
|
|
||||||
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
|
|
||||||
if (!Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
|
|
||||||
senderAmount = Coin.ZERO;
|
|
||||||
/* new Popup()
|
|
||||||
.warning("The amount is lower than the transaction fee and the min. possible tx value (dust).")
|
|
||||||
.show();*/
|
|
||||||
}
|
|
||||||
return senderAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String getBitcoinURI() {
|
|
||||||
return BitcoinURI.convertToBitcoinURI(addressTextField.getAddress(),
|
|
||||||
getAmountAsCoin(),
|
|
||||||
paymentLabel,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
tableView.getSelectionModel().selectedItemProperty().addListener(tableViewSelectionListener);
|
tableView.getSelectionModel().selectedItemProperty().addListener(tableViewSelectionListener);
|
||||||
|
@ -236,6 +217,9 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||||
addressTextField.setAmountAsCoin(formatter.parseToCoin(t));
|
addressTextField.setAmountAsCoin(formatter.parseToCoin(t));
|
||||||
updateQRCode();
|
updateQRCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (tableView.getSelectionModel().getSelectedItem() == null && !sortedList.isEmpty())
|
||||||
|
tableView.getSelectionModel().select(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -309,6 +293,24 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||||
.forEach(e -> observableList.add(new DepositListItem(e, walletService, formatter)));
|
.forEach(e -> observableList.add(new DepositListItem(e, walletService, formatter)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Coin getAmountAsCoin() {
|
||||||
|
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
|
||||||
|
if (!Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
|
||||||
|
senderAmount = Coin.ZERO;
|
||||||
|
/* new Popup()
|
||||||
|
.warning("The amount is lower than the transaction fee and the min. possible tx value (dust).")
|
||||||
|
.show();*/
|
||||||
|
}
|
||||||
|
return senderAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private String getBitcoinURI() {
|
||||||
|
return BitcoinURI.convertToBitcoinURI(addressTextField.getAddress(),
|
||||||
|
getAmountAsCoin(),
|
||||||
|
paymentLabel,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ColumnCellFactories
|
// ColumnCellFactories
|
||||||
|
|
|
@ -228,7 +228,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
calculateVolume();
|
calculateVolume();
|
||||||
calculateTotalToPay();
|
calculateTotalToPay();
|
||||||
updateBalance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTabSelected(boolean isSelected) {
|
void onTabSelected(boolean isSelected) {
|
||||||
|
@ -394,11 +393,13 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateTotalToPay() {
|
void calculateTotalToPay() {
|
||||||
if (securityDepositAsCoin != null) {
|
if (direction != null && amountAsCoin.get() != null) {
|
||||||
Coin feeAndSecDeposit = offerFeeAsCoin.add(networkFeeAsCoin).add(securityDepositAsCoin);
|
Coin feeAndSecDeposit = offerFeeAsCoin.add(networkFeeAsCoin).add(securityDepositAsCoin);
|
||||||
Coin feeAndSecDepositAndAmount = feeAndSecDeposit.add(amountAsCoin.get() == null ? Coin.ZERO : amountAsCoin.get());
|
Coin feeAndSecDepositAndAmount = feeAndSecDeposit.add(amountAsCoin.get());
|
||||||
Coin required = direction == Offer.Direction.BUY ? feeAndSecDeposit : feeAndSecDepositAndAmount;
|
Coin required = direction == Offer.Direction.BUY ? feeAndSecDeposit : feeAndSecDepositAndAmount;
|
||||||
totalToPayAsCoin.set(required);
|
totalToPayAsCoin.set(required);
|
||||||
|
log.debug("totalToPayAsCoin " + totalToPayAsCoin.get().toFriendlyString());
|
||||||
|
updateBalance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,11 +408,12 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
if (useSavingsWallet) {
|
if (useSavingsWallet) {
|
||||||
Coin savingWalletBalance = walletService.getSavingWalletBalance();
|
Coin savingWalletBalance = walletService.getSavingWalletBalance();
|
||||||
totalAvailableBalance = savingWalletBalance.add(tradeWalletBalance);
|
totalAvailableBalance = savingWalletBalance.add(tradeWalletBalance);
|
||||||
|
if (totalToPayAsCoin.get() != null) {
|
||||||
if (totalToPayAsCoin.get() != null && totalAvailableBalance.compareTo(totalToPayAsCoin.get()) > 0)
|
if (totalAvailableBalance.compareTo(totalToPayAsCoin.get()) > 0)
|
||||||
balance.set(totalToPayAsCoin.get());
|
balance.set(totalToPayAsCoin.get());
|
||||||
else
|
else
|
||||||
balance.set(totalAvailableBalance);
|
balance.set(totalAvailableBalance);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
balance.set(tradeWalletBalance);
|
balance.set(tradeWalletBalance);
|
||||||
}
|
}
|
||||||
|
@ -422,6 +424,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
missingCoin.set(Coin.ZERO);
|
missingCoin.set(Coin.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug("missingCoin " + missingCoin.get().toFriendlyString());
|
||||||
|
|
||||||
isWalletFunded.set(isBalanceSufficient(balance.get()));
|
isWalletFunded.set(isBalanceSufficient(balance.get()));
|
||||||
if (totalToPayAsCoin.get() != null && isWalletFunded.get() && walletFundedNotification == null) {
|
if (totalToPayAsCoin.get() != null && isWalletFunded.get() && walletFundedNotification == null) {
|
||||||
walletFundedNotification = new Notification()
|
walletFundedNotification = new Notification()
|
||||||
|
|
|
@ -176,7 +176,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
calculateVolume();
|
calculateVolume();
|
||||||
calculateTotalToPay();
|
calculateTotalToPay();
|
||||||
updateBalance();
|
|
||||||
|
|
||||||
balanceListener = new BalanceListener(addressEntry.getAddress()) {
|
balanceListener = new BalanceListener(addressEntry.getAddress()) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -325,11 +324,21 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setAmount(Coin amount) {
|
||||||
|
amountAsCoin.set(amount);
|
||||||
|
calculateTotalToPay();
|
||||||
|
}
|
||||||
|
|
||||||
void calculateTotalToPay() {
|
void calculateTotalToPay() {
|
||||||
if (getDirection() == Offer.Direction.SELL)
|
if (offer != null && amountAsCoin.get() != null) {
|
||||||
totalToPayAsCoin.set(takerFeeAsCoin.add(networkFeeAsCoin).add(securityDepositAsCoin));
|
if (getDirection() == Offer.Direction.SELL)
|
||||||
else
|
totalToPayAsCoin.set(takerFeeAsCoin.add(networkFeeAsCoin).add(securityDepositAsCoin));
|
||||||
totalToPayAsCoin.set(takerFeeAsCoin.add(networkFeeAsCoin).add(securityDepositAsCoin).add(amountAsCoin.get()));
|
else
|
||||||
|
totalToPayAsCoin.set(takerFeeAsCoin.add(networkFeeAsCoin).add(securityDepositAsCoin).add(amountAsCoin.get()));
|
||||||
|
|
||||||
|
updateBalance();
|
||||||
|
log.debug("totalToPayAsCoin " + totalToPayAsCoin.get().toFriendlyString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBalance() {
|
void updateBalance() {
|
||||||
|
@ -337,11 +346,12 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
if (useSavingsWallet) {
|
if (useSavingsWallet) {
|
||||||
Coin savingWalletBalance = walletService.getSavingWalletBalance();
|
Coin savingWalletBalance = walletService.getSavingWalletBalance();
|
||||||
totalAvailableBalance = savingWalletBalance.add(tradeWalletBalance);
|
totalAvailableBalance = savingWalletBalance.add(tradeWalletBalance);
|
||||||
|
if (totalToPayAsCoin.get() != null) {
|
||||||
if (totalToPayAsCoin.get() != null && totalAvailableBalance.compareTo(totalToPayAsCoin.get()) > 0)
|
if (totalAvailableBalance.compareTo(totalToPayAsCoin.get()) > 0)
|
||||||
balance.set(totalToPayAsCoin.get());
|
balance.set(totalToPayAsCoin.get());
|
||||||
else
|
else
|
||||||
balance.set(totalAvailableBalance);
|
balance.set(totalAvailableBalance);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
balance.set(tradeWalletBalance);
|
balance.set(tradeWalletBalance);
|
||||||
}
|
}
|
||||||
|
@ -350,17 +360,18 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
if (missingCoin.get().isNegative())
|
if (missingCoin.get().isNegative())
|
||||||
missingCoin.set(Coin.ZERO);
|
missingCoin.set(Coin.ZERO);
|
||||||
}
|
}
|
||||||
|
log.debug("missingCoin " + missingCoin.get().toFriendlyString());
|
||||||
|
|
||||||
isWalletFunded.set(isBalanceSufficient(balance.get()));
|
isWalletFunded.set(isBalanceSufficient(balance.get()));
|
||||||
if (totalToPayAsCoin.get() != null && isWalletFunded.get() && walletFundedNotification == null) {
|
if (totalToPayAsCoin.get() != null && isWalletFunded.get() && walletFundedNotification == null) {
|
||||||
walletFundedNotification = new Notification()
|
walletFundedNotification = new Notification()
|
||||||
.headLine("Trading wallet update")
|
.headLine("Trading wallet update")
|
||||||
.notification("Your trading wallet is sufficiently funded.\n" +
|
.notification("Your trading wallet is sufficiently funded.\n" +
|
||||||
"Amount: " + formatter.formatCoinWithCode(totalToPayAsCoin.get()))
|
"Amount: " + formatter.formatCoinWithCode(totalToPayAsCoin.get()))
|
||||||
.autoClose();
|
.autoClose();
|
||||||
|
|
||||||
walletFundedNotification.show();
|
walletFundedNotification.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBalanceSufficient(Coin balance) {
|
private boolean isBalanceSufficient(Coin balance) {
|
||||||
|
|
|
@ -520,7 +520,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAmountToModel() {
|
private void setAmountToModel() {
|
||||||
dataModel.amountAsCoin.set(formatter.parseToCoinWith4Decimals(amount.get()));
|
dataModel.setAmount(formatter.parseToCoinWith4Decimals(amount.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ public class SellerStep3View extends TradeStepView {
|
||||||
if (model.p2PService.isBootstrapped()) {
|
if (model.p2PService.isBootstrapped()) {
|
||||||
Preferences preferences = model.dataModel.preferences;
|
Preferences preferences = model.dataModel.preferences;
|
||||||
String key = "confirmPaymentReceived";
|
String key = "confirmPaymentReceived";
|
||||||
if (preferences.showAgain(key)) {
|
if (!BitsquareApp.DEV_MODE && preferences.showAgain(key)) {
|
||||||
new Popup()
|
new Popup()
|
||||||
.headLine("Confirm that you have received the payment")
|
.headLine("Confirm that you have received the payment")
|
||||||
.confirmation("Have you received the " + CurrencyUtil.getNameByCode(model.dataModel.getCurrencyCode()) +
|
.confirmation("Have you received the " + CurrencyUtil.getNameByCode(model.dataModel.getCurrencyCode()) +
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue