mirror of
https://github.com/boldsuck/haveno.git
synced 2025-01-03 06:39:34 +00:00
support scheduling offers with locked funds
This commit is contained in:
parent
2da77de41b
commit
fa15612586
25 changed files with 386 additions and 201 deletions
|
@ -44,7 +44,7 @@ import static java.lang.String.format;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static protobuf.Offer.State.OFFER_FEE_PAID;
|
import static protobuf.Offer.State.OFFER_FEE_RESERVED;
|
||||||
import static protobuf.OfferPayload.Direction.BUY;
|
import static protobuf.OfferPayload.Direction.BUY;
|
||||||
import static protobuf.OpenOffer.State.AVAILABLE;
|
import static protobuf.OpenOffer.State.AVAILABLE;
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest {
|
||||||
sleep(5000);
|
sleep(5000);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
assertEquals(OFFER_FEE_PAID.name(), trade.getOffer().getState());
|
assertEquals(OFFER_FEE_RESERVED.name(), trade.getOffer().getState());
|
||||||
EXPECTED_PROTOCOL_STATUS.setState(BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG)
|
EXPECTED_PROTOCOL_STATUS.setState(BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG)
|
||||||
.setPhase(PAYMENT_SENT)
|
.setPhase(PAYMENT_SENT)
|
||||||
.setFiatSent(true);
|
.setFiatSent(true);
|
||||||
|
|
|
@ -46,7 +46,7 @@ import static java.lang.String.format;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static protobuf.Offer.State.OFFER_FEE_PAID;
|
import static protobuf.Offer.State.OFFER_FEE_RESERVED;
|
||||||
import static protobuf.OfferPayload.Direction.SELL;
|
import static protobuf.OfferPayload.Direction.SELL;
|
||||||
import static protobuf.OpenOffer.State.AVAILABLE;
|
import static protobuf.OpenOffer.State.AVAILABLE;
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest {
|
||||||
sleep(3000);
|
sleep(3000);
|
||||||
|
|
||||||
trade = aliceClient.getTrade(tradeId);
|
trade = aliceClient.getTrade(tradeId);
|
||||||
assertEquals(OFFER_FEE_PAID.name(), trade.getOffer().getState());
|
assertEquals(OFFER_FEE_RESERVED.name(), trade.getOffer().getState());
|
||||||
EXPECTED_PROTOCOL_STATUS.setState(SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG)
|
EXPECTED_PROTOCOL_STATUS.setState(SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG)
|
||||||
.setPhase(PAYOUT_PUBLISHED)
|
.setPhase(PAYOUT_PUBLISHED)
|
||||||
.setPayoutPublished(true)
|
.setPayoutPublished(true)
|
||||||
|
|
|
@ -119,13 +119,12 @@ class CoreOffersService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Offer getMyOffer(String id) {
|
Offer getMyOffer(String id) {
|
||||||
Offer offer = offerBookService.getOffers().stream()
|
return openOfferManager.getObservableList().stream()
|
||||||
|
.map(OpenOffer::getOffer)
|
||||||
.filter(o -> o.getId().equals(id))
|
.filter(o -> o.getId().equals(id))
|
||||||
.filter(o -> o.isMyOffer(keyRing))
|
.filter(o -> o.isMyOffer(keyRing))
|
||||||
.findAny().orElseThrow(() ->
|
.findAny().orElseThrow(() ->
|
||||||
new IllegalStateException(format("offer with id '%s' not found", id)));
|
new IllegalStateException(format("offer with id '%s' not found", id)));
|
||||||
setOpenOfferState(offer);
|
|
||||||
return offer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Offer> getOffers(String direction, String currencyCode) {
|
List<Offer> getOffers(String direction, String currencyCode) {
|
||||||
|
@ -143,9 +142,10 @@ class CoreOffersService {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Offer> getMyOffers(String direction, String currencyCode) {
|
List<Offer> getMyOffers(String direction, String currencyCode) {
|
||||||
|
|
||||||
// get my offers posted to books
|
// get my open offers
|
||||||
List<Offer> offers = offerBookService.getOffers().stream()
|
List<Offer> offers = openOfferManager.getObservableList().stream()
|
||||||
|
.map(OpenOffer::getOffer)
|
||||||
.filter(o -> o.isMyOffer(keyRing))
|
.filter(o -> o.isMyOffer(keyRing))
|
||||||
.filter(o -> offerMatchesDirectionAndCurrency(o, direction, currencyCode))
|
.filter(o -> offerMatchesDirectionAndCurrency(o, direction, currencyCode))
|
||||||
.sorted(priceComparator(direction))
|
.sorted(priceComparator(direction))
|
||||||
|
@ -162,9 +162,6 @@ class CoreOffersService {
|
||||||
}
|
}
|
||||||
openOfferManager.removeOpenOffers(unreservedOpenOffers, null);
|
openOfferManager.removeOpenOffers(unreservedOpenOffers, null);
|
||||||
|
|
||||||
// set offer states
|
|
||||||
for (Offer offer : offers) setOpenOfferState(offer);
|
|
||||||
|
|
||||||
return offers;
|
return offers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +171,7 @@ class CoreOffersService {
|
||||||
// collect reserved key images and check for duplicate funds
|
// collect reserved key images and check for duplicate funds
|
||||||
List<String> allKeyImages = new ArrayList<String>();
|
List<String> allKeyImages = new ArrayList<String>();
|
||||||
for (Offer offer : offers) {
|
for (Offer offer : offers) {
|
||||||
|
if (offer.getOfferPayload().getReserveTxKeyImages() == null) continue;
|
||||||
for (String keyImage : offer.getOfferPayload().getReserveTxKeyImages()) {
|
for (String keyImage : offer.getOfferPayload().getReserveTxKeyImages()) {
|
||||||
if (!allKeyImages.add(keyImage)) {
|
if (!allKeyImages.add(keyImage)) {
|
||||||
log.warn("Key image {} belongs to another offer, removing offer {}", keyImage, offer.getId()); // TODO (woodser): this is list, not set, so not checking for duplicates
|
log.warn("Key image {} belongs to another offer, removing offer {}", keyImage, offer.getId()); // TODO (woodser): this is list, not set, so not checking for duplicates
|
||||||
|
@ -192,6 +190,7 @@ class CoreOffersService {
|
||||||
|
|
||||||
// check for offers with spent key images
|
// check for offers with spent key images
|
||||||
for (Offer offer : offers) {
|
for (Offer offer : offers) {
|
||||||
|
if (offer.getOfferPayload().getReserveTxKeyImages() == null) continue;
|
||||||
if (unreservedOffers.contains(offer)) continue;
|
if (unreservedOffers.contains(offer)) continue;
|
||||||
for (String keyImage : offer.getOfferPayload().getReserveTxKeyImages()) {
|
for (String keyImage : offer.getOfferPayload().getReserveTxKeyImages()) {
|
||||||
if (spentKeyImages.contains(keyImage)) {
|
if (spentKeyImages.contains(keyImage)) {
|
||||||
|
@ -256,7 +255,6 @@ class CoreOffersService {
|
||||||
boolean useSavingsWallet = true;
|
boolean useSavingsWallet = true;
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
placeOffer(offer,
|
placeOffer(offer,
|
||||||
buyerSecurityDeposit,
|
|
||||||
triggerPriceAsString,
|
triggerPriceAsString,
|
||||||
useSavingsWallet,
|
useSavingsWallet,
|
||||||
transaction -> resultHandler.accept(offer),
|
transaction -> resultHandler.accept(offer),
|
||||||
|
@ -308,14 +306,12 @@ class CoreOffersService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void placeOffer(Offer offer,
|
private void placeOffer(Offer offer,
|
||||||
double buyerSecurityDeposit,
|
|
||||||
String triggerPriceAsString,
|
String triggerPriceAsString,
|
||||||
boolean useSavingsWallet,
|
boolean useSavingsWallet,
|
||||||
Consumer<Transaction> resultHandler,
|
Consumer<Transaction> resultHandler,
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
long triggerPriceAsLong = PriceUtil.getMarketPriceAsLong(triggerPriceAsString, offer.getCurrencyCode());
|
long triggerPriceAsLong = PriceUtil.getMarketPriceAsLong(triggerPriceAsString, offer.getCurrencyCode());
|
||||||
openOfferManager.placeOffer(offer,
|
openOfferManager.placeOffer(offer,
|
||||||
buyerSecurityDeposit,
|
|
||||||
useSavingsWallet,
|
useSavingsWallet,
|
||||||
triggerPriceAsLong,
|
triggerPriceAsLong,
|
||||||
resultHandler::accept,
|
resultHandler::accept,
|
||||||
|
@ -331,11 +327,6 @@ class CoreOffersService {
|
||||||
return offerOfWantedDirection && offerInWantedCurrency;
|
return offerOfWantedDirection && offerInWantedCurrency;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setOpenOfferState(Offer offer) {
|
|
||||||
Optional<OpenOffer> openOffer = openOfferManager.getOpenOfferById(offer.getId());
|
|
||||||
if (openOffer.isPresent()) offer.setState(openOffer.get().getState() == OpenOffer.State.AVAILABLE ? Offer.State.AVAILABLE : Offer.State.NOT_AVAILABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Comparator<Offer> priceComparator(String direction) {
|
private Comparator<Offer> priceComparator(String direction) {
|
||||||
// A buyer probably wants to see sell orders in price ascending order.
|
// A buyer probably wants to see sell orders in price ascending order.
|
||||||
// A seller probably wants to see buy orders in price descending order.
|
// A seller probably wants to see buy orders in price descending order.
|
||||||
|
|
|
@ -20,9 +20,10 @@ package bisq.core.api.model;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
|
|
||||||
import bisq.common.Payload;
|
import bisq.common.Payload;
|
||||||
|
import bisq.common.proto.ProtoUtil;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
@ -47,6 +48,7 @@ public class OfferInfo implements Payload {
|
||||||
private final long minVolume;
|
private final long minVolume;
|
||||||
private final long txFee;
|
private final long txFee;
|
||||||
private final long makerFee;
|
private final long makerFee;
|
||||||
|
@Nullable
|
||||||
private final String offerFeePaymentTxId;
|
private final String offerFeePaymentTxId;
|
||||||
private final long buyerSecurityDeposit;
|
private final long buyerSecurityDeposit;
|
||||||
private final long sellerSecurityDeposit;
|
private final long sellerSecurityDeposit;
|
||||||
|
@ -129,7 +131,7 @@ public class OfferInfo implements Payload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public bisq.proto.grpc.OfferInfo toProtoMessage() {
|
public bisq.proto.grpc.OfferInfo toProtoMessage() {
|
||||||
return bisq.proto.grpc.OfferInfo.newBuilder()
|
bisq.proto.grpc.OfferInfo.Builder builder = bisq.proto.grpc.OfferInfo.newBuilder()
|
||||||
.setId(id)
|
.setId(id)
|
||||||
.setDirection(direction)
|
.setDirection(direction)
|
||||||
.setPrice(price)
|
.setPrice(price)
|
||||||
|
@ -141,7 +143,6 @@ public class OfferInfo implements Payload {
|
||||||
.setMinVolume(minVolume)
|
.setMinVolume(minVolume)
|
||||||
.setMakerFee(makerFee)
|
.setMakerFee(makerFee)
|
||||||
.setTxFee(txFee)
|
.setTxFee(txFee)
|
||||||
.setOfferFeePaymentTxId(offerFeePaymentTxId)
|
|
||||||
.setBuyerSecurityDeposit(buyerSecurityDeposit)
|
.setBuyerSecurityDeposit(buyerSecurityDeposit)
|
||||||
.setSellerSecurityDeposit(sellerSecurityDeposit)
|
.setSellerSecurityDeposit(sellerSecurityDeposit)
|
||||||
.setTriggerPrice(triggerPrice)
|
.setTriggerPrice(triggerPrice)
|
||||||
|
@ -151,8 +152,9 @@ public class OfferInfo implements Payload {
|
||||||
.setBaseCurrencyCode(baseCurrencyCode)
|
.setBaseCurrencyCode(baseCurrencyCode)
|
||||||
.setCounterCurrencyCode(counterCurrencyCode)
|
.setCounterCurrencyCode(counterCurrencyCode)
|
||||||
.setDate(date)
|
.setDate(date)
|
||||||
.setState(state)
|
.setState(state);
|
||||||
.build();
|
Optional.ofNullable(offerFeePaymentTxId).ifPresent(builder::setOfferFeePaymentTxId);
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -169,7 +171,7 @@ public class OfferInfo implements Payload {
|
||||||
.withMinVolume(proto.getMinVolume())
|
.withMinVolume(proto.getMinVolume())
|
||||||
.withMakerFee(proto.getMakerFee())
|
.withMakerFee(proto.getMakerFee())
|
||||||
.withTxFee(proto.getTxFee())
|
.withTxFee(proto.getTxFee())
|
||||||
.withOfferFeePaymentTxId(proto.getOfferFeePaymentTxId())
|
.withOfferFeePaymentTxId(ProtoUtil.stringOrNullFromProto(proto.getOfferFeePaymentTxId()))
|
||||||
.withBuyerSecurityDeposit(proto.getBuyerSecurityDeposit())
|
.withBuyerSecurityDeposit(proto.getBuyerSecurityDeposit())
|
||||||
.withSellerSecurityDeposit(proto.getSellerSecurityDeposit())
|
.withSellerSecurityDeposit(proto.getSellerSecurityDeposit())
|
||||||
.withTriggerPrice(proto.getTriggerPrice())
|
.withTriggerPrice(proto.getTriggerPrice())
|
||||||
|
|
|
@ -413,13 +413,8 @@ public class XmrWalletService {
|
||||||
System.out.println("Monero wallet balance: " + wallet.getBalance(0));
|
System.out.println("Monero wallet balance: " + wallet.getBalance(0));
|
||||||
System.out.println("Monero wallet unlocked balance: " + wallet.getUnlockedBalance(0));
|
System.out.println("Monero wallet unlocked balance: " + wallet.getUnlockedBalance(0));
|
||||||
|
|
||||||
// notify on balance changes
|
// register internal listener to notify external listeners
|
||||||
wallet.addListener(new MoneroWalletListener() {
|
wallet.addListener(new XmrWalletListener());
|
||||||
@Override
|
|
||||||
public void onBalancesChanged(BigInteger newBalance, BigInteger newUnlockedBalance) {
|
|
||||||
notifyBalanceListeners();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,6 +753,15 @@ public class XmrWalletService {
|
||||||
available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).stream());
|
available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).stream());
|
||||||
return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).isPositive());
|
return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).isPositive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addWalletListener(MoneroWalletListenerI listener) {
|
||||||
|
walletListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeWalletListener(MoneroWalletListenerI listener) {
|
||||||
|
if (!walletListeners.contains(listener)) throw new RuntimeException("Listener is not registered with wallet");
|
||||||
|
walletListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (woodser): update balance and other listening
|
// TODO (woodser): update balance and other listening
|
||||||
public void addBalanceListener(XmrBalanceListener listener) {
|
public void addBalanceListener(XmrBalanceListener listener) {
|
||||||
|
@ -786,26 +790,22 @@ public class XmrWalletService {
|
||||||
for (MoneroTxWallet tx : txs) sb.append('\n' + tx.toString());
|
for (MoneroTxWallet tx : txs) sb.append('\n' + tx.toString());
|
||||||
log.info("\n" + tracePrefix + ":" + sb.toString());
|
log.info("\n" + tracePrefix + ":" + sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------- HELPERS -------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a MoneroWalletListener to notify the Haveno application.
|
* Processes internally before notifying external listeners.
|
||||||
*
|
*
|
||||||
* TODO (woodser): this is no longer necessary since not syncing to thread?
|
* TODO: no longer neccessary to execute on user thread?
|
||||||
*/
|
*/
|
||||||
public class HavenoWalletListener extends MoneroWalletListener {
|
private class XmrWalletListener extends MoneroWalletListener {
|
||||||
|
|
||||||
private MoneroWalletListener listener;
|
|
||||||
|
|
||||||
public HavenoWalletListener(MoneroWalletListener listener) {
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSyncProgress(long height, long startHeight, long endHeight, double percentDone, String message) {
|
public void onSyncProgress(long height, long startHeight, long endHeight, double percentDone, String message) {
|
||||||
UserThread.execute(new Runnable() {
|
UserThread.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);
|
for (MoneroWalletListenerI listener : walletListeners) listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -815,7 +815,7 @@ public class XmrWalletService {
|
||||||
UserThread.execute(new Runnable() {
|
UserThread.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listener.onNewBlock(height);
|
for (MoneroWalletListenerI listener : walletListeners) listener.onNewBlock(height);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -825,7 +825,8 @@ public class XmrWalletService {
|
||||||
UserThread.execute(new Runnable() {
|
UserThread.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listener.onBalancesChanged(newBalance, newUnlockedBalance);
|
for (MoneroWalletListenerI listener : walletListeners) listener.onBalancesChanged(newBalance, newUnlockedBalance);
|
||||||
|
notifyBalanceListeners();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -835,7 +836,7 @@ public class XmrWalletService {
|
||||||
UserThread.execute(new Runnable() {
|
UserThread.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listener.onOutputReceived(output);
|
for (MoneroWalletListenerI listener : walletListeners) listener.onOutputReceived(output);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -845,7 +846,7 @@ public class XmrWalletService {
|
||||||
UserThread.execute(new Runnable() {
|
UserThread.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listener.onOutputSpent(output);
|
for (MoneroWalletListenerI listener : walletListeners) listener.onOutputSpent(output);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,13 @@ import bisq.core.locale.CurrencyUtil;
|
||||||
import bisq.core.monetary.Altcoin;
|
import bisq.core.monetary.Altcoin;
|
||||||
import bisq.core.monetary.Price;
|
import bisq.core.monetary.Price;
|
||||||
import bisq.core.monetary.Volume;
|
import bisq.core.monetary.Volume;
|
||||||
|
import bisq.core.offer.OfferPayload.Direction;
|
||||||
import bisq.core.offer.availability.OfferAvailabilityModel;
|
import bisq.core.offer.availability.OfferAvailabilityModel;
|
||||||
import bisq.core.offer.availability.OfferAvailabilityProtocol;
|
import bisq.core.offer.availability.OfferAvailabilityProtocol;
|
||||||
import bisq.core.payment.payload.PaymentMethod;
|
import bisq.core.payment.payload.PaymentMethod;
|
||||||
import bisq.core.provider.price.MarketPrice;
|
import bisq.core.provider.price.MarketPrice;
|
||||||
import bisq.core.provider.price.PriceFeedService;
|
import bisq.core.provider.price.PriceFeedService;
|
||||||
import bisq.core.util.VolumeUtil;
|
import bisq.core.util.VolumeUtil;
|
||||||
|
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
|
|
||||||
import bisq.common.crypto.KeyRing;
|
import bisq.common.crypto.KeyRing;
|
||||||
|
@ -82,6 +82,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
|
SCHEDULED,
|
||||||
OFFER_FEE_RESERVED,
|
OFFER_FEE_RESERVED,
|
||||||
AVAILABLE,
|
AVAILABLE,
|
||||||
NOT_AVAILABLE,
|
NOT_AVAILABLE,
|
||||||
|
@ -257,6 +258,11 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void setState(Offer.State state) {
|
public void setState(Offer.State state) {
|
||||||
|
try {
|
||||||
|
throw new RuntimeException("Setting offer state: " + state);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
stateProperty().set(state);
|
stateProperty().set(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,6 +283,15 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
||||||
// Getter
|
// Getter
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// get the amount needed for the maker to reserve the offer
|
||||||
|
public Coin getReserveAmount() {
|
||||||
|
Coin reserveAmount = getAmount();
|
||||||
|
reserveAmount = reserveAmount.add(getDirection() == Direction.BUY ?
|
||||||
|
getBuyerSecurityDeposit() :
|
||||||
|
getSellerSecurityDeposit());
|
||||||
|
return reserveAmount;
|
||||||
|
}
|
||||||
|
|
||||||
// converted payload properties
|
// converted payload properties
|
||||||
public Coin getTxFee() {
|
public Coin getTxFee() {
|
||||||
return Coin.valueOf(offerPayload.getTxFee());
|
return Coin.valueOf(offerPayload.getTxFee());
|
||||||
|
|
|
@ -297,9 +297,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
|
||||||
.setProtocolVersion(protocolVersion)
|
.setProtocolVersion(protocolVersion)
|
||||||
.setArbitratorSigner(arbitratorSigner.toProtoMessage());
|
.setArbitratorSigner(arbitratorSigner.toProtoMessage());
|
||||||
|
|
||||||
builder.setOfferFeePaymentTxId(checkNotNull(offerFeePaymentTxId,
|
Optional.ofNullable(offerFeePaymentTxId).ifPresent(builder::setOfferFeePaymentTxId);
|
||||||
"OfferPayload is in invalid state: offerFeePaymentTxID is not set when adding to P2P network."));
|
|
||||||
|
|
||||||
Optional.ofNullable(countryCode).ifPresent(builder::setCountryCode);
|
Optional.ofNullable(countryCode).ifPresent(builder::setCountryCode);
|
||||||
Optional.ofNullable(bankId).ifPresent(builder::setBankId);
|
Optional.ofNullable(bankId).ifPresent(builder::setBankId);
|
||||||
Optional.ofNullable(acceptedBankIds).ifPresent(builder::addAllAcceptedBankIds);
|
Optional.ofNullable(acceptedBankIds).ifPresent(builder::addAllAcceptedBankIds);
|
||||||
|
@ -313,7 +311,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OfferPayload fromProto(protobuf.OfferPayload proto) {
|
public static OfferPayload fromProto(protobuf.OfferPayload proto) {
|
||||||
checkArgument(!proto.getOfferFeePaymentTxId().isEmpty(), "OfferFeePaymentTxId must be set in PB.OfferPayload");
|
|
||||||
List<String> acceptedBankIds = proto.getAcceptedBankIdsList().isEmpty() ?
|
List<String> acceptedBankIds = proto.getAcceptedBankIdsList().isEmpty() ?
|
||||||
null : new ArrayList<>(proto.getAcceptedBankIdsList());
|
null : new ArrayList<>(proto.getAcceptedBankIdsList());
|
||||||
List<String> acceptedCountryCodes = proto.getAcceptedCountryCodesList().isEmpty() ?
|
List<String> acceptedCountryCodes = proto.getAcceptedCountryCodesList().isEmpty() ?
|
||||||
|
@ -336,7 +333,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay
|
||||||
proto.getCounterCurrencyCode(),
|
proto.getCounterCurrencyCode(),
|
||||||
proto.getPaymentMethodId(),
|
proto.getPaymentMethodId(),
|
||||||
proto.getMakerPaymentAccountId(),
|
proto.getMakerPaymentAccountId(),
|
||||||
proto.getOfferFeePaymentTxId(),
|
ProtoUtil.stringOrNullFromProto(proto.getOfferFeePaymentTxId()),
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getCountryCode()),
|
ProtoUtil.stringOrNullFromProto(proto.getCountryCode()),
|
||||||
acceptedCountryCodes,
|
acceptedCountryCodes,
|
||||||
ProtoUtil.stringOrNullFromProto(proto.getBankId()),
|
ProtoUtil.stringOrNullFromProto(proto.getBankId()),
|
||||||
|
|
|
@ -25,6 +25,7 @@ import bisq.common.Timer;
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
import bisq.common.proto.ProtoUtil;
|
import bisq.common.proto.ProtoUtil;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
@ -42,6 +43,7 @@ public final class OpenOffer implements Tradable {
|
||||||
transient private Timer timeoutTimer;
|
transient private Timer timeoutTimer;
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
|
SCHEDULED,
|
||||||
AVAILABLE,
|
AVAILABLE,
|
||||||
RESERVED,
|
RESERVED,
|
||||||
CLOSED,
|
CLOSED,
|
||||||
|
@ -59,10 +61,24 @@ public final class OpenOffer implements Tradable {
|
||||||
private NodeAddress backupArbitrator;
|
private NodeAddress backupArbitrator;
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
|
private boolean autoSplit;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Nullable
|
||||||
|
private String scheduledAmount;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Nullable
|
||||||
|
private List<String> scheduledTxHashes;
|
||||||
|
@Nullable
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private String reserveTxHash;
|
private String reserveTxHash;
|
||||||
|
@Nullable
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
private String reserveTxHex;
|
private String reserveTxHex;
|
||||||
|
@Nullable
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
private String reserveTxKey;
|
private String reserveTxKey;
|
||||||
|
@ -77,26 +93,18 @@ public final class OpenOffer implements Tradable {
|
||||||
transient private long mempoolStatus = -1;
|
transient private long mempoolStatus = -1;
|
||||||
|
|
||||||
public OpenOffer(Offer offer) {
|
public OpenOffer(Offer offer) {
|
||||||
this(offer, 0);
|
this(offer, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenOffer(Offer offer, long triggerPrice) {
|
public OpenOffer(Offer offer, long triggerPrice) {
|
||||||
this.offer = offer;
|
this(offer, triggerPrice, false);
|
||||||
this.triggerPrice = triggerPrice;
|
|
||||||
state = State.AVAILABLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenOffer(Offer offer,
|
public OpenOffer(Offer offer, long triggerPrice, boolean autoSplit) {
|
||||||
long triggerPrice,
|
|
||||||
String reserveTxHash,
|
|
||||||
String reserveTxHex,
|
|
||||||
String reserveTxKey) {
|
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.triggerPrice = triggerPrice;
|
this.triggerPrice = triggerPrice;
|
||||||
state = State.AVAILABLE;
|
this.autoSplit = autoSplit;
|
||||||
this.reserveTxHash = reserveTxHash;
|
state = State.SCHEDULED;
|
||||||
this.reserveTxHex = reserveTxHex;
|
|
||||||
this.reserveTxKey = reserveTxKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -107,13 +115,18 @@ public final class OpenOffer implements Tradable {
|
||||||
State state,
|
State state,
|
||||||
@Nullable NodeAddress backupArbitrator,
|
@Nullable NodeAddress backupArbitrator,
|
||||||
long triggerPrice,
|
long triggerPrice,
|
||||||
String reserveTxHash,
|
boolean autoSplit,
|
||||||
String reserveTxHex,
|
@Nullable String scheduledAmount,
|
||||||
String reserveTxKey) {
|
@Nullable List<String> scheduledTxHashes,
|
||||||
|
@Nullable String reserveTxHash,
|
||||||
|
@Nullable String reserveTxHex,
|
||||||
|
@Nullable String reserveTxKey) {
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.backupArbitrator = backupArbitrator;
|
this.backupArbitrator = backupArbitrator;
|
||||||
this.triggerPrice = triggerPrice;
|
this.triggerPrice = triggerPrice;
|
||||||
|
this.autoSplit = autoSplit;
|
||||||
|
this.scheduledTxHashes = scheduledTxHashes;
|
||||||
this.reserveTxHash = reserveTxHash;
|
this.reserveTxHash = reserveTxHash;
|
||||||
this.reserveTxHex = reserveTxHex;
|
this.reserveTxHex = reserveTxHex;
|
||||||
this.reserveTxKey = reserveTxKey;
|
this.reserveTxKey = reserveTxKey;
|
||||||
|
@ -128,11 +141,14 @@ public final class OpenOffer implements Tradable {
|
||||||
.setOffer(offer.toProtoMessage())
|
.setOffer(offer.toProtoMessage())
|
||||||
.setTriggerPrice(triggerPrice)
|
.setTriggerPrice(triggerPrice)
|
||||||
.setState(protobuf.OpenOffer.State.valueOf(state.name()))
|
.setState(protobuf.OpenOffer.State.valueOf(state.name()))
|
||||||
.setReserveTxHash(reserveTxHash)
|
.setAutoSplit(autoSplit);
|
||||||
.setReserveTxHex(reserveTxHex)
|
|
||||||
.setReserveTxKey(reserveTxKey);
|
|
||||||
|
|
||||||
|
Optional.ofNullable(scheduledAmount).ifPresent(e -> builder.setScheduledAmount(scheduledAmount));
|
||||||
Optional.ofNullable(backupArbitrator).ifPresent(nodeAddress -> builder.setBackupArbitrator(nodeAddress.toProtoMessage()));
|
Optional.ofNullable(backupArbitrator).ifPresent(nodeAddress -> builder.setBackupArbitrator(nodeAddress.toProtoMessage()));
|
||||||
|
Optional.ofNullable(scheduledTxHashes).ifPresent(e -> builder.addAllScheduledTxHashes(scheduledTxHashes));
|
||||||
|
Optional.ofNullable(reserveTxHash).ifPresent(e -> builder.setReserveTxHash(reserveTxHash));
|
||||||
|
Optional.ofNullable(reserveTxHex).ifPresent(e -> builder.setReserveTxHex(reserveTxHex));
|
||||||
|
Optional.ofNullable(reserveTxKey).ifPresent(e -> builder.setReserveTxKey(reserveTxKey));
|
||||||
|
|
||||||
return protobuf.Tradable.newBuilder().setOpenOffer(builder).build();
|
return protobuf.Tradable.newBuilder().setOpenOffer(builder).build();
|
||||||
}
|
}
|
||||||
|
@ -142,6 +158,9 @@ public final class OpenOffer implements Tradable {
|
||||||
ProtoUtil.enumFromProto(OpenOffer.State.class, proto.getState().name()),
|
ProtoUtil.enumFromProto(OpenOffer.State.class, proto.getState().name()),
|
||||||
proto.hasBackupArbitrator() ? NodeAddress.fromProto(proto.getBackupArbitrator()) : null,
|
proto.hasBackupArbitrator() ? NodeAddress.fromProto(proto.getBackupArbitrator()) : null,
|
||||||
proto.getTriggerPrice(),
|
proto.getTriggerPrice(),
|
||||||
|
proto.getAutoSplit(),
|
||||||
|
proto.getScheduledAmount(),
|
||||||
|
proto.getScheduledTxHashesList(),
|
||||||
proto.getReserveTxHash(),
|
proto.getReserveTxHash(),
|
||||||
proto.getReserveTxHex(),
|
proto.getReserveTxHex(),
|
||||||
proto.getReserveTxKey());
|
proto.getReserveTxKey());
|
||||||
|
@ -172,7 +191,7 @@ public final class OpenOffer implements Tradable {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
|
||||||
// We keep it reserved for a limited time, if trade preparation fails we revert to available state
|
// We keep it reserved for a limited time, if trade preparation fails we revert to available state
|
||||||
if (this.state == State.RESERVED) {
|
if (this.state == State.RESERVED) { // TODO (woodser): remove this?
|
||||||
startTimeout();
|
startTimeout();
|
||||||
} else {
|
} else {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
|
|
|
@ -38,6 +38,7 @@ import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||||
import bisq.core.support.dispute.mediation.mediator.Mediator;
|
import bisq.core.support.dispute.mediation.mediator.Mediator;
|
||||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||||
import bisq.core.trade.TradableList;
|
import bisq.core.trade.TradableList;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.closed.ClosedTradableManager;
|
import bisq.core.trade.closed.ClosedTradableManager;
|
||||||
import bisq.core.trade.handlers.TransactionResultHandler;
|
import bisq.core.trade.handlers.TransactionResultHandler;
|
||||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||||
|
@ -85,6 +86,7 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -92,6 +94,10 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import monero.wallet.model.MoneroIncomingTransfer;
|
||||||
|
import monero.wallet.model.MoneroTxQuery;
|
||||||
|
import monero.wallet.model.MoneroTxWallet;
|
||||||
|
import monero.wallet.model.MoneroWalletListener;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -107,7 +113,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
private static final long REFRESH_INTERVAL_MS = TimeUnit.MINUTES.toMillis(6);
|
private static final long REFRESH_INTERVAL_MS = TimeUnit.MINUTES.toMillis(6);
|
||||||
|
|
||||||
private final CoreContext coreContext;
|
private final CoreContext coreContext;
|
||||||
private final CreateOfferService createOfferService;
|
|
||||||
private final KeyRing keyRing;
|
private final KeyRing keyRing;
|
||||||
private final User user;
|
private final User user;
|
||||||
private final P2PService p2PService;
|
private final P2PService p2PService;
|
||||||
|
@ -130,6 +135,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
private final SignedOfferList signedOffers = new SignedOfferList();
|
private final SignedOfferList signedOffers = new SignedOfferList();
|
||||||
private final PersistenceManager<SignedOfferList> signedOfferPersistenceManager;
|
private final PersistenceManager<SignedOfferList> signedOfferPersistenceManager;
|
||||||
private final Map<String, PlaceOfferProtocol> placeOfferProtocols = new HashMap<String, PlaceOfferProtocol>();
|
private final Map<String, PlaceOfferProtocol> placeOfferProtocols = new HashMap<String, PlaceOfferProtocol>();
|
||||||
|
private BigInteger lastUnlockedBalance;
|
||||||
private boolean stopped;
|
private boolean stopped;
|
||||||
private Timer periodicRepublishOffersTimer, periodicRefreshOffersTimer, retryRepublishOffersTimer;
|
private Timer periodicRepublishOffersTimer, periodicRefreshOffersTimer, retryRepublishOffersTimer;
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -142,7 +148,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public OpenOfferManager(CoreContext coreContext,
|
public OpenOfferManager(CoreContext coreContext,
|
||||||
CreateOfferService createOfferService,
|
|
||||||
KeyRing keyRing,
|
KeyRing keyRing,
|
||||||
User user,
|
User user,
|
||||||
P2PService p2PService,
|
P2PService p2PService,
|
||||||
|
@ -162,7 +167,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
PersistenceManager<TradableList<OpenOffer>> persistenceManager,
|
PersistenceManager<TradableList<OpenOffer>> persistenceManager,
|
||||||
PersistenceManager<SignedOfferList> signedOfferPersistenceManager) {
|
PersistenceManager<SignedOfferList> signedOfferPersistenceManager) {
|
||||||
this.coreContext = coreContext;
|
this.coreContext = coreContext;
|
||||||
this.createOfferService = createOfferService;
|
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.p2PService = p2PService;
|
this.p2PService = p2PService;
|
||||||
|
@ -223,6 +227,25 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
openOffers.stream()
|
openOffers.stream()
|
||||||
.forEach(openOffer -> OfferUtil.getInvalidMakerFeeTxErrorMessage(openOffer.getOffer(), btcWalletService)
|
.forEach(openOffer -> OfferUtil.getInvalidMakerFeeTxErrorMessage(openOffer.getOffer(), btcWalletService)
|
||||||
.ifPresent(errorMsg -> invalidOffers.add(new Tuple2<>(openOffer, errorMsg))));
|
.ifPresent(errorMsg -> invalidOffers.add(new Tuple2<>(openOffer, errorMsg))));
|
||||||
|
|
||||||
|
// process unposted offers
|
||||||
|
lastUnlockedBalance = xmrWalletService.getWallet().getUnlockedBalance(0);
|
||||||
|
processUnpostedOffers((transaction) -> {}, (errMessage) -> {
|
||||||
|
log.warn("Error processing unposted offers on new unlocked balance: " + errMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
// register to process unposted offers when unlocked balance increases
|
||||||
|
xmrWalletService.addWalletListener(new MoneroWalletListener() {
|
||||||
|
@Override
|
||||||
|
public void onBalancesChanged(BigInteger newBalance, BigInteger newUnlockedBalance) {
|
||||||
|
if (lastUnlockedBalance.compareTo(newUnlockedBalance) < 0) {
|
||||||
|
processUnpostedOffers((transaction) -> {}, (errMessage) -> {
|
||||||
|
log.warn("Error processing unposted offers on new unlocked balance: " + errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
lastUnlockedBalance = newUnlockedBalance;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanUpAddressEntries() {
|
private void cleanUpAddressEntries() {
|
||||||
|
@ -384,55 +407,27 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void placeOffer(Offer offer,
|
public void placeOffer(Offer offer,
|
||||||
double buyerSecurityDeposit,
|
|
||||||
boolean useSavingsWallet,
|
boolean useSavingsWallet,
|
||||||
long triggerPrice,
|
long triggerPrice,
|
||||||
TransactionResultHandler resultHandler,
|
TransactionResultHandler resultHandler,
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
checkNotNull(offer.getMakerFee(), "makerFee must not be null");
|
checkNotNull(offer.getMakerFee(), "makerFee must not be null");
|
||||||
|
|
||||||
Coin reservedFundsForOffer = createOfferService.getReservedFundsForOffer(offer.getDirection(),
|
boolean autoSplit = false; // TODO: support in api
|
||||||
offer.getAmount(),
|
|
||||||
buyerSecurityDeposit,
|
// TODO (woodser): validate offer
|
||||||
createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDeposit));
|
|
||||||
|
// create open offer
|
||||||
PlaceOfferModel model = new PlaceOfferModel(offer,
|
OpenOffer openOffer = new OpenOffer(offer, triggerPrice, autoSplit);
|
||||||
reservedFundsForOffer,
|
|
||||||
useSavingsWallet,
|
// process open offer to schedule or post
|
||||||
p2PService,
|
processUnpostedOffer(openOffer, (transaction) -> {
|
||||||
btcWalletService,
|
openOffers.add(openOffer);
|
||||||
xmrWalletService,
|
requestPersistence();
|
||||||
tradeWalletService,
|
resultHandler.handleResult(transaction);
|
||||||
offerBookService,
|
}, (errMessage) -> {
|
||||||
arbitratorManager,
|
errorMessageHandler.handleErrorMessage(errMessage);
|
||||||
mediatorManager,
|
});
|
||||||
tradeStatisticsManager,
|
|
||||||
user,
|
|
||||||
keyRing,
|
|
||||||
filterManager);
|
|
||||||
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
|
||||||
model,
|
|
||||||
transaction -> {
|
|
||||||
|
|
||||||
// save reserve tx with open offer
|
|
||||||
OpenOffer openOffer = new OpenOffer(offer, triggerPrice, model.getReserveTx().getHash(), model.getReserveTx().getFullHex(), model.getReserveTx().getKey());
|
|
||||||
openOffers.add(openOffer);
|
|
||||||
requestPersistence();
|
|
||||||
resultHandler.handleResult(transaction);
|
|
||||||
if (!stopped) {
|
|
||||||
startPeriodicRepublishOffersTimer();
|
|
||||||
startPeriodicRefreshOffersTimer();
|
|
||||||
} else {
|
|
||||||
log.debug("We have stopped already. We ignore that placeOfferProtocol.placeOffer.onResult call.");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
errorMessageHandler
|
|
||||||
);
|
|
||||||
|
|
||||||
synchronized (placeOfferProtocols) {
|
|
||||||
placeOfferProtocols.put(offer.getId(), placeOfferProtocol);
|
|
||||||
}
|
|
||||||
placeOfferProtocol.placeOffer(); // TODO (woodser): if error placing offer (e.g. bad signature), remove protocol and unfreeze trade funds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from offerbook
|
// Remove from offerbook
|
||||||
|
@ -442,11 +437,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
removeOpenOffer(openOfferOptional.get(), resultHandler, errorMessageHandler);
|
removeOpenOffer(openOfferOptional.get(), resultHandler, errorMessageHandler);
|
||||||
} else {
|
} else {
|
||||||
log.warn("Offer was not found in our list of open offers. We still try to remove it from the offerbook.");
|
log.warn("Offer was not found in our list of open offers. We still try to remove it from the offerbook.");
|
||||||
errorMessageHandler.handleErrorMessage("Offer was not found in our list of open offers. " +
|
errorMessageHandler.handleErrorMessage("Offer was not found in our list of open offers. " + "We still try to remove it from the offerbook.");
|
||||||
"We still try to remove it from the offerbook.");
|
offerBookService.removeOffer(offer.getOfferPayload(), () -> offer.setState(Offer.State.REMOVED), null);
|
||||||
offerBookService.removeOffer(offer.getOfferPayload(),
|
|
||||||
() -> offer.setState(Offer.State.REMOVED),
|
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +561,9 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onRemoved(@NotNull OpenOffer openOffer, ResultHandler resultHandler, Offer offer) {
|
private void onRemoved(@NotNull OpenOffer openOffer, ResultHandler resultHandler, Offer offer) {
|
||||||
for (String frozenKeyImage : offer.getOfferPayload().getReserveTxKeyImages()) xmrWalletService.getWallet().thawOutput(frozenKeyImage);
|
if (offer.getOfferPayload().getReserveTxKeyImages() != null) {
|
||||||
|
for (String frozenKeyImage : offer.getOfferPayload().getReserveTxKeyImages()) xmrWalletService.getWallet().thawOutput(frozenKeyImage);
|
||||||
|
}
|
||||||
offer.setState(Offer.State.REMOVED);
|
offer.setState(Offer.State.REMOVED);
|
||||||
openOffer.setState(OpenOffer.State.CANCELED);
|
openOffer.setState(OpenOffer.State.CANCELED);
|
||||||
openOffers.remove(openOffer);
|
openOffers.remove(openOffer);
|
||||||
|
@ -622,6 +616,166 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
return signedOffers.stream().filter(e -> e.getOfferId().equals(offerId)).findFirst();
|
return signedOffers.stream().filter(e -> e.getOfferId().equals(offerId)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Place offer helpers
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void processUnpostedOffers(TransactionResultHandler resultHandler, // TODO (woodser): transaction not needed with result handler
|
||||||
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
|
List<String> errorMessages = new ArrayList<String>();
|
||||||
|
for (OpenOffer scheduledOffer : openOffers.getObservableList()) {
|
||||||
|
if (scheduledOffer.getState() != OpenOffer.State.SCHEDULED) continue;
|
||||||
|
CountDownLatch latch = new CountDownLatch(openOffers.list.size());
|
||||||
|
processUnpostedOffer(scheduledOffer, (transaction) -> {
|
||||||
|
latch.countDown();
|
||||||
|
}, errorMessage -> {
|
||||||
|
latch.countDown();
|
||||||
|
errorMessages.add(errorMessage);
|
||||||
|
});
|
||||||
|
TradeUtils.waitForLatch(latch);
|
||||||
|
}
|
||||||
|
requestPersistence();
|
||||||
|
if (errorMessages.size() > 0) errorMessageHandler.handleErrorMessage(errorMessages.toString());
|
||||||
|
else resultHandler.handleResult(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processUnpostedOffer(OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
// get offer reserve amount
|
||||||
|
Coin offerReserveAmountCoin = openOffer.getOffer().getReserveAmount();
|
||||||
|
BigInteger offerReserveAmount = ParsingUtils.centinerosToAtomicUnits(offerReserveAmountCoin.value);
|
||||||
|
|
||||||
|
// handle sufficient available balance
|
||||||
|
if (xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0) {
|
||||||
|
|
||||||
|
// split outputs if applicable
|
||||||
|
boolean splitOutput = openOffer.isAutoSplit(); // TODO: determine if output needs split
|
||||||
|
if (splitOutput) {
|
||||||
|
throw new Error("Post offer with split output option not yet supported"); // TODO: support scheduling offer with split outputs
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise sign and post offer
|
||||||
|
else {
|
||||||
|
signAndPostOffer(openOffer, offerReserveAmountCoin, true, resultHandler, errorMessageHandler);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle unscheduled offer
|
||||||
|
if (openOffer.getScheduledTxHashes() == null) {
|
||||||
|
|
||||||
|
// check for sufficient balance - scheduled offers amount
|
||||||
|
if (xmrWalletService.getWallet().getBalance(0).subtract(getScheduledAmount()).compareTo(offerReserveAmount) < 0) {
|
||||||
|
throw new RuntimeException("Not enough money in Haveno wallet");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get locked txs
|
||||||
|
List<MoneroTxWallet> lockedTxs = xmrWalletService.getWallet().getTxs(new MoneroTxQuery().setIsLocked(true));
|
||||||
|
|
||||||
|
// get earliest unscheduled txs with sufficient incoming amount
|
||||||
|
List<String> scheduledTxHashes = new ArrayList<String>();
|
||||||
|
BigInteger scheduledAmount = new BigInteger("0");
|
||||||
|
for (MoneroTxWallet lockedTx : lockedTxs) {
|
||||||
|
if (isTxScheduled(lockedTx.getHash())) continue;
|
||||||
|
if (lockedTx.getIncomingTransfers() == null || lockedTx.getIncomingTransfers().isEmpty()) continue;
|
||||||
|
scheduledTxHashes.add(lockedTx.getHash());
|
||||||
|
for (MoneroIncomingTransfer transfer : lockedTx.getIncomingTransfers()) {
|
||||||
|
if (transfer.getAccountIndex() == 0) scheduledAmount = scheduledAmount.add(transfer.getAmount());
|
||||||
|
}
|
||||||
|
if (scheduledAmount.compareTo(offerReserveAmount) >= 0) break;
|
||||||
|
}
|
||||||
|
if (scheduledAmount.compareTo(offerReserveAmount) < 0) throw new Error("Not enough funds to schedule offer");
|
||||||
|
|
||||||
|
// schedule txs
|
||||||
|
openOffer.setScheduledTxHashes(scheduledTxHashes);
|
||||||
|
openOffer.setScheduledAmount(scheduledAmount.toString());
|
||||||
|
openOffer.getOffer().setState(Offer.State.SCHEDULED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle result
|
||||||
|
resultHandler.handleResult(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
errorMessageHandler.handleErrorMessage(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigInteger getScheduledAmount() {
|
||||||
|
BigInteger scheduledAmount = new BigInteger("0");
|
||||||
|
for (OpenOffer openOffer : openOffers.getObservableList()) {
|
||||||
|
if (openOffer.getState() != OpenOffer.State.SCHEDULED) continue;
|
||||||
|
if (openOffer.getScheduledTxHashes() == null) continue;
|
||||||
|
List<MoneroTxWallet> fundingTxs = xmrWalletService.getWallet().getTxs(openOffer.getScheduledTxHashes());
|
||||||
|
for (MoneroTxWallet fundingTx : fundingTxs) {
|
||||||
|
for (MoneroIncomingTransfer transfer : fundingTx.getIncomingTransfers()) {
|
||||||
|
if (transfer.getAccountIndex() == 0) scheduledAmount = scheduledAmount.add(transfer.getAmount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scheduledAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTxScheduled(String txHash) {
|
||||||
|
for (OpenOffer openOffer : openOffers.getObservableList()) {
|
||||||
|
if (openOffer.getState() != OpenOffer.State.SCHEDULED) continue;
|
||||||
|
if (openOffer.getScheduledTxHashes() == null) continue;
|
||||||
|
for (String scheduledTxHash : openOffer.getScheduledTxHashes()) {
|
||||||
|
if (txHash.equals(scheduledTxHash)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void signAndPostOffer(OpenOffer openOffer,
|
||||||
|
Coin offerReserveAmount, // TODO: switch to BigInteger
|
||||||
|
boolean useSavingsWallet, // TODO: remove this
|
||||||
|
TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
|
|
||||||
|
// create model
|
||||||
|
PlaceOfferModel model = new PlaceOfferModel(openOffer.getOffer(),
|
||||||
|
offerReserveAmount,
|
||||||
|
useSavingsWallet,
|
||||||
|
p2PService,
|
||||||
|
btcWalletService,
|
||||||
|
xmrWalletService,
|
||||||
|
tradeWalletService,
|
||||||
|
offerBookService,
|
||||||
|
arbitratorManager,
|
||||||
|
mediatorManager,
|
||||||
|
tradeStatisticsManager,
|
||||||
|
user,
|
||||||
|
keyRing,
|
||||||
|
filterManager);
|
||||||
|
|
||||||
|
// create protocol
|
||||||
|
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(model,
|
||||||
|
transaction -> {
|
||||||
|
|
||||||
|
// set reserve tx on open offer
|
||||||
|
openOffer.setReserveTxHash(model.getReserveTx().getHash());
|
||||||
|
openOffer.setReserveTxHex(model.getReserveTx().getHash());
|
||||||
|
openOffer.setReserveTxKey(model.getReserveTx().getKey());
|
||||||
|
|
||||||
|
// set offer state
|
||||||
|
openOffer.setState(OpenOffer.State.AVAILABLE);
|
||||||
|
|
||||||
|
resultHandler.handleResult(transaction);
|
||||||
|
if (!stopped) {
|
||||||
|
startPeriodicRepublishOffersTimer();
|
||||||
|
startPeriodicRefreshOffersTimer();
|
||||||
|
} else {
|
||||||
|
log.debug("We have stopped already. We ignore that placeOfferProtocol.placeOffer.onResult call.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorMessageHandler);
|
||||||
|
|
||||||
|
// run protocol
|
||||||
|
synchronized (placeOfferProtocols) {
|
||||||
|
placeOfferProtocols.put(openOffer.getOffer().getId(), placeOfferProtocol);
|
||||||
|
}
|
||||||
|
placeOfferProtocol.placeOffer(); // TODO (woodser): if error placing offer (e.g. bad signature), remove protocol and unfreeze trade funds
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Arbitrator Signs Offer
|
// Arbitrator Signs Offer
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -19,7 +19,7 @@ package bisq.core.offer.placeoffer;
|
||||||
|
|
||||||
import bisq.core.offer.messages.SignOfferResponse;
|
import bisq.core.offer.messages.SignOfferResponse;
|
||||||
import bisq.core.offer.placeoffer.tasks.AddToOfferBook;
|
import bisq.core.offer.placeoffer.tasks.AddToOfferBook;
|
||||||
import bisq.core.offer.placeoffer.tasks.MakerReservesTradeFunds;
|
import bisq.core.offer.placeoffer.tasks.MakerReservesOfferFunds;
|
||||||
import bisq.core.offer.placeoffer.tasks.MakerSendsSignOfferRequest;
|
import bisq.core.offer.placeoffer.tasks.MakerSendsSignOfferRequest;
|
||||||
import bisq.core.offer.placeoffer.tasks.MakerProcessesSignOfferResponse;
|
import bisq.core.offer.placeoffer.tasks.MakerProcessesSignOfferResponse;
|
||||||
import bisq.core.offer.placeoffer.tasks.ValidateOffer;
|
import bisq.core.offer.placeoffer.tasks.ValidateOffer;
|
||||||
|
@ -56,7 +56,6 @@ public class PlaceOfferProtocol {
|
||||||
// Called from UI
|
// Called from UI
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// TODO (woodser): this returns before offer is placed
|
|
||||||
public void placeOffer() {
|
public void placeOffer() {
|
||||||
log.debug("placeOffer() " + model.getOffer().getId());
|
log.debug("placeOffer() " + model.getOffer().getId());
|
||||||
TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model,
|
TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model,
|
||||||
|
@ -71,7 +70,7 @@ public class PlaceOfferProtocol {
|
||||||
);
|
);
|
||||||
taskRunner.addTasks(
|
taskRunner.addTasks(
|
||||||
ValidateOffer.class,
|
ValidateOffer.class,
|
||||||
MakerReservesTradeFunds.class,
|
MakerReservesOfferFunds.class,
|
||||||
MakerSendsSignOfferRequest.class
|
MakerSendsSignOfferRequest.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,9 @@ import java.util.List;
|
||||||
import monero.daemon.model.MoneroOutput;
|
import monero.daemon.model.MoneroOutput;
|
||||||
import monero.wallet.model.MoneroTxWallet;
|
import monero.wallet.model.MoneroTxWallet;
|
||||||
|
|
||||||
public class MakerReservesTradeFunds extends Task<PlaceOfferModel> {
|
public class MakerReservesOfferFunds extends Task<PlaceOfferModel> {
|
||||||
|
|
||||||
public MakerReservesTradeFunds(TaskRunner taskHandler, PlaceOfferModel model) {
|
public MakerReservesOfferFunds(TaskRunner taskHandler, PlaceOfferModel model) {
|
||||||
super(taskHandler, model);
|
super(taskHandler, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class MakerReservesTradeFunds extends Task<PlaceOfferModel> {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
|
|
||||||
// freeze trade funds and get reserve tx
|
// freeze offer funds and get reserve tx
|
||||||
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
|
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
|
||||||
BigInteger makerFee = ParsingUtils.coinToAtomicUnits(offer.getMakerFee());
|
BigInteger makerFee = ParsingUtils.coinToAtomicUnits(offer.getMakerFee());
|
||||||
BigInteger depositAmount = ParsingUtils.coinToAtomicUnits(model.getReservedFundsForOffer());
|
BigInteger depositAmount = ParsingUtils.coinToAtomicUnits(model.getReservedFundsForOffer());
|
|
@ -901,7 +901,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create block listener
|
// create block listener
|
||||||
depositTxListener = processModel.getXmrWalletService().new HavenoWalletListener(new MoneroWalletListener() { // TODO (woodser): separate into own class file
|
depositTxListener = new MoneroWalletListener() {
|
||||||
|
|
||||||
Long unlockHeight = null;
|
Long unlockHeight = null;
|
||||||
|
|
||||||
|
@ -939,14 +939,14 @@ public abstract class Trade implements Tradable, Model {
|
||||||
if (unlockHeight != null && height == unlockHeight) {
|
if (unlockHeight != null && height == unlockHeight) {
|
||||||
log.info("Multisig deposits unlocked for trade {}", getId());
|
log.info("Multisig deposits unlocked for trade {}", getId());
|
||||||
setConfirmedState(); // TODO (woodser): bisq "confirmed" = xmr unlocked after 10 confirmations
|
setConfirmedState(); // TODO (woodser): bisq "confirmed" = xmr unlocked after 10 confirmations
|
||||||
havenoWallet.removeListener(depositTxListener); // remove listener when notified
|
xmrWalletService.removeWalletListener(depositTxListener); // remove listener when notified
|
||||||
depositTxListener = null; // prevent re-applying trade state in subsequent requests
|
depositTxListener = null; // prevent re-applying trade state in subsequent requests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
// register wallet listener
|
// register wallet listener
|
||||||
havenoWallet.addListener(depositTxListener);
|
xmrWalletService.addWalletListener(depositTxListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -27,6 +27,7 @@ import bisq.core.offer.OfferPayload;
|
||||||
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
|
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
|
||||||
import bisq.core.trade.messages.InitTradeRequest;
|
import bisq.core.trade.messages.InitTradeRequest;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of utilities for trading.
|
* Collection of utilities for trading.
|
||||||
|
@ -173,4 +174,12 @@ public class TradeUtils {
|
||||||
//
|
//
|
||||||
// return new Tuple2<>(multiSigAddress.getAddressString(), payoutAddress);
|
// return new Tuple2<>(multiSigAddress.getAddressString(), payoutAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void waitForLatch(CountDownLatch latch) {
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package bisq.core.trade.protocol;
|
||||||
|
|
||||||
import bisq.core.trade.ArbitratorTrade;
|
import bisq.core.trade.ArbitratorTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.messages.DepositRequest;
|
import bisq.core.trade.messages.DepositRequest;
|
||||||
import bisq.core.trade.messages.InitMultisigRequest;
|
import bisq.core.trade.messages.InitMultisigRequest;
|
||||||
import bisq.core.trade.messages.InitTradeRequest;
|
import bisq.core.trade.messages.InitTradeRequest;
|
||||||
|
@ -59,7 +60,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +145,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ package bisq.core.trade.protocol;
|
||||||
import bisq.core.trade.BuyerAsMakerTrade;
|
import bisq.core.trade.BuyerAsMakerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.Trade.State;
|
import bisq.core.trade.Trade.State;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
|
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
|
||||||
import bisq.core.trade.messages.DepositResponse;
|
import bisq.core.trade.messages.DepositResponse;
|
||||||
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
||||||
|
@ -100,7 +101,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +189,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
|
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
|
||||||
|
@ -222,7 +223,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +255,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import bisq.core.offer.Offer;
|
||||||
import bisq.core.trade.BuyerAsTakerTrade;
|
import bisq.core.trade.BuyerAsTakerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.Trade.State;
|
import bisq.core.trade.Trade.State;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.handlers.TradeResultHandler;
|
import bisq.core.trade.handlers.TradeResultHandler;
|
||||||
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
|
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
|
||||||
import bisq.core.trade.messages.DepositResponse;
|
import bisq.core.trade.messages.DepositResponse;
|
||||||
|
@ -33,7 +34,6 @@ import bisq.core.trade.messages.PaymentReceivedMessage;
|
||||||
import bisq.core.trade.messages.SignContractRequest;
|
import bisq.core.trade.messages.SignContractRequest;
|
||||||
import bisq.core.trade.messages.SignContractResponse;
|
import bisq.core.trade.messages.SignContractResponse;
|
||||||
import bisq.core.trade.messages.TradeMessage;
|
import bisq.core.trade.messages.TradeMessage;
|
||||||
import bisq.core.trade.protocol.TakerProtocol.TakerEvent;
|
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
||||||
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
||||||
|
@ -116,7 +116,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
|
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
|
||||||
|
@ -239,7 +239,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
||||||
|
|
|
@ -19,6 +19,7 @@ package bisq.core.trade.protocol;
|
||||||
|
|
||||||
import bisq.core.trade.BuyerTrade;
|
import bisq.core.trade.BuyerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
|
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
|
||||||
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
||||||
import bisq.core.trade.messages.PaymentReceivedMessage;
|
import bisq.core.trade.messages.PaymentReceivedMessage;
|
||||||
|
@ -26,7 +27,6 @@ import bisq.core.trade.messages.TradeMessage;
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
import bisq.core.trade.protocol.tasks.SetupDepositTxsListener;
|
import bisq.core.trade.protocol.tasks.SetupDepositTxsListener;
|
||||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||||
import bisq.core.trade.protocol.tasks.UpdateMultisigWithTradingPeer;
|
|
||||||
import bisq.core.trade.protocol.tasks.buyer.BuyerPreparesPaymentSentMessage;
|
import bisq.core.trade.protocol.tasks.buyer.BuyerPreparesPaymentSentMessage;
|
||||||
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessesPaymentReceivedMessage;
|
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessesPaymentReceivedMessage;
|
||||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSendsPaymentSentMessage;
|
import bisq.core.trade.protocol.tasks.buyer.BuyerSendsPaymentSentMessage;
|
||||||
|
@ -182,7 +182,7 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
})))
|
})))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ package bisq.core.trade.protocol;
|
||||||
import bisq.core.trade.SellerAsMakerTrade;
|
import bisq.core.trade.SellerAsMakerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.Trade.State;
|
import bisq.core.trade.Trade.State;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.messages.PaymentSentMessage;
|
import bisq.core.trade.messages.PaymentSentMessage;
|
||||||
import bisq.core.trade.messages.DepositResponse;
|
import bisq.core.trade.messages.DepositResponse;
|
||||||
import bisq.core.trade.messages.DepositTxMessage;
|
import bisq.core.trade.messages.DepositTxMessage;
|
||||||
|
@ -100,7 +101,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +189,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
|
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
|
||||||
|
@ -222,7 +223,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +255,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import bisq.core.offer.Offer;
|
||||||
import bisq.core.trade.SellerAsTakerTrade;
|
import bisq.core.trade.SellerAsTakerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.Trade.State;
|
import bisq.core.trade.Trade.State;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.handlers.TradeResultHandler;
|
import bisq.core.trade.handlers.TradeResultHandler;
|
||||||
import bisq.core.trade.messages.PaymentSentMessage;
|
import bisq.core.trade.messages.PaymentSentMessage;
|
||||||
import bisq.core.trade.messages.DepositResponse;
|
import bisq.core.trade.messages.DepositResponse;
|
||||||
|
@ -108,7 +109,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +167,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +197,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
|
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
|
||||||
|
@ -231,7 +232,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +264,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);
|
||||||
|
|
|
@ -20,6 +20,7 @@ package bisq.core.trade.protocol;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.TradeManager;
|
import bisq.core.trade.TradeManager;
|
||||||
|
import bisq.core.trade.TradeUtils;
|
||||||
import bisq.core.trade.handlers.TradeResultHandler;
|
import bisq.core.trade.handlers.TradeResultHandler;
|
||||||
import bisq.core.trade.messages.PaymentSentMessage;
|
import bisq.core.trade.messages.PaymentSentMessage;
|
||||||
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
||||||
|
@ -236,7 +237,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
);
|
);
|
||||||
startTimeout(TRADE_TIMEOUT);
|
startTimeout(TRADE_TIMEOUT);
|
||||||
taskRunner.run();
|
taskRunner.run();
|
||||||
wait(latch);
|
TradeUtils.waitForLatch(latch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,14 +368,6 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Timeout
|
// Timeout
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
protected void wait(CountDownLatch latch) {
|
|
||||||
try {
|
|
||||||
latch.await();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void startTimeout(long timeoutSec) {
|
protected void startTimeout(long timeoutSec) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
|
|
|
@ -56,7 +56,6 @@ public class OpenOfferManagerTest {
|
||||||
when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class));
|
when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class));
|
||||||
|
|
||||||
final OpenOfferManager manager = new OpenOfferManager(coreContext,
|
final OpenOfferManager manager = new OpenOfferManager(coreContext,
|
||||||
null,
|
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
p2PService,
|
p2PService,
|
||||||
|
@ -103,7 +102,6 @@ public class OpenOfferManagerTest {
|
||||||
when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class));
|
when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class));
|
||||||
|
|
||||||
final OpenOfferManager manager = new OpenOfferManager(coreContext,
|
final OpenOfferManager manager = new OpenOfferManager(coreContext,
|
||||||
null,
|
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
p2PService,
|
p2PService,
|
||||||
|
@ -144,7 +142,6 @@ public class OpenOfferManagerTest {
|
||||||
|
|
||||||
|
|
||||||
final OpenOfferManager manager = new OpenOfferManager(coreContext,
|
final OpenOfferManager manager = new OpenOfferManager(coreContext,
|
||||||
null,
|
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
p2PService,
|
p2PService,
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class TradableListTest {
|
||||||
|
|
||||||
// test adding an OpenOffer and convert toProto
|
// test adding an OpenOffer and convert toProto
|
||||||
Offer offer = new Offer(offerPayload);
|
Offer offer = new Offer(offerPayload);
|
||||||
OpenOffer openOffer = new OpenOffer(offer, 0, "", "", "");
|
OpenOffer openOffer = new OpenOffer(offer, 0);
|
||||||
openOfferTradableList.add(openOffer);
|
openOfferTradableList.add(openOffer);
|
||||||
message = (protobuf.PersistableEnvelope) openOfferTradableList.toProtoMessage();
|
message = (protobuf.PersistableEnvelope) openOfferTradableList.toProtoMessage();
|
||||||
assertEquals(message.getMessageCase(), TRADABLE_LIST);
|
assertEquals(message.getMessageCase(), TRADABLE_LIST);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import bisq.desktop.components.TitledGroupBg;
|
||||||
import bisq.core.offer.availability.tasks.ProcessOfferAvailabilityResponse;
|
import bisq.core.offer.availability.tasks.ProcessOfferAvailabilityResponse;
|
||||||
import bisq.core.offer.availability.tasks.SendOfferAvailabilityRequest;
|
import bisq.core.offer.availability.tasks.SendOfferAvailabilityRequest;
|
||||||
import bisq.core.offer.placeoffer.tasks.AddToOfferBook;
|
import bisq.core.offer.placeoffer.tasks.AddToOfferBook;
|
||||||
import bisq.core.offer.placeoffer.tasks.MakerReservesTradeFunds;
|
import bisq.core.offer.placeoffer.tasks.MakerReservesOfferFunds;
|
||||||
import bisq.core.offer.placeoffer.tasks.ValidateOffer;
|
import bisq.core.offer.placeoffer.tasks.ValidateOffer;
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
||||||
|
@ -109,7 +109,7 @@ public class DebugView extends InitializableView<GridPane, Void> {
|
||||||
addGroup("PlaceOfferProtocol",
|
addGroup("PlaceOfferProtocol",
|
||||||
FXCollections.observableArrayList(Arrays.asList(
|
FXCollections.observableArrayList(Arrays.asList(
|
||||||
ValidateOffer.class,
|
ValidateOffer.class,
|
||||||
MakerReservesTradeFunds.class,
|
MakerReservesOfferFunds.class,
|
||||||
AddToOfferBook.class)
|
AddToOfferBook.class)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -315,7 +315,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
||||||
|
|
||||||
void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) {
|
void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) {
|
||||||
openOfferManager.placeOffer(offer,
|
openOfferManager.placeOffer(offer,
|
||||||
buyerSecurityDeposit.get(),
|
|
||||||
useSavingsWallet,
|
useSavingsWallet,
|
||||||
triggerPrice,
|
triggerPrice,
|
||||||
resultHandler,
|
resultHandler,
|
||||||
|
|
|
@ -1450,11 +1450,12 @@ message Offer {
|
||||||
enum State {
|
enum State {
|
||||||
PB_ERROR = 0;
|
PB_ERROR = 0;
|
||||||
UNKNOWN = 1;
|
UNKNOWN = 1;
|
||||||
OFFER_FEE_PAID = 2;
|
SCHEDULED = 2;
|
||||||
AVAILABLE = 3;
|
OFFER_FEE_RESERVED = 3;
|
||||||
NOT_AVAILABLE = 4;
|
AVAILABLE = 4;
|
||||||
REMOVED = 5;
|
NOT_AVAILABLE = 5;
|
||||||
MAKER_OFFLINE = 6;
|
REMOVED = 6;
|
||||||
|
MAKER_OFFLINE = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
OfferPayload offer_payload = 1;
|
OfferPayload offer_payload = 1;
|
||||||
|
@ -1474,20 +1475,24 @@ message SignedOffer {
|
||||||
message OpenOffer {
|
message OpenOffer {
|
||||||
enum State {
|
enum State {
|
||||||
PB_ERROR = 0;
|
PB_ERROR = 0;
|
||||||
AVAILABLE = 1;
|
SCHEDULED = 1;
|
||||||
RESERVED = 2;
|
AVAILABLE = 2;
|
||||||
CLOSED = 3;
|
RESERVED = 3;
|
||||||
CANCELED = 4;
|
CLOSED = 4;
|
||||||
DEACTIVATED = 5;
|
CANCELED = 5;
|
||||||
|
DEACTIVATED = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
Offer offer = 1;
|
Offer offer = 1;
|
||||||
State state = 2;
|
State state = 2;
|
||||||
NodeAddress backup_arbitrator = 3;
|
NodeAddress backup_arbitrator = 3;
|
||||||
int64 trigger_price = 4;
|
int64 trigger_price = 4;
|
||||||
string reserve_tx_hash = 5;
|
bool auto_split = 5;
|
||||||
string reserve_tx_hex = 6;
|
repeated string scheduled_tx_hashes = 6;
|
||||||
string reserve_tx_key = 7;
|
string scheduled_amount = 7; // BigInteger
|
||||||
|
string reserve_tx_hash = 8;
|
||||||
|
string reserve_tx_hex = 9;
|
||||||
|
string reserve_tx_key = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Tradable {
|
message Tradable {
|
||||||
|
|
Loading…
Reference in a new issue