mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-25 23:39:26 -05:00
show reserved amount in maker's offer details
This commit is contained in:
parent
e63141279c
commit
94ab3c1f9b
@ -282,12 +282,18 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
|||||||
// Getter
|
// Getter
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// get the amount needed for the maker to reserve the offer
|
// amount needed for the maker to reserve the offer
|
||||||
public BigInteger getReserveAmount() {
|
public BigInteger getAmountNeeded() {
|
||||||
BigInteger reserveAmount = getDirection() == OfferDirection.BUY ? getMaxBuyerSecurityDeposit() : getMaxSellerSecurityDeposit();
|
BigInteger amountNeeded = getDirection() == OfferDirection.BUY ? getMaxBuyerSecurityDeposit() : getMaxSellerSecurityDeposit();
|
||||||
if (getDirection() == OfferDirection.SELL) reserveAmount = reserveAmount.add(getAmount());
|
if (getDirection() == OfferDirection.SELL) amountNeeded = amountNeeded.add(getAmount());
|
||||||
reserveAmount = reserveAmount.add(getMaxMakerFee());
|
amountNeeded = amountNeeded.add(getMaxMakerFee());
|
||||||
return reserveAmount;
|
return amountNeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
// amount reserved for offer
|
||||||
|
public BigInteger getReservedAmount() {
|
||||||
|
if (offerPayload.getReserveTxKeyImages() == null) return null;
|
||||||
|
return HavenoUtils.xmrWalletService.getOutputsAmount(offerPayload.getReserveTxKeyImages());
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigInteger getMaxMakerFee() {
|
public BigInteger getMaxMakerFee() {
|
||||||
|
@ -879,8 +879,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get offer reserve amount
|
// get amount needed to reserve offer
|
||||||
BigInteger offerReserveAmount = openOffer.getOffer().getReserveAmount();
|
BigInteger amountNeeded = openOffer.getOffer().getAmountNeeded();
|
||||||
|
|
||||||
// handle split output offer
|
// handle split output offer
|
||||||
if (openOffer.isReserveExactAmount()) {
|
if (openOffer.isReserveExactAmount()) {
|
||||||
@ -889,13 +889,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
MoneroTxWallet splitOutputTx = findSplitOutputFundingTx(openOffers, openOffer);
|
MoneroTxWallet splitOutputTx = findSplitOutputFundingTx(openOffers, openOffer);
|
||||||
if (splitOutputTx != null && openOffer.getScheduledTxHashes() == null) {
|
if (splitOutputTx != null && openOffer.getScheduledTxHashes() == null) {
|
||||||
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
||||||
openOffer.setScheduledAmount(offerReserveAmount.toString());
|
openOffer.setScheduledAmount(amountNeeded.toString());
|
||||||
openOffer.setState(OpenOffer.State.SCHEDULED);
|
openOffer.setState(OpenOffer.State.SCHEDULED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not found, create tx to split exact output
|
// if not found, create tx to split exact output
|
||||||
if (splitOutputTx == null) {
|
if (splitOutputTx == null) {
|
||||||
splitOrSchedule(openOffers, openOffer, offerReserveAmount);
|
splitOrSchedule(openOffers, openOffer, amountNeeded);
|
||||||
} else if (!splitOutputTx.isLocked()) {
|
} else if (!splitOutputTx.isLocked()) {
|
||||||
|
|
||||||
// otherwise sign and post offer if split output available
|
// otherwise sign and post offer if split output available
|
||||||
@ -905,7 +905,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
if (openOffer.getSplitOutputTxHash() == null) {
|
if (openOffer.getSplitOutputTxHash() == null) {
|
||||||
int offerSubaddress = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).getSubaddressIndex();
|
int offerSubaddress = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).getSubaddressIndex();
|
||||||
log.warn("Splitting new output because spending scheduled output(s) failed for offer {}. Offer funding subadress={}", openOffer.getId(), offerSubaddress);
|
log.warn("Splitting new output because spending scheduled output(s) failed for offer {}. Offer funding subadress={}", openOffer.getId(), offerSubaddress);
|
||||||
splitOrSchedule(openOffers, openOffer, offerReserveAmount);
|
splitOrSchedule(openOffers, openOffer, amountNeeded);
|
||||||
resultHandler.handleResult(null);
|
resultHandler.handleResult(null);
|
||||||
} else {
|
} else {
|
||||||
errorMessageHandler.handleErrorMessage(errMsg);
|
errorMessageHandler.handleErrorMessage(errMsg);
|
||||||
@ -916,7 +916,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
// handle sufficient balance
|
// handle sufficient balance
|
||||||
boolean hasSufficientBalance = xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0;
|
boolean hasSufficientBalance = xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(amountNeeded) >= 0;
|
||||||
if (hasSufficientBalance) {
|
if (hasSufficientBalance) {
|
||||||
signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler);
|
signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler);
|
||||||
return;
|
return;
|
||||||
@ -936,7 +936,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
|
|
||||||
private MoneroTxWallet findSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
private MoneroTxWallet findSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
||||||
XmrAddressEntry addressEntry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING);
|
XmrAddressEntry addressEntry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING);
|
||||||
return findSplitOutputFundingTx(openOffers, openOffer, openOffer.getOffer().getReserveAmount(), addressEntry.getSubaddressIndex());
|
return findSplitOutputFundingTx(openOffers, openOffer, openOffer.getOffer().getAmountNeeded(), addressEntry.getSubaddressIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
private MoneroTxWallet findSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger reserveAmount, Integer preferredSubaddressIndex) {
|
private MoneroTxWallet findSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger reserveAmount, Integer preferredSubaddressIndex) {
|
||||||
@ -1035,7 +1035,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MoneroTxWallet splitAndSchedule(OpenOffer openOffer) {
|
private MoneroTxWallet splitAndSchedule(OpenOffer openOffer) {
|
||||||
BigInteger reserveAmount = openOffer.getOffer().getReserveAmount();
|
BigInteger reserveAmount = openOffer.getOffer().getAmountNeeded();
|
||||||
xmrWalletService.swapAddressEntryToAvailable(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); // change funding subaddress in case funded with unsuitable output(s)
|
xmrWalletService.swapAddressEntryToAvailable(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); // change funding subaddress in case funded with unsuitable output(s)
|
||||||
MoneroTxWallet splitOutputTx = null;
|
MoneroTxWallet splitOutputTx = null;
|
||||||
synchronized (XmrWalletService.WALLET_LOCK) {
|
synchronized (XmrWalletService.WALLET_LOCK) {
|
||||||
@ -1064,7 +1064,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
openOffer.setSplitOutputTxHash(splitOutputTx.getHash());
|
openOffer.setSplitOutputTxHash(splitOutputTx.getHash());
|
||||||
openOffer.setSplitOutputTxFee(splitOutputTx.getFee().longValueExact());
|
openOffer.setSplitOutputTxFee(splitOutputTx.getFee().longValueExact());
|
||||||
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
||||||
openOffer.setScheduledAmount(openOffer.getOffer().getReserveAmount().toString());
|
openOffer.setScheduledAmount(openOffer.getOffer().getAmountNeeded().toString());
|
||||||
openOffer.setState(OpenOffer.State.SCHEDULED);
|
openOffer.setState(OpenOffer.State.SCHEDULED);
|
||||||
return splitOutputTx;
|
return splitOutputTx;
|
||||||
}
|
}
|
||||||
@ -1072,7 +1072,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
private void scheduleWithEarliestTxs(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
private void scheduleWithEarliestTxs(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
||||||
|
|
||||||
// check for sufficient balance - scheduled offers amount
|
// check for sufficient balance - scheduled offers amount
|
||||||
BigInteger offerReserveAmount = openOffer.getOffer().getReserveAmount();
|
BigInteger offerReserveAmount = openOffer.getOffer().getAmountNeeded();
|
||||||
if (xmrWalletService.getWallet().getBalance(0).subtract(getScheduledAmount(openOffers)).compareTo(offerReserveAmount) < 0) {
|
if (xmrWalletService.getWallet().getBalance(0).subtract(getScheduledAmount(openOffers)).compareTo(offerReserveAmount) < 0) {
|
||||||
throw new RuntimeException("Not enough money in Haveno wallet");
|
throw new RuntimeException("Not enough money in Haveno wallet");
|
||||||
}
|
}
|
||||||
@ -1135,7 +1135,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
|
|
||||||
// create model
|
// create model
|
||||||
PlaceOfferModel model = new PlaceOfferModel(openOffer,
|
PlaceOfferModel model = new PlaceOfferModel(openOffer,
|
||||||
openOffer.getOffer().getReserveAmount(),
|
openOffer.getOffer().getAmountNeeded(),
|
||||||
useSavingsWallet,
|
useSavingsWallet,
|
||||||
p2PService,
|
p2PService,
|
||||||
btcWalletService,
|
btcWalletService,
|
||||||
|
@ -36,6 +36,7 @@ import haveno.core.trade.messages.InitTradeRequest;
|
|||||||
import haveno.core.trade.messages.PaymentReceivedMessage;
|
import haveno.core.trade.messages.PaymentReceivedMessage;
|
||||||
import haveno.core.trade.messages.PaymentSentMessage;
|
import haveno.core.trade.messages.PaymentSentMessage;
|
||||||
import haveno.core.util.JsonUtil;
|
import haveno.core.util.JsonUtil;
|
||||||
|
import haveno.core.xmr.wallet.XmrWalletService;
|
||||||
import haveno.network.p2p.NodeAddress;
|
import haveno.network.p2p.NodeAddress;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@ -93,8 +94,9 @@ public class HavenoUtils {
|
|||||||
public static final DecimalFormat XMR_FORMATTER = new DecimalFormat("##############0.000000000000", DECIMAL_FORMAT_SYMBOLS);
|
public static final DecimalFormat XMR_FORMATTER = new DecimalFormat("##############0.000000000000", DECIMAL_FORMAT_SYMBOLS);
|
||||||
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||||
|
|
||||||
public static ArbitrationManager arbitrationManager; // TODO: better way to share references?
|
|
||||||
public static HavenoSetup havenoSetup;
|
public static HavenoSetup havenoSetup;
|
||||||
|
public static ArbitrationManager arbitrationManager; // TODO: better way to share references?
|
||||||
|
public static XmrWalletService xmrWalletService;
|
||||||
|
|
||||||
public static boolean isSeedNode() {
|
public static boolean isSeedNode() {
|
||||||
return havenoSetup == null;
|
return havenoSetup == null;
|
||||||
|
@ -82,6 +82,7 @@ import monero.common.TaskLooper;
|
|||||||
import monero.daemon.MoneroDaemonRpc;
|
import monero.daemon.MoneroDaemonRpc;
|
||||||
import monero.daemon.model.MoneroDaemonInfo;
|
import monero.daemon.model.MoneroDaemonInfo;
|
||||||
import monero.daemon.model.MoneroFeeEstimate;
|
import monero.daemon.model.MoneroFeeEstimate;
|
||||||
|
import monero.daemon.model.MoneroKeyImage;
|
||||||
import monero.daemon.model.MoneroNetworkType;
|
import monero.daemon.model.MoneroNetworkType;
|
||||||
import monero.daemon.model.MoneroOutput;
|
import monero.daemon.model.MoneroOutput;
|
||||||
import monero.daemon.model.MoneroSubmitTxResult;
|
import monero.daemon.model.MoneroSubmitTxResult;
|
||||||
@ -196,6 +197,7 @@ public class XmrWalletService {
|
|||||||
this.rpcBindPort = rpcBindPort;
|
this.rpcBindPort = rpcBindPort;
|
||||||
this.useNativeXmrWallet = useNativeXmrWallet;
|
this.useNativeXmrWallet = useNativeXmrWallet;
|
||||||
this.xmrWalletFile = new File(walletDir, MONERO_WALLET_NAME);
|
this.xmrWalletFile = new File(walletDir, MONERO_WALLET_NAME);
|
||||||
|
HavenoUtils.xmrWalletService = this;
|
||||||
|
|
||||||
// set monero logging
|
// set monero logging
|
||||||
if (MONERO_LOG_LEVEL >= 0) MoneroUtils.setLogLevel(MONERO_LOG_LEVEL);
|
if (MONERO_LOG_LEVEL >= 0) MoneroUtils.setLogLevel(MONERO_LOG_LEVEL);
|
||||||
@ -535,6 +537,15 @@ public class XmrWalletService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigInteger getOutputsAmount(Collection<String> keyImages) {
|
||||||
|
BigInteger sum = BigInteger.ZERO;
|
||||||
|
for (String keyImage : keyImages) {
|
||||||
|
List<MoneroOutputWallet> outputs = getOutputs(new MoneroOutputQuery().setIsSpent(false).setKeyImage(new MoneroKeyImage(keyImage)));
|
||||||
|
if (!outputs.isEmpty()) sum = sum.add(outputs.get(0).getAmount());
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Integer> getSubaddressesWithExactInput(BigInteger amount) {
|
private List<Integer> getSubaddressesWithExactInput(BigInteger amount) {
|
||||||
|
|
||||||
// fetch unspent, unfrozen, unlocked outputs
|
// fetch unspent, unfrozen, unlocked outputs
|
||||||
|
@ -173,6 +173,7 @@ shared.acceptedTakerCountries=Accepted taker countries
|
|||||||
shared.tradePrice=Trade price
|
shared.tradePrice=Trade price
|
||||||
shared.tradeAmount=Trade amount
|
shared.tradeAmount=Trade amount
|
||||||
shared.tradeVolume=Trade volume
|
shared.tradeVolume=Trade volume
|
||||||
|
shared.reservedAmount=Reserved amount
|
||||||
shared.invalidKey=The key you entered was not correct.
|
shared.invalidKey=The key you entered was not correct.
|
||||||
shared.enterPrivKey=Enter private key to unlock
|
shared.enterPrivKey=Enter private key to unlock
|
||||||
shared.payoutTxId=Payout transaction ID
|
shared.payoutTxId=Payout transaction ID
|
||||||
|
@ -212,14 +212,14 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||||||
addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel,
|
addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel,
|
||||||
DisplayUtils.getDirectionBothSides(direction), firstRowDistance);
|
DisplayUtils.getDirectionBothSides(direction), firstRowDistance);
|
||||||
}
|
}
|
||||||
String btcAmount = Res.get("shared.xmrAmount");
|
String amount = Res.get("shared.xmrAmount");
|
||||||
if (takeOfferHandlerOptional.isPresent()) {
|
if (takeOfferHandlerOptional.isPresent()) {
|
||||||
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + xmrDirectionInfo,
|
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
|
||||||
HavenoUtils.formatXmr(tradeAmount, true));
|
HavenoUtils.formatXmr(tradeAmount, true));
|
||||||
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo,
|
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo,
|
||||||
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
|
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
|
||||||
} else {
|
} else {
|
||||||
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + xmrDirectionInfo,
|
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
|
||||||
HavenoUtils.formatXmr(offer.getAmount(), true));
|
HavenoUtils.formatXmr(offer.getAmount(), true));
|
||||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minXmrAmount"),
|
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minXmrAmount"),
|
||||||
HavenoUtils.formatXmr(offer.getMinAmount(), true));
|
HavenoUtils.formatXmr(offer.getMinAmount(), true));
|
||||||
@ -257,7 +257,8 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||||||
final String makerPaymentAccountId = offer.getMakerPaymentAccountId();
|
final String makerPaymentAccountId = offer.getMakerPaymentAccountId();
|
||||||
final PaymentAccount myPaymentAccount = user.getPaymentAccount(makerPaymentAccountId);
|
final PaymentAccount myPaymentAccount = user.getPaymentAccount(makerPaymentAccountId);
|
||||||
String countryCode = offer.getCountryCode();
|
String countryCode = offer.getCountryCode();
|
||||||
if (offer.isMyOffer(keyRing) && makerPaymentAccountId != null && myPaymentAccount != null) {
|
boolean isMyOffer = offer.isMyOffer(keyRing);
|
||||||
|
if (isMyOffer && makerPaymentAccountId != null && myPaymentAccount != null) {
|
||||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), myPaymentAccount.getAccountName());
|
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), myPaymentAccount.getAccountName());
|
||||||
} else {
|
} else {
|
||||||
final String method = Res.get(paymentMethod.getId());
|
final String method = Res.get(paymentMethod.getId());
|
||||||
@ -316,11 +317,16 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||||||
textArea.setEditable(false);
|
textArea.setEditable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get amount reserved for the offer
|
||||||
|
BigInteger reservedAmount = isMyOffer ? offer.getReservedAmount() : null;
|
||||||
|
|
||||||
rows = 3;
|
rows = 3;
|
||||||
if (countryCode != null)
|
if (countryCode != null)
|
||||||
rows++;
|
rows++;
|
||||||
if (!isF2F)
|
if (!isF2F)
|
||||||
rows++;
|
rows++;
|
||||||
|
if (reservedAmount != null)
|
||||||
|
rows++;
|
||||||
|
|
||||||
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.GROUP_DISTANCE);
|
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.GROUP_DISTANCE);
|
||||||
addConfirmationLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.get("shared.offerId"), offer.getId(),
|
addConfirmationLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.get("shared.offerId"), offer.getId(),
|
||||||
@ -337,6 +343,9 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||||||
" " +
|
" " +
|
||||||
HavenoUtils.formatXmr(offer.getOfferPayload().getMaxSellerSecurityDeposit(), true);
|
HavenoUtils.formatXmr(offer.getOfferPayload().getMaxSellerSecurityDeposit(), true);
|
||||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
|
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
|
||||||
|
if (reservedAmount != null) {
|
||||||
|
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.reservedAmount"), HavenoUtils.formatXmr(reservedAmount, true));
|
||||||
|
}
|
||||||
|
|
||||||
if (countryCode != null && !isF2F)
|
if (countryCode != null && !isF2F)
|
||||||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.countryBank"),
|
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.countryBank"),
|
||||||
|
Loading…
Reference in New Issue
Block a user