mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 15:00:30 +01:00
Add callback for tradeFee tx to be seen in the network to avoid errors at take offer that the trade address is not funded.
This commit is contained in:
parent
7bce5c4943
commit
bb0f0ec273
3 changed files with 81 additions and 40 deletions
|
@ -154,7 +154,8 @@ public class TradeWalletService {
|
|||
boolean useSavingsWallet,
|
||||
Coin tradingFee,
|
||||
Coin txFee,
|
||||
String feeReceiverAddresses)
|
||||
String feeReceiverAddresses,
|
||||
FutureCallback<Transaction> callback)
|
||||
throws InsufficientMoneyException, AddressFormatException {
|
||||
log.debug("fundingAddress " + fundingAddress.toString());
|
||||
log.debug("reservedForTradeAddress " + reservedForTradeAddress.toString());
|
||||
|
@ -193,6 +194,10 @@ public class TradeWalletService {
|
|||
wallet.completeTx(sendRequest);
|
||||
WalletService.printTx("tradingFeeTx", tradingFeeTx);
|
||||
|
||||
checkNotNull(walletConfig, "walletConfig must not be null");
|
||||
ListenableFuture<Transaction> broadcastComplete = walletConfig.peerGroup().broadcastTransaction(tradingFeeTx).future();
|
||||
Futures.addCallback(broadcastComplete, callback);
|
||||
|
||||
return tradingFeeTx;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package io.bisq.core.offer.placeoffer.tasks;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.taskrunner.Task;
|
||||
import io.bisq.common.taskrunner.TaskRunner;
|
||||
import io.bisq.core.arbitration.Arbitrator;
|
||||
|
@ -43,6 +44,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateMakerFeeTx.class);
|
||||
private Transaction tradeFeeTx = null;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public CreateMakerFeeTx(TaskRunner taskHandler, PlaceOfferModel model) {
|
||||
|
@ -70,8 +72,11 @@ public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
|||
Address changeAddress = walletService.getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE).getAddress();
|
||||
|
||||
final TradeWalletService tradeWalletService = model.getTradeWalletService();
|
||||
|
||||
// We dont use a timeout here as we need to get the tradeFee tx callback called to be sure the addressEntry is funded
|
||||
|
||||
if (offer.isCurrencyForMakerFeeBtc()) {
|
||||
Transaction btcTransaction = tradeWalletService.createBtcTradingFeeTx(
|
||||
tradeFeeTx = tradeWalletService.createBtcTradingFeeTx(
|
||||
fundingAddress,
|
||||
reservedForTradeAddress,
|
||||
changeAddress,
|
||||
|
@ -79,17 +84,36 @@ public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
|||
model.isUseSavingsWallet(),
|
||||
offer.getMakerFee(),
|
||||
offer.getTxFee(),
|
||||
selectedArbitrator.getBtcAddress());
|
||||
selectedArbitrator.getBtcAddress(),
|
||||
new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
// we delay one render frame to be sure we don't get called before the method call has
|
||||
// returned (tradeFeeTx would be null in that case)
|
||||
UserThread.execute(() -> {
|
||||
if (!completed) {
|
||||
if (tradeFeeTx != null && !tradeFeeTx.getHashAsString().equals(transaction.getHashAsString()))
|
||||
log.warn("The trade fee tx received from the network had another tx ID than the one we publish");
|
||||
|
||||
// We assume there will be no tx malleability. We add a check later in case the published offer has a different hash.
|
||||
// As the txId is part of the offer and therefore change the hash data we need to be sure to have no
|
||||
// tx malleability
|
||||
offer.setOfferFeePaymentTxId(btcTransaction.getHashAsString());
|
||||
model.setTransaction(btcTransaction);
|
||||
log.error("CreateMakerFeeTx, offerid={}, OFFER_FUNDING", id);
|
||||
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
offer.setOfferFeePaymentTxId(transaction.getHashAsString());
|
||||
model.setTransaction(transaction);
|
||||
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
complete();
|
||||
} else {
|
||||
log.warn("We got the callback called after the timeout has been triggered a complete().");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
complete();
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
if (!completed) {
|
||||
failed(t);
|
||||
} else {
|
||||
log.warn("We got the callback called after the timeout has been triggered a complete().");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
final BsqWalletService bsqWalletService = model.getBsqWalletService();
|
||||
Transaction preparedBurnFeeTx = model.getBsqWalletService().getPreparedBurnFeeTx(offer.getMakerFee());
|
||||
|
@ -107,6 +131,9 @@ public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
|||
// We need to create another instance, otherwise the tx would trigger an invalid state exception
|
||||
// if it gets committed 2 times
|
||||
tradeWalletService.commitTx(tradeWalletService.getClonedTransaction(signedTx));
|
||||
|
||||
// We dont use a timeout here as we need to get the tradeFee tx callback called to be sure the addressEntry is funded
|
||||
|
||||
bsqWalletService.broadcastTx(signedTx, new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Transaction transaction) {
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package io.bisq.core.trade.protocol.tasks.taker;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.taskrunner.TaskRunner;
|
||||
import io.bisq.core.arbitration.Arbitrator;
|
||||
|
@ -44,6 +43,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
@Slf4j
|
||||
public class CreateTakerFeeTx extends TradeTask {
|
||||
private Transaction tradeFeeTx;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public CreateTakerFeeTx(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
|
@ -71,7 +72,10 @@ public class CreateTakerFeeTx extends TradeTask {
|
|||
Address changeAddress = changeAddressEntry.getAddress();
|
||||
final TradeWalletService tradeWalletService = processModel.getTradeWalletService();
|
||||
if (trade.isCurrencyForTakerFeeBtc()) {
|
||||
Transaction createTakeOfferFeeTx = tradeWalletService.createBtcTradingFeeTx(
|
||||
|
||||
// We dont use a timeout here as we need to get the tradeFee tx callback called to be sure the addressEntry is funded
|
||||
|
||||
tradeFeeTx = tradeWalletService.createBtcTradingFeeTx(
|
||||
fundingAddress,
|
||||
reservedForTradeAddress,
|
||||
changeAddress,
|
||||
|
@ -79,20 +83,40 @@ public class CreateTakerFeeTx extends TradeTask {
|
|||
processModel.isUseSavingsWallet(),
|
||||
trade.getTakerFee(),
|
||||
trade.getTxFee(),
|
||||
selectedArbitrator.getBtcAddress());
|
||||
selectedArbitrator.getBtcAddress(),
|
||||
new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
// we delay one render frame to be sure we don't get called before the method call has
|
||||
// returned (tradeFeeTx would be null in that case)
|
||||
UserThread.execute(() -> {
|
||||
if (!completed) {
|
||||
if (tradeFeeTx != null && !tradeFeeTx.getHashAsString().equals(transaction.getHashAsString()))
|
||||
log.warn("The trade fee tx received from the network had another tx ID than the one we publish");
|
||||
|
||||
//TODO use handler for broadcastTx success
|
||||
processModel.setTakeOfferFeeTx(createTakeOfferFeeTx);
|
||||
trade.setTakerFeeTxId(createTakeOfferFeeTx.getHashAsString());
|
||||
// TODO cehck
|
||||
// Don't call that as it caused in some cased a InsufficientMoneyException
|
||||
// walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
processModel.setTakeOfferFeeTx(tradeFeeTx);
|
||||
trade.setTakerFeeTxId(tradeFeeTx.getHashAsString());
|
||||
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
|
||||
complete();
|
||||
complete();
|
||||
} else {
|
||||
log.warn("We got the callback called after the timeout has been triggered a complete().");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
if (!completed) {
|
||||
failed(t);
|
||||
} else {
|
||||
log.warn("We got the callback called after the timeout has been triggered a complete().");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
final BsqWalletService bsqWalletService = processModel.getBsqWalletService();
|
||||
Transaction preparedBurnFeeTx = processModel.getBsqWalletService().getPreparedBurnFeeTx(trade.getTakerFee());
|
||||
//Coin txFee = trade.getTxFee().subtract(trade.getTakerFee());
|
||||
Transaction txWithBsqFee = tradeWalletService.completeBsqTradingFeeTx(preparedBurnFeeTx,
|
||||
fundingAddress,
|
||||
reservedForTradeAddress,
|
||||
|
@ -108,33 +132,19 @@ public class CreateTakerFeeTx extends TradeTask {
|
|||
// if it gets committed 2 times
|
||||
tradeWalletService.commitTx(tradeWalletService.getClonedTransaction(signedTx));
|
||||
|
||||
Timer timeoutTimer = UserThread.runAfter(() -> {
|
||||
log.warn("Broadcast not completed after 5 sec. We go on with the trade protocol.");
|
||||
trade.setTakerFeeTxId(signedTx.getHashAsString());
|
||||
processModel.setTakeOfferFeeTx(signedTx);
|
||||
|
||||
// TODO cehck
|
||||
// Don't call that as it caused in some cased a InsufficientMoneyException
|
||||
// walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
|
||||
complete();
|
||||
}, 5);
|
||||
// We dont use a timeout here as we need to get the tradeFee tx callback called to be sure the addressEntry is funded
|
||||
|
||||
bsqWalletService.broadcastTx(signedTx, new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Transaction transaction) {
|
||||
if (!completed) {
|
||||
timeoutTimer.stop();
|
||||
if (transaction != null) {
|
||||
log.debug("Successfully sent tx with id " + transaction.getHashAsString());
|
||||
checkArgument(transaction.equals(signedTx));
|
||||
trade.setTakerFeeTxId(transaction.getHashAsString());
|
||||
processModel.setTakeOfferFeeTx(transaction);
|
||||
|
||||
// TODO cehck
|
||||
// Don't call that as it caused in some cased a InsufficientMoneyException
|
||||
// walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
|
||||
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
|
||||
complete();
|
||||
}
|
||||
} else {
|
||||
|
@ -145,7 +155,6 @@ public class CreateTakerFeeTx extends TradeTask {
|
|||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
if (!completed) {
|
||||
timeoutTimer.stop();
|
||||
log.error(t.toString());
|
||||
t.printStackTrace();
|
||||
trade.setErrorMessage("An error occurred.\n" +
|
||||
|
|
Loading…
Add table
Reference in a new issue