mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-10-01 01:35:48 -04:00
fix bugs resetting trade payout address entries
This commit is contained in:
parent
aa36518f69
commit
900d3a91e1
@ -667,7 +667,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
getOpenOfferById(offer.getId()).ifPresent(openOffer -> {
|
||||
removeOpenOffer(openOffer);
|
||||
openOffer.setState(OpenOffer.State.CLOSED);
|
||||
xmrWalletService.resetOfferFundingForOpenOffer(offer.getId());
|
||||
xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId());
|
||||
offerBookService.removeOffer(openOffer.getOffer().getOfferPayload(),
|
||||
() -> log.info("Successfully removed offer {}", offer.getId()),
|
||||
log::error);
|
||||
@ -764,6 +764,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasAvailableOutput(BigInteger amount) {
|
||||
return findSplitOutputFundingTx(getOpenOffers(), null, amount, null) != null;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Place offer helpers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -811,7 +815,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
|
||||
// find tx with exact input amount
|
||||
MoneroTxWallet splitOutputTx = findSplitOutputFundingTx(openOffers, openOffer);
|
||||
if (openOffer.getScheduledTxHashes() == null && splitOutputTx != null) {
|
||||
if (splitOutputTx != null && openOffer.getScheduledTxHashes() == null) {
|
||||
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
||||
openOffer.setSplitOutputTxHash(splitOutputTx.getHash());
|
||||
openOffer.setScheduledAmount(offerReserveAmount.toString());
|
||||
@ -829,7 +833,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
// on error, create new tx to split output if offer subaddress does not have exact output
|
||||
int offerSubaddress = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).getSubaddressIndex();
|
||||
if (!splitOutputTx.getOutgoingTransfer().getSubaddressIndices().equals(Arrays.asList(offerSubaddress))) {
|
||||
log.warn("Splitting new output because spending existing output(s) failed for offer {}", openOffer.getId());
|
||||
log.warn("Splitting new output because spending existing output(s) failed for offer {}. Split output tx subaddresses={}. Offer funding subadress={}", openOffer.getId(), splitOutputTx.getOutgoingTransfer().getSubaddressIndices(), offerSubaddress);
|
||||
splitOrSchedule(openOffers, openOffer, offerReserveAmount);
|
||||
resultHandler.handleResult(null);
|
||||
} else {
|
||||
@ -846,7 +850,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler);
|
||||
return;
|
||||
} else if (openOffer.getScheduledTxHashes() == null) {
|
||||
scheduleOfferWithEarliestTxs(openOffers, openOffer);
|
||||
scheduleWithEarliestTxs(openOffers, openOffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -860,29 +864,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void splitOrSchedule(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger offerReserveAmount) {
|
||||
|
||||
// handle sufficient available balance to split output
|
||||
boolean sufficientAvailableBalance = xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0;
|
||||
if (sufficientAvailableBalance) {
|
||||
|
||||
// create and relay tx to split output
|
||||
MoneroTxWallet splitOutputTx = createAndRelaySplitOutputTx(openOffer);
|
||||
|
||||
// schedule txs
|
||||
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
||||
openOffer.setSplitOutputTxHash(splitOutputTx.getHash());
|
||||
openOffer.setScheduledAmount(offerReserveAmount.toString());
|
||||
openOffer.setState(OpenOffer.State.SCHEDULED);
|
||||
} else if (openOffer.getScheduledTxHashes() == null) {
|
||||
scheduleOfferWithEarliestTxs(openOffers, openOffer);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasAvailableOutput(BigInteger amount) {
|
||||
return findSplitOutputFundingTx(getOpenOffers(), null, amount, null) != null;
|
||||
}
|
||||
|
||||
private MoneroTxWallet findSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
||||
XmrAddressEntry addressEntry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING);
|
||||
return findSplitOutputFundingTx(openOffers, openOffer, openOffer.getOffer().getReserveAmount(), addressEntry.getSubaddressIndex());
|
||||
@ -968,7 +949,38 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
return earliestUnscheduledTx;
|
||||
}
|
||||
|
||||
private void scheduleOfferWithEarliestTxs(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
||||
private void splitOrSchedule(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger offerReserveAmount) {
|
||||
|
||||
// handle sufficient available balance to split output
|
||||
boolean sufficientAvailableBalance = xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0;
|
||||
if (sufficientAvailableBalance) {
|
||||
splitAndSchedule(openOffer);
|
||||
} else if (openOffer.getScheduledTxHashes() == null) {
|
||||
scheduleWithEarliestTxs(openOffers, openOffer);
|
||||
}
|
||||
}
|
||||
|
||||
private MoneroTxWallet splitAndSchedule(OpenOffer openOffer) {
|
||||
BigInteger reserveAmount = openOffer.getOffer().getReserveAmount();
|
||||
xmrWalletService.swapAddressEntryToAvailable(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); // change funding subaddress in case funded with unsuitable output(s)
|
||||
XmrAddressEntry entry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING);
|
||||
log.info("Creating split output tx to fund offer {} at subaddress {}", openOffer.getId(), entry.getSubaddressIndex());
|
||||
MoneroTxWallet splitOutputTx = xmrWalletService.getWallet().createTx(new MoneroTxConfig()
|
||||
.setAccountIndex(0)
|
||||
.setAddress(entry.getAddressString())
|
||||
.setAmount(reserveAmount)
|
||||
.setRelay(true));
|
||||
log.info("Done creating split output tx to fund offer {}", openOffer.getId());
|
||||
|
||||
// schedule txs
|
||||
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
||||
openOffer.setSplitOutputTxHash(splitOutputTx.getHash());
|
||||
openOffer.setScheduledAmount(openOffer.getOffer().getReserveAmount().toString());
|
||||
openOffer.setState(OpenOffer.State.SCHEDULED);
|
||||
return splitOutputTx;
|
||||
}
|
||||
|
||||
private void scheduleWithEarliestTxs(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
||||
|
||||
// check for sufficient balance - scheduled offers amount
|
||||
BigInteger offerReserveAmount = openOffer.getOffer().getReserveAmount();
|
||||
@ -999,20 +1011,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
openOffer.setState(OpenOffer.State.SCHEDULED);
|
||||
}
|
||||
|
||||
private MoneroTxWallet createAndRelaySplitOutputTx(OpenOffer openOffer) {
|
||||
BigInteger reserveAmount = openOffer.getOffer().getReserveAmount();
|
||||
xmrWalletService.swapAddressEntryToAvailable(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); // change funding subaddress in case funded with unsuitable output(s)
|
||||
String fundingSubaddress = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).getAddressString();
|
||||
log.info("Creating split output tx to fund offer {}", openOffer.getId());
|
||||
MoneroTxWallet splitOutputTx = xmrWalletService.getWallet().createTx(new MoneroTxConfig()
|
||||
.setAccountIndex(0)
|
||||
.setAddress(fundingSubaddress)
|
||||
.setAmount(reserveAmount)
|
||||
.setRelay(true));
|
||||
log.info("Done creating split output tx to fund offer {}", openOffer.getId());
|
||||
return splitOutputTx;
|
||||
}
|
||||
|
||||
private BigInteger getScheduledAmount(List<OpenOffer> openOffers) {
|
||||
BigInteger scheduledAmount = BigInteger.valueOf(0);
|
||||
for (OpenOffer openOffer : openOffers) {
|
||||
|
@ -691,26 +691,26 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
private void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress peer) {
|
||||
log.info("Received InitMultisigRequest from {} with tradeId {} and uid {}", peer, request.getTradeId(), request.getUid());
|
||||
log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid());
|
||||
|
||||
try {
|
||||
Validator.nonEmptyStringOf(request.getTradeId());
|
||||
} catch (Throwable t) {
|
||||
log.warn("Invalid InitMultisigRequest " + request.toString());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Validator.nonEmptyStringOf(request.getTradeId());
|
||||
} catch (Throwable t) {
|
||||
log.warn("Invalid InitMultisigRequest " + request.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId());
|
||||
if (!tradeOptional.isPresent()) {
|
||||
log.warn("No trade with id " + request.getTradeId() + " at node " + P2PService.getMyNodeAddress());
|
||||
return;
|
||||
}
|
||||
Trade trade = tradeOptional.get();
|
||||
getTradeProtocol(trade).handleInitMultisigRequest(request, peer);
|
||||
Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId());
|
||||
if (!tradeOptional.isPresent()) {
|
||||
log.warn("No trade with id " + request.getTradeId() + " at node " + P2PService.getMyNodeAddress());
|
||||
return;
|
||||
}
|
||||
Trade trade = tradeOptional.get();
|
||||
getTradeProtocol(trade).handleInitMultisigRequest(request, peer);
|
||||
}
|
||||
|
||||
private void handleSignContractRequest(SignContractRequest request, NodeAddress peer) {
|
||||
log.info("Received SignContractRequest from {} with tradeId {} and uid {}", peer, request.getTradeId(), request.getUid());
|
||||
log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid());
|
||||
|
||||
try {
|
||||
Validator.nonEmptyStringOf(request.getTradeId());
|
||||
@ -729,7 +729,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
private void handleSignContractResponse(SignContractResponse request, NodeAddress peer) {
|
||||
log.info("Received SignContractResponse from {} with tradeId {} and uid {}", peer, request.getTradeId(), request.getUid());
|
||||
log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid());
|
||||
|
||||
try {
|
||||
Validator.nonEmptyStringOf(request.getTradeId());
|
||||
@ -748,7 +748,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
private void handleDepositRequest(DepositRequest request, NodeAddress peer) {
|
||||
log.info("Received DepositRequest from {} with tradeId {} and uid {}", peer, request.getTradeId(), request.getUid());
|
||||
log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid());
|
||||
|
||||
try {
|
||||
Validator.nonEmptyStringOf(request.getTradeId());
|
||||
@ -767,7 +767,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
private void handleDepositResponse(DepositResponse response, NodeAddress peer) {
|
||||
log.info("Received DepositResponse from {} with tradeId {} and uid {}", peer, response.getTradeId(), response.getUid());
|
||||
log.info("Received {} for trade {} from {} with uid {}", response.getClass().getSimpleName(), response.getTradeId(), peer, response.getUid());
|
||||
|
||||
try {
|
||||
Validator.nonEmptyStringOf(response.getTradeId());
|
||||
|
@ -38,7 +38,7 @@ public class RemoveOffer extends TradeTask {
|
||||
if (trade instanceof MakerTrade) {
|
||||
processModel.getOpenOfferManager().closeOpenOffer(checkNotNull(trade.getOffer()));
|
||||
} else {
|
||||
trade.getXmrWalletService().resetOfferFundingForOpenOffer(trade.getId());
|
||||
trade.getXmrWalletService().resetAddressEntriesForOpenOffer(trade.getId());
|
||||
}
|
||||
|
||||
complete();
|
||||
|
@ -687,7 +687,7 @@ public class XmrWalletService {
|
||||
wallet.startSyncing(connectionsService.getRefreshPeriodMs());
|
||||
if (getMoneroNetworkType() != MoneroNetworkType.MAINNET) log.info("Monero wallet balance={}, unlocked balance={}", wallet.getBalance(0), wallet.getUnlockedBalance(0));
|
||||
|
||||
// TODO: using this to signify both daemon and wallet synced, use separate sync handlers
|
||||
// TODO: using this to signify both daemon and wallet synced, use separate sync handlers?
|
||||
connectionsService.doneDownload();
|
||||
|
||||
// notify setup that main wallet is initialized
|
||||
@ -978,12 +978,11 @@ public class XmrWalletService {
|
||||
public synchronized void resetAddressEntriesForOpenOffer(String offerId) {
|
||||
log.info("resetAddressEntriesForOpenOffer offerId={}", offerId);
|
||||
swapAddressEntryToAvailable(offerId, XmrAddressEntry.Context.OFFER_FUNDING);
|
||||
swapAddressEntryToAvailable(offerId, XmrAddressEntry.Context.TRADE_PAYOUT);
|
||||
}
|
||||
|
||||
public synchronized void resetOfferFundingForOpenOffer(String offerId) {
|
||||
log.info("resetOfferFundingForOpenOffer offerId={}", offerId);
|
||||
swapAddressEntryToAvailable(offerId, XmrAddressEntry.Context.OFFER_FUNDING);
|
||||
// swap trade payout to available if applicable
|
||||
if (tradeManager == null) return;
|
||||
Trade trade = tradeManager.getTrade(offerId);
|
||||
if (trade == null || trade.isPayoutUnlocked()) swapAddressEntryToAvailable(offerId, XmrAddressEntry.Context.TRADE_PAYOUT);
|
||||
}
|
||||
|
||||
public synchronized void resetAddressEntriesForTrade(String offerId) {
|
||||
@ -1136,9 +1135,10 @@ public class XmrWalletService {
|
||||
}
|
||||
|
||||
public Stream<XmrAddressEntry> getAddressEntriesForAvailableBalanceStream() {
|
||||
Stream<XmrAddressEntry> availableAndPayout = Stream.concat(getAddressEntries(XmrAddressEntry.Context.TRADE_PAYOUT).stream(), getFundedAvailableAddressEntries().stream());
|
||||
Stream<XmrAddressEntry> available = Stream.concat(availableAndPayout, getAddressEntries(XmrAddressEntry.Context.ARBITRATOR).stream());
|
||||
Stream<XmrAddressEntry> available = getFundedAvailableAddressEntries().stream();
|
||||
available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.ARBITRATOR).stream());
|
||||
available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).stream().filter(entry -> !tradeManager.getOpenOfferManager().getOpenOfferById(entry.getOfferId()).isPresent()));
|
||||
available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.TRADE_PAYOUT).stream().filter(entry -> tradeManager.getTrade(entry.getOfferId()) == null || tradeManager.getTrade(entry.getOfferId()).isPayoutUnlocked()));
|
||||
return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.valueOf(0)) > 0);
|
||||
}
|
||||
|
||||
|
@ -1017,8 +1017,8 @@ funds.tab.transactions=Transactions
|
||||
funds.deposit.unused=Unused
|
||||
funds.deposit.usedInTx=Used in {0} transaction(s)
|
||||
funds.deposit.baseAddress=Base address
|
||||
funds.deposit.offerFunding=Reserved for offer funding
|
||||
funds.deposit.tradePayout=Reserved for trade payout
|
||||
funds.deposit.offerFunding=Reserved for offer funding ({0})
|
||||
funds.deposit.tradePayout=Reserved for trade payout ({0})
|
||||
funds.deposit.fundHavenoWallet=Fund Haveno wallet
|
||||
funds.deposit.noAddresses=No deposit addresses have been generated yet
|
||||
funds.deposit.fundWallet=Fund your wallet
|
||||
|
@ -104,10 +104,10 @@ class DepositListItem {
|
||||
usage = numTxsWithOutputs == 0 ? Res.get("funds.deposit.unused") : Res.get("funds.deposit.usedInTx", numTxsWithOutputs);
|
||||
break;
|
||||
case OFFER_FUNDING:
|
||||
usage = Res.get("funds.deposit.offerFunding");
|
||||
usage = Res.get("funds.deposit.offerFunding", addressEntry.getShortOfferId());
|
||||
break;
|
||||
case TRADE_PAYOUT:
|
||||
usage = Res.get("funds.deposit.tradePayout");
|
||||
usage = Res.get("funds.deposit.tradePayout", addressEntry.getShortOfferId());
|
||||
break;
|
||||
default:
|
||||
usage = addressEntry.getContext().toString();
|
||||
|
Loading…
Reference in New Issue
Block a user