sign and post offer directly if reserve amount = available balance

This commit is contained in:
woodser 2025-03-08 17:30:31 -05:00 committed by woodser
parent b0e9627c10
commit bedd38748e
4 changed files with 49 additions and 26 deletions

View File

@ -987,26 +987,16 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
setSplitOutputTx(openOffer, splitOutputTx);
}
// if not found, create tx to split exact output
if (splitOutputTx == null) {
if (openOffer.getSplitOutputTxHash() != null) {
log.warn("Split output tx unexpectedly unavailable for offer, offerId={}, split output tx={}", openOffer.getId(), openOffer.getSplitOutputTxHash());
setSplitOutputTx(openOffer, null);
}
try {
splitOrSchedule(openOffers, openOffer, amountNeeded);
} catch (Exception e) {
log.warn("Unable to split or schedule funds for offer {}: {}", openOffer.getId(), e.getMessage());
openOffer.getOffer().setState(Offer.State.INVALID);
errorMessageHandler.handleErrorMessage(e.getMessage());
return;
}
} else if (!splitOutputTx.isLocked()) {
// otherwise sign and post offer if split output available
signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler);
// if wallet has exact available balance, try to sign and post directly
if (xmrWalletService.getAvailableBalance().equals(amountNeeded)) {
signAndPostOffer(openOffer, true, resultHandler, (errorMessage) -> {
splitOrSchedule(splitOutputTx, openOffers, openOffer, amountNeeded, resultHandler, errorMessageHandler);
});
return;
} else {
splitOrSchedule(splitOutputTx, openOffers, openOffer, amountNeeded, resultHandler, errorMessageHandler);
}
} else {
// sign and post offer if enough funds
@ -1017,11 +1007,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
return;
} else if (openOffer.getScheduledTxHashes() == null) {
scheduleWithEarliestTxs(openOffers, openOffer);
resultHandler.handleResult(null);
return;
}
}
// handle result
resultHandler.handleResult(null);
} catch (Exception e) {
if (!openOffer.isCanceled()) log.error("Error processing pending offer: {}\n", e.getMessage(), e);
errorMessageHandler.handleErrorMessage(e.getMessage());
@ -1087,13 +1076,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
if (output.isSpent() || output.isFrozen()) removeTxs.add(tx);
}
}
if (!hasExactAmount(tx, reserveAmount, preferredSubaddressIndex)) removeTxs.add(tx);
if (!hasExactOutput(tx, reserveAmount, preferredSubaddressIndex)) removeTxs.add(tx);
}
splitOutputTxs.removeAll(removeTxs);
return splitOutputTxs;
}
private boolean hasExactAmount(MoneroTxWallet tx, BigInteger amount, Integer preferredSubaddressIndex) {
private boolean hasExactOutput(MoneroTxWallet tx, BigInteger amount, Integer preferredSubaddressIndex) {
boolean hasExactOutput = (tx.getOutputsWallet(new MoneroOutputQuery()
.setAccountIndex(0)
.setSubaddressIndex(preferredSubaddressIndex)
@ -1115,7 +1104,35 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
return earliestUnscheduledTx;
}
private void splitOrSchedule(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger offerReserveAmount) {
// if split tx not found and cannot reserve exact amount directly, create tx to split or reserve exact output
private void splitOrSchedule(MoneroTxWallet splitOutputTx, List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger amountNeeded, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
if (splitOutputTx == null) {
if (openOffer.getSplitOutputTxHash() != null) {
log.warn("Split output tx unexpectedly unavailable for offer, offerId={}, split output tx={}", openOffer.getId(), openOffer.getSplitOutputTxHash());
setSplitOutputTx(openOffer, null);
}
try {
splitOrScheduleAux(openOffers, openOffer, amountNeeded);
resultHandler.handleResult(null);
return;
} catch (Exception e) {
log.warn("Unable to split or schedule funds for offer {}: {}", openOffer.getId(), e.getMessage());
openOffer.getOffer().setState(Offer.State.INVALID);
errorMessageHandler.handleErrorMessage(e.getMessage());
return;
}
} else if (!splitOutputTx.isLocked()) {
// otherwise sign and post offer if split output available
signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler);
return;
} else {
resultHandler.handleResult(null);
return;
}
}
private void splitOrScheduleAux(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger offerReserveAmount) {
// handle sufficient available balance to split output
boolean sufficientAvailableBalance = xmrWalletService.getAvailableBalance().compareTo(offerReserveAmount) >= 0;
@ -1299,13 +1316,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
openOffer.setScheduledAmount(null);
requestPersistence();
resultHandler.handleResult(transaction);
if (!stopped) {
startPeriodicRepublishOffersTimer();
startPeriodicRefreshOffersTimer();
} else {
log.debug("We have stopped already. We ignore that placeOfferProtocol.placeOffer.onResult call.");
}
resultHandler.handleResult(transaction);
},
errorMessageHandler);

View File

@ -87,6 +87,9 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
try {
//if (true) throw new RuntimeException("Pretend error");
reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, openOffer.isReserveExactAmount(), preferredSubaddressIndex);
} catch (IllegalStateException e) {
log.warn("Illegal state creating reserve tx, offerId={}, error={}", openOffer.getShortId(), i + 1, e.getMessage());
throw e;
} catch (Exception e) {
log.warn("Error creating reserve tx, offerId={}, attempt={}/{}, error={}", openOffer.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage());
model.getXmrWalletService().handleWalletError(e, sourceConnection);

View File

@ -77,7 +77,7 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> {
offer.getOfferPayload().getReserveTxKeyImages(),
returnAddress);
// send request to least used arbitrators until success
// send request to random arbitrators until success
sendSignOfferRequests(request, () -> {
complete();
}, (errorMessage) -> {

View File

@ -70,6 +70,9 @@ public class TakerReserveTradeFunds extends TradeTask {
MoneroRpcConnection sourceConnection = trade.getXmrConnectionService().getConnection();
try {
reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, takerFee, sendAmount, securityDeposit, returnAddress, false, null);
} catch (IllegalStateException e) {
log.warn("Illegal state creating reserve tx, offerId={}, error={}", trade.getShortId(), i + 1, e.getMessage());
throw e;
} catch (Exception e) {
log.warn("Error creating reserve tx, tradeId={}, attempt={}/{}, error={}", trade.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage());
trade.getXmrWalletService().handleWalletError(e, sourceConnection);