mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Merge pull request #6247 from ghubstan/check-precondition-for-confirm-payment-sent-or-rcvd
Conditionally block API's send payment sent/rcvd msgs
This commit is contained in:
commit
d5e0c53c09
11 changed files with 282 additions and 68 deletions
|
@ -2,6 +2,8 @@ package bisq.apitest.method.trade;
|
|||
|
||||
import bisq.proto.grpc.TradeInfo;
|
||||
|
||||
import io.grpc.StatusRuntimeException;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -32,6 +34,7 @@ import bisq.cli.CliMain;
|
|||
import bisq.cli.GrpcClient;
|
||||
import bisq.cli.table.builder.TableBuilder;
|
||||
|
||||
@SuppressWarnings({"ConstantConditions", "unused"})
|
||||
public class AbstractTradeTest extends AbstractOfferTest {
|
||||
|
||||
public static final ExpectedProtocolStatus EXPECTED_PROTOCOL_STATUS = new ExpectedProtocolStatus();
|
||||
|
@ -40,10 +43,16 @@ public class AbstractTradeTest extends AbstractOfferTest {
|
|||
@Getter
|
||||
protected static String tradeId;
|
||||
|
||||
protected final Supplier<Integer> maxTradeStateAndPhaseChecks = () -> isLongRunningTest ? 10 : 2;
|
||||
protected final Supplier<Integer> maxTradeStateAndPhaseChecks = () ->
|
||||
isLongRunningTest
|
||||
? 10
|
||||
: 2;
|
||||
protected final Function<TradeInfo, String> toTradeDetailTable = (trade) ->
|
||||
new TableBuilder(TRADE_DETAIL_TBL, trade).build().toString();
|
||||
protected final Function<GrpcClient, String> toUserName = (client) -> client.equals(aliceClient) ? "Alice" : "Bob";
|
||||
protected final Function<GrpcClient, String> toUserName = (client) ->
|
||||
client.equals(aliceClient)
|
||||
? "Alice"
|
||||
: "Bob";
|
||||
|
||||
@BeforeAll
|
||||
public static void initStaticFixtures() {
|
||||
|
@ -84,17 +93,17 @@ public class AbstractTradeTest extends AbstractOfferTest {
|
|||
return trade;
|
||||
}
|
||||
|
||||
protected final void waitForDepositConfirmation(Logger log,
|
||||
TestInfo testInfo,
|
||||
GrpcClient grpcClient,
|
||||
String tradeId) {
|
||||
protected final void waitForTakerDepositConfirmation(Logger log,
|
||||
TestInfo testInfo,
|
||||
GrpcClient takerClient,
|
||||
String tradeId) {
|
||||
Predicate<TradeInfo> isTradeInDepositConfirmedStateAndPhase = (t) ->
|
||||
t.getState().equals(DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN.name())
|
||||
&& t.getPhase().equals(DEPOSIT_CONFIRMED.name());
|
||||
|
||||
String userName = toUserName.apply(grpcClient);
|
||||
String userName = toUserName.apply(takerClient);
|
||||
for (int i = 1; i <= maxTradeStateAndPhaseChecks.get(); i++) {
|
||||
TradeInfo trade = grpcClient.getTrade(tradeId);
|
||||
TradeInfo trade = takerClient.getTrade(tradeId);
|
||||
if (!isTradeInDepositConfirmedStateAndPhase.test(trade)) {
|
||||
log.warn("{} still waiting on trade {} tx {}: DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN, attempt # {}",
|
||||
userName,
|
||||
|
@ -117,6 +126,15 @@ public class AbstractTradeTest extends AbstractOfferTest {
|
|||
}
|
||||
}
|
||||
|
||||
protected final void verifyTakerDepositNotConfirmed(TradeInfo trade) {
|
||||
if (trade.getIsDepositConfirmed()) {
|
||||
fail(format("INVALID_PHASE for trade %s in STATE=%s PHASE=%s, deposit tx should NOT be confirmed yet.",
|
||||
trade.getShortId(),
|
||||
trade.getState(),
|
||||
trade.getPhase()));
|
||||
}
|
||||
}
|
||||
|
||||
protected final void verifyTakerDepositConfirmed(TradeInfo trade) {
|
||||
if (!trade.getIsDepositConfirmed()) {
|
||||
fail(format("INVALID_PHASE for trade %s in STATE=%s PHASE=%s, deposit tx never confirmed.",
|
||||
|
@ -126,7 +144,80 @@ public class AbstractTradeTest extends AbstractOfferTest {
|
|||
}
|
||||
}
|
||||
|
||||
protected final void waitForBuyerSeesPaymentInitiatedMessage(Logger log,
|
||||
protected final void verifyPaymentSentMsgIsFromBtcBuyerPrecondition(Logger log, GrpcClient sellerClient) {
|
||||
String userName = toUserName.apply(sellerClient);
|
||||
log.debug("BTC seller {} incorrectly sends a confirmpaymentstarted message, for trade {}", userName, tradeId);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> sellerClient.confirmPaymentStarted(tradeId));
|
||||
String expectedExceptionMessage = "FAILED_PRECONDITION: you are the seller, and not sending payment";
|
||||
assertEquals(expectedExceptionMessage, exception.getMessage());
|
||||
}
|
||||
|
||||
protected final void verifyPaymentReceivedMsgIsFromBtcSellerPrecondition(Logger log, GrpcClient buyerClient) {
|
||||
String userName = toUserName.apply(buyerClient);
|
||||
log.debug("BTC buyer {} incorrectly sends a confirmpaymentreceived message, for trade {}", userName, tradeId);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> buyerClient.confirmPaymentReceived(tradeId));
|
||||
String expectedExceptionMessage = "FAILED_PRECONDITION: you are the buyer, and not receiving payment";
|
||||
assertEquals(expectedExceptionMessage, exception.getMessage());
|
||||
}
|
||||
|
||||
protected final void verifyPaymentSentMsgDepositTxConfirmedPrecondition(Logger log, GrpcClient buyerClient) {
|
||||
var trade = buyerClient.getTrade(tradeId);
|
||||
verifyTakerDepositNotConfirmed(trade);
|
||||
|
||||
String userName = toUserName.apply(buyerClient);
|
||||
log.debug("BTC buyer {} sends a confirmpaymentstarted message before deposit tx is confirmed, for trade {}",
|
||||
userName,
|
||||
tradeId);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> buyerClient.confirmPaymentStarted(tradeId));
|
||||
String expectedExceptionMessage =
|
||||
format("FAILED_PRECONDITION: cannot send a payment started message for trade '%s'", tradeId);
|
||||
String failureReason = format("Expected exception message to start with '%s'%n, but got '%s'",
|
||||
expectedExceptionMessage,
|
||||
exception.getMessage());
|
||||
assertTrue(exception.getMessage().startsWith(expectedExceptionMessage), failureReason);
|
||||
expectedExceptionMessage = format("until trade deposit tx '%s' is confirmed", trade.getDepositTxId());
|
||||
assertTrue(exception.getMessage().contains(expectedExceptionMessage));
|
||||
}
|
||||
|
||||
protected final void verifyPaymentReceivedMsgDepositTxConfirmedPrecondition(Logger log, GrpcClient sellerClient) {
|
||||
var trade = sellerClient.getTrade(tradeId);
|
||||
verifyTakerDepositNotConfirmed(trade);
|
||||
|
||||
String userName = toUserName.apply(sellerClient);
|
||||
log.debug("BTC seller {} sends a confirmpaymentreceived message before deposit tx is confirmed, for trade {}",
|
||||
userName,
|
||||
tradeId);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> sellerClient.confirmPaymentReceived(tradeId));
|
||||
String expectedExceptionMessage =
|
||||
format("FAILED_PRECONDITION: cannot send a payment received message for trade '%s'", tradeId);
|
||||
String failureReason = format("Expected exception message to start with '%s'%n, but got '%s'",
|
||||
expectedExceptionMessage,
|
||||
exception.getMessage());
|
||||
assertTrue(exception.getMessage().startsWith(expectedExceptionMessage), failureReason);
|
||||
expectedExceptionMessage = format("until trade deposit tx '%s' is confirmed", trade.getDepositTxId());
|
||||
assertTrue(exception.getMessage().contains(expectedExceptionMessage));
|
||||
}
|
||||
|
||||
protected final void verifyPaymentReceivedMsgAfterPaymentSentMsgPrecondition(Logger log, GrpcClient sellerClient) {
|
||||
var trade = sellerClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
|
||||
String userName = toUserName.apply(sellerClient);
|
||||
log.debug("BTC seller {} sends a confirmpaymentreceived message before a payment started message has been sent, for trade {}",
|
||||
userName,
|
||||
tradeId);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> sellerClient.confirmPaymentReceived(tradeId));
|
||||
String expectedExceptionMessage =
|
||||
format("FAILED_PRECONDITION: cannot send a payment received confirmation message for trade '%s'", tradeId);
|
||||
String failureReason = format("Expected exception message to start with '%s'%n, but got '%s'",
|
||||
expectedExceptionMessage,
|
||||
exception.getMessage());
|
||||
assertTrue(exception.getMessage().startsWith(expectedExceptionMessage), failureReason);
|
||||
expectedExceptionMessage = "until after a trade payment started message has been sent";
|
||||
assertTrue(exception.getMessage().contains(expectedExceptionMessage));
|
||||
}
|
||||
|
||||
protected final void waitUntilBuyerSeesPaymentStartedMessage(Logger log,
|
||||
TestInfo testInfo,
|
||||
GrpcClient grpcClient,
|
||||
String tradeId) {
|
||||
|
@ -153,7 +244,7 @@ public class AbstractTradeTest extends AbstractOfferTest {
|
|||
}
|
||||
}
|
||||
|
||||
protected final void waitForSellerSeesPaymentInitiatedMessage(Logger log,
|
||||
protected final void waitUntilSellerSeesPaymentStartedMessage(Logger log,
|
||||
TestInfo testInfo,
|
||||
GrpcClient grpcClient,
|
||||
String tradeId) {
|
||||
|
|
|
@ -46,6 +46,7 @@ import bisq.apitest.method.offer.AbstractOfferTest;
|
|||
|
||||
// https://github.com/ghubstan/bisq/blob/master/cli/src/main/java/bisq/cli/TradeFormat.java
|
||||
|
||||
@Deprecated // Bisq v1 protocol BSQ trades have been replaced by BSQ Swaps.
|
||||
@Disabled
|
||||
@Slf4j
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
|
@ -100,7 +101,7 @@ public class TakeBuyBSQOfferTest extends AbstractTradeTest {
|
|||
alicesBsqOffers = aliceClient.getMyOffersSortedByDate(BSQ);
|
||||
assertEquals(0, alicesBsqOffers.size());
|
||||
|
||||
waitForDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
waitForTakerDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
|
||||
trade = bobClient.getTrade(tradeId);
|
||||
|
@ -122,7 +123,7 @@ public class TakeBuyBSQOfferTest extends AbstractTradeTest {
|
|||
genBtcBlocksThenWait(1, 2_500);
|
||||
bobClient.confirmPaymentStarted(trade.getTradeId());
|
||||
sleep(6000);
|
||||
waitForBuyerSeesPaymentInitiatedMessage(log, testInfo, bobClient, tradeId);
|
||||
waitUntilBuyerSeesPaymentStartedMessage(log, testInfo, bobClient, tradeId);
|
||||
logTrade(log, testInfo, "Alice's Maker/Buyer View (Payment Sent)", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Seller View (Payment Sent)", bobClient.getTrade(tradeId));
|
||||
} catch (StatusRuntimeException e) {
|
||||
|
@ -134,7 +135,7 @@ public class TakeBuyBSQOfferTest extends AbstractTradeTest {
|
|||
@Order(3)
|
||||
public void testAlicesConfirmPaymentReceived(final TestInfo testInfo) {
|
||||
try {
|
||||
waitForSellerSeesPaymentInitiatedMessage(log, testInfo, aliceClient, tradeId);
|
||||
waitUntilSellerSeesPaymentStartedMessage(log, testInfo, aliceClient, tradeId);
|
||||
sleep(2_000);
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
verifyBsqPaymentHasBeenReceived(log, aliceClient, trade);
|
||||
|
|
|
@ -42,6 +42,7 @@ import static protobuf.OfferDirection.BUY;
|
|||
import static protobuf.OpenOffer.State.AVAILABLE;
|
||||
|
||||
@Disabled
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Slf4j
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class TakeBuyBTCOfferTest extends AbstractTradeTest {
|
||||
|
@ -82,11 +83,9 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest {
|
|||
sleep(2_500); // Allow available offer to be removed from offer book.
|
||||
alicesUsdOffers = aliceClient.getMyOffersSortedByDate(BUY.name(), USD);
|
||||
assertEquals(0, alicesUsdOffers.size());
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
|
||||
trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
verifyTakerDepositNotConfirmed(trade);
|
||||
logTrade(log, testInfo, "Alice's Maker/Buyer View", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Seller View", bobClient.getTrade(tradeId));
|
||||
} catch (StatusRuntimeException e) {
|
||||
|
@ -96,13 +95,23 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest {
|
|||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testAlicesConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
public void testPaymentMessagingPreconditions(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
waitForDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
aliceClient.confirmPaymentStarted(trade.getTradeId());
|
||||
sleep(6_000);
|
||||
waitForBuyerSeesPaymentInitiatedMessage(log, testInfo, aliceClient, tradeId);
|
||||
// Alice is maker / btc buyer, Bob is taker / btc seller.
|
||||
// Verify payment sent and rcvd msgs are sent by the right peers: buyer and seller.
|
||||
verifyPaymentSentMsgIsFromBtcBuyerPrecondition(log, bobClient);
|
||||
verifyPaymentReceivedMsgIsFromBtcSellerPrecondition(log, aliceClient);
|
||||
|
||||
// Verify fiat payment sent and rcvd msgs cannot be sent before trade deposit tx is confirmed.
|
||||
verifyPaymentSentMsgDepositTxConfirmedPrecondition(log, aliceClient);
|
||||
verifyPaymentReceivedMsgDepositTxConfirmedPrecondition(log, bobClient);
|
||||
|
||||
// Now generate the BTC block to confirm the taker deposit tx.
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForTakerDepositConfirmation(log, testInfo, bobClient, tradeId);
|
||||
|
||||
// Verify the seller can only send a payment rcvd msg after the payment started msg.
|
||||
verifyPaymentReceivedMsgAfterPaymentSentMsgPrecondition(log, bobClient);
|
||||
} catch (StatusRuntimeException e) {
|
||||
fail(e);
|
||||
}
|
||||
|
@ -110,9 +119,23 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest {
|
|||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testAlicesConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
waitForTakerDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
aliceClient.confirmPaymentStarted(trade.getTradeId());
|
||||
sleep(6_000);
|
||||
waitUntilBuyerSeesPaymentStartedMessage(log, testInfo, aliceClient, tradeId);
|
||||
} catch (StatusRuntimeException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testBobsConfirmPaymentReceived(final TestInfo testInfo) {
|
||||
try {
|
||||
waitForSellerSeesPaymentInitiatedMessage(log, testInfo, bobClient, tradeId);
|
||||
waitUntilSellerSeesPaymentStartedMessage(log, testInfo, bobClient, tradeId);
|
||||
var trade = bobClient.getTrade(tradeId);
|
||||
bobClient.confirmPaymentReceived(trade.getTradeId());
|
||||
sleep(3_000);
|
||||
|
@ -131,7 +154,7 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@Order(5)
|
||||
public void testCloseTrade(final TestInfo testInfo) {
|
||||
try {
|
||||
genBtcBlocksThenWait(1, 1_000);
|
||||
|
|
|
@ -145,7 +145,7 @@ public class TakeBuyBTCOfferWithNationalBankAcctTest extends AbstractTradeTest {
|
|||
alicesOffers = aliceClient.getMyOffersSortedByDate(BUY.name(), BRL);
|
||||
assertEquals(0, alicesOffers.size());
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
waitForTakerDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
|
||||
trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
|
@ -182,10 +182,10 @@ public class TakeBuyBTCOfferWithNationalBankAcctTest extends AbstractTradeTest {
|
|||
public void testAlicesConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
waitForDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
waitForTakerDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
aliceClient.confirmPaymentStarted(trade.getTradeId());
|
||||
sleep(6_000);
|
||||
waitForBuyerSeesPaymentInitiatedMessage(log, testInfo, aliceClient, tradeId);
|
||||
waitUntilBuyerSeesPaymentStartedMessage(log, testInfo, aliceClient, tradeId);
|
||||
trade = aliceClient.getTrade(tradeId);
|
||||
assertEquals(OFFER_FEE_PAID.name(), trade.getOffer().getState());
|
||||
logTrade(log, testInfo, "Alice's Maker/Buyer View (Payment Sent)", aliceClient.getTrade(tradeId));
|
||||
|
@ -199,7 +199,7 @@ public class TakeBuyBTCOfferWithNationalBankAcctTest extends AbstractTradeTest {
|
|||
@Order(4)
|
||||
public void testBobsConfirmPaymentReceived(final TestInfo testInfo) {
|
||||
try {
|
||||
waitForSellerSeesPaymentInitiatedMessage(log, testInfo, bobClient, tradeId);
|
||||
waitUntilSellerSeesPaymentStartedMessage(log, testInfo, bobClient, tradeId);
|
||||
var trade = bobClient.getTrade(tradeId);
|
||||
bobClient.confirmPaymentReceived(trade.getTradeId());
|
||||
sleep(3_000);
|
||||
|
|
|
@ -47,6 +47,7 @@ import bisq.apitest.method.offer.AbstractOfferTest;
|
|||
import bisq.cli.table.builder.TableBuilder;
|
||||
|
||||
@Disabled
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Slf4j
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class TakeBuyXMROfferTest extends AbstractTradeTest {
|
||||
|
@ -89,11 +90,9 @@ public class TakeBuyXMROfferTest extends AbstractTradeTest {
|
|||
var trade = takeAlicesOffer(offerId, bobsXmrAcct.getId(), TRADE_FEE_CURRENCY_CODE);
|
||||
alicesXmrOffers = aliceClient.getMyOffersSortedByDate(XMR);
|
||||
assertEquals(0, alicesXmrOffers.size());
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
|
||||
trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
verifyTakerDepositNotConfirmed(trade);
|
||||
logTrade(log, testInfo, "Alice's Maker/Buyer View", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Seller View", bobClient.getTrade(tradeId));
|
||||
} catch (StatusRuntimeException e) {
|
||||
|
@ -103,15 +102,39 @@ public class TakeBuyXMROfferTest extends AbstractTradeTest {
|
|||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testPaymentMessagingPreconditions(final TestInfo testInfo) {
|
||||
try {
|
||||
// Alice is maker / xmr buyer (btc seller), Bob is taker / xmr seller (btc buyer).
|
||||
// Verify payment sent and rcvd msgs are sent by the right peers: buyer and seller.
|
||||
verifyPaymentSentMsgIsFromBtcBuyerPrecondition(log, aliceClient);
|
||||
verifyPaymentReceivedMsgIsFromBtcSellerPrecondition(log, bobClient);
|
||||
|
||||
// Verify xmr payment sent and rcvd msgs cannot be sent before trade deposit tx is confirmed.
|
||||
verifyPaymentSentMsgDepositTxConfirmedPrecondition(log, bobClient);
|
||||
verifyPaymentReceivedMsgDepositTxConfirmedPrecondition(log, aliceClient);
|
||||
|
||||
// Now generate the BTC block to confirm the taker deposit tx.
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForTakerDepositConfirmation(log, testInfo, bobClient, tradeId);
|
||||
|
||||
// Verify the seller can only send a payment rcvd msg after the payment started msg.
|
||||
verifyPaymentReceivedMsgAfterPaymentSentMsgPrecondition(log, aliceClient);
|
||||
} catch (StatusRuntimeException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testBobsConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = bobClient.getTrade(tradeId);
|
||||
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
log.debug("Bob sends XMR payment to Alice for trade {}", trade.getTradeId());
|
||||
bobClient.confirmPaymentStarted(trade.getTradeId());
|
||||
log.debug("Bob sends XMR payment to Alice for trade {}", tradeId);
|
||||
bobClient.confirmPaymentStarted(tradeId);
|
||||
sleep(3500);
|
||||
waitForBuyerSeesPaymentInitiatedMessage(log, testInfo, bobClient, tradeId);
|
||||
waitUntilBuyerSeesPaymentStartedMessage(log, testInfo, bobClient, tradeId);
|
||||
|
||||
logTrade(log, testInfo, "Alice's Maker/Buyer View (Payment Sent)", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Seller View (Payment Sent)", bobClient.getTrade(tradeId));
|
||||
|
@ -121,18 +144,18 @@ public class TakeBuyXMROfferTest extends AbstractTradeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
@Order(4)
|
||||
public void testAlicesConfirmPaymentReceived(final TestInfo testInfo) {
|
||||
try {
|
||||
waitForSellerSeesPaymentInitiatedMessage(log, testInfo, aliceClient, tradeId);
|
||||
waitUntilSellerSeesPaymentStartedMessage(log, testInfo, aliceClient, tradeId);
|
||||
|
||||
sleep(2_000);
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
// If we were trading BSQ, Alice would verify payment has been sent to her
|
||||
// Bisq / BSQ wallet, but we can do no such checks for XMR payments.
|
||||
// All XMR transfers are done outside Bisq.
|
||||
log.debug("Alice verifies XMR payment was received from Bob, for trade {}", trade.getTradeId());
|
||||
aliceClient.confirmPaymentReceived(trade.getTradeId());
|
||||
log.debug("Alice verifies XMR payment was received from Bob, for trade {}", tradeId);
|
||||
aliceClient.confirmPaymentReceived(tradeId);
|
||||
sleep(3_000);
|
||||
|
||||
trade = aliceClient.getTrade(tradeId);
|
||||
|
@ -150,7 +173,7 @@ public class TakeBuyXMROfferTest extends AbstractTradeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@Order(5)
|
||||
public void testCloseTrade(final TestInfo testInfo) {
|
||||
try {
|
||||
genBtcBlocksThenWait(1, 1_000);
|
||||
|
|
|
@ -46,6 +46,7 @@ import static protobuf.OfferDirection.BUY;
|
|||
import bisq.apitest.method.offer.AbstractOfferTest;
|
||||
import bisq.cli.table.builder.TableBuilder;
|
||||
|
||||
@Deprecated // Bisq v1 protocol BSQ trades have been replaced by BSQ Swaps.
|
||||
@Disabled
|
||||
@Slf4j
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
|
@ -81,7 +82,7 @@ public class TakeSellBSQOfferTest extends AbstractTradeTest {
|
|||
alicesLegacyBsqAcct.getId(),
|
||||
TRADE_FEE_CURRENCY_CODE);
|
||||
log.debug("Alice's SELL BSQ (BUY BTC) Offer:\n{}", new TableBuilder(OFFER_TBL, alicesOffer).build());
|
||||
genBtcBlocksThenWait(1, 4_000);
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
var offerId = alicesOffer.getId();
|
||||
assertTrue(alicesOffer.getIsCurrencyForMakerFeeBtc());
|
||||
var alicesBsqOffers = aliceClient.getMyOffers(btcTradeDirection, BSQ);
|
||||
|
@ -94,7 +95,7 @@ public class TakeSellBSQOfferTest extends AbstractTradeTest {
|
|||
alicesBsqOffers = aliceClient.getMyOffersSortedByDate(BSQ);
|
||||
assertEquals(0, alicesBsqOffers.size());
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
waitForTakerDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
logTrade(log, testInfo, "Alice's Maker/Seller View", aliceClient.getTrade(tradeId));
|
||||
|
@ -109,12 +110,12 @@ public class TakeSellBSQOfferTest extends AbstractTradeTest {
|
|||
public void testAlicesConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
waitForDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
waitForTakerDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
sendBsqPayment(log, aliceClient, trade);
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
aliceClient.confirmPaymentStarted(trade.getTradeId());
|
||||
sleep(6_000);
|
||||
waitForBuyerSeesPaymentInitiatedMessage(log, testInfo, aliceClient, tradeId);
|
||||
waitUntilBuyerSeesPaymentStartedMessage(log, testInfo, aliceClient, tradeId);
|
||||
logTrade(log, testInfo, "Alice's Maker/Seller View (Payment Sent)", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Buyer View (Payment Sent)", bobClient.getTrade(tradeId));
|
||||
} catch (StatusRuntimeException e) {
|
||||
|
@ -126,7 +127,7 @@ public class TakeSellBSQOfferTest extends AbstractTradeTest {
|
|||
@Order(3)
|
||||
public void testBobsConfirmPaymentReceived(final TestInfo testInfo) {
|
||||
try {
|
||||
waitForSellerSeesPaymentInitiatedMessage(log, testInfo, bobClient, tradeId);
|
||||
waitUntilSellerSeesPaymentStartedMessage(log, testInfo, bobClient, tradeId);
|
||||
|
||||
sleep(2_000);
|
||||
var trade = bobClient.getTrade(tradeId);
|
||||
|
|
|
@ -43,6 +43,7 @@ import static protobuf.Offer.State.OFFER_FEE_PAID;
|
|||
import static protobuf.OfferDirection.SELL;
|
||||
|
||||
@Disabled
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Slf4j
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class TakeSellBTCOfferTest extends AbstractTradeTest {
|
||||
|
@ -86,10 +87,9 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest {
|
|||
sleep(2_500); // Allow available offer to be removed from offer book.
|
||||
var takeableUsdOffers = bobClient.getOffersSortedByDate(SELL.name(), USD);
|
||||
assertEquals(0, takeableUsdOffers.size());
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
|
||||
trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
verifyTakerDepositNotConfirmed(trade);
|
||||
logTrade(log, testInfo, "Alice's Maker/Buyer View", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Seller View", bobClient.getTrade(tradeId));
|
||||
} catch (StatusRuntimeException e) {
|
||||
|
@ -99,13 +99,23 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest {
|
|||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testBobsConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
public void testPaymentMessagingPreconditions(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
bobClient.confirmPaymentStarted(tradeId);
|
||||
sleep(6_000);
|
||||
waitForBuyerSeesPaymentInitiatedMessage(log, testInfo, bobClient, tradeId);
|
||||
// Alice is maker / btc seller, Bob is taker / btc buyer.
|
||||
// Verify payment sent and rcvd msgs are sent by the right peers: buyer and seller.
|
||||
verifyPaymentSentMsgIsFromBtcBuyerPrecondition(log, aliceClient);
|
||||
verifyPaymentReceivedMsgIsFromBtcSellerPrecondition(log, bobClient);
|
||||
|
||||
// Verify fiat payment sent and rcvd msgs cannot be sent before trade deposit tx is confirmed.
|
||||
verifyPaymentSentMsgDepositTxConfirmedPrecondition(log, bobClient);
|
||||
verifyPaymentReceivedMsgDepositTxConfirmedPrecondition(log, aliceClient);
|
||||
|
||||
// Now generate the BTC block to confirm the taker deposit tx.
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForTakerDepositConfirmation(log, testInfo, bobClient, tradeId);
|
||||
|
||||
// Verify the seller can only send a payment rcvd msg after the payment started msg.
|
||||
verifyPaymentReceivedMsgAfterPaymentSentMsgPrecondition(log, aliceClient);
|
||||
} catch (StatusRuntimeException e) {
|
||||
fail(e);
|
||||
}
|
||||
|
@ -113,9 +123,23 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest {
|
|||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testBobsConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
bobClient.confirmPaymentStarted(tradeId);
|
||||
sleep(6_000);
|
||||
waitUntilBuyerSeesPaymentStartedMessage(log, testInfo, bobClient, tradeId);
|
||||
} catch (StatusRuntimeException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testAlicesConfirmPaymentReceived(final TestInfo testInfo) {
|
||||
try {
|
||||
waitForSellerSeesPaymentInitiatedMessage(log, testInfo, aliceClient, tradeId);
|
||||
waitUntilSellerSeesPaymentStartedMessage(log, testInfo, aliceClient, tradeId);
|
||||
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
aliceClient.confirmPaymentReceived(trade.getTradeId());
|
||||
|
@ -134,7 +158,7 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@Order(5)
|
||||
public void testBobsBtcWithdrawalToExternalAddress(final TestInfo testInfo) {
|
||||
try {
|
||||
genBtcBlocksThenWait(1, 1_000);
|
||||
|
|
|
@ -60,7 +60,7 @@ public class TakeSellXMROfferTest extends AbstractTradeTest {
|
|||
|
||||
@BeforeAll
|
||||
public static void setUp() {
|
||||
AbstractOfferTest.setUp();
|
||||
AbstractOfferTest.setUp(false);
|
||||
createXmrPaymentAccounts();
|
||||
EXPECTED_PROTOCOL_STATUS.init();
|
||||
}
|
||||
|
@ -93,12 +93,9 @@ public class TakeSellXMROfferTest extends AbstractTradeTest {
|
|||
var trade = takeAlicesOffer(offerId, bobsXmrAcct.getId(), TRADE_FEE_CURRENCY_CODE);
|
||||
alicesXmrOffers = aliceClient.getMyOffersSortedByDate(XMR);
|
||||
assertEquals(0, alicesXmrOffers.size());
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
|
||||
waitForDepositConfirmation(log, testInfo, bobClient, trade.getTradeId());
|
||||
|
||||
trade = bobClient.getTrade(tradeId);
|
||||
verifyTakerDepositConfirmed(trade);
|
||||
verifyTakerDepositNotConfirmed(trade);
|
||||
logTrade(log, testInfo, "Alice's Maker/Seller View", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Buyer View", bobClient.getTrade(tradeId));
|
||||
} catch (StatusRuntimeException e) {
|
||||
|
@ -108,15 +105,39 @@ public class TakeSellXMROfferTest extends AbstractTradeTest {
|
|||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testPaymentMessagingPreconditions(final TestInfo testInfo) {
|
||||
try {
|
||||
// Alice is maker / xmr seller (btc buyer), Bob is taker / xmr buyer (btc seller).
|
||||
// Verify payment sent and rcvd msgs are sent by the right peers: buyer and seller.
|
||||
verifyPaymentSentMsgIsFromBtcBuyerPrecondition(log, bobClient);
|
||||
verifyPaymentReceivedMsgIsFromBtcSellerPrecondition(log, aliceClient);
|
||||
|
||||
// Verify xmr payment sent and rcvd msgs cannot be sent before trade deposit tx is confirmed.
|
||||
verifyPaymentSentMsgDepositTxConfirmedPrecondition(log, aliceClient);
|
||||
verifyPaymentReceivedMsgDepositTxConfirmedPrecondition(log, bobClient);
|
||||
|
||||
// Now generate the BTC block to confirm the taker deposit tx.
|
||||
genBtcBlocksThenWait(1, 2_500);
|
||||
waitForTakerDepositConfirmation(log, testInfo, bobClient, tradeId);
|
||||
|
||||
// Verify the seller can only send a payment rcvd msg after the payment started msg.
|
||||
verifyPaymentReceivedMsgAfterPaymentSentMsgPrecondition(log, bobClient);
|
||||
} catch (StatusRuntimeException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testAlicesConfirmPaymentStarted(final TestInfo testInfo) {
|
||||
try {
|
||||
var trade = aliceClient.getTrade(tradeId);
|
||||
waitForDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
waitForTakerDepositConfirmation(log, testInfo, aliceClient, trade.getTradeId());
|
||||
log.debug("Alice sends XMR payment to Bob for trade {}", trade.getTradeId());
|
||||
aliceClient.confirmPaymentStarted(trade.getTradeId());
|
||||
sleep(3500);
|
||||
sleep(3_500);
|
||||
|
||||
waitForBuyerSeesPaymentInitiatedMessage(log, testInfo, aliceClient, tradeId);
|
||||
waitUntilBuyerSeesPaymentStartedMessage(log, testInfo, aliceClient, tradeId);
|
||||
logTrade(log, testInfo, "Alice's Maker/Seller View (Payment Sent)", aliceClient.getTrade(tradeId));
|
||||
logTrade(log, testInfo, "Bob's Taker/Buyer View (Payment Sent)", bobClient.getTrade(tradeId));
|
||||
} catch (StatusRuntimeException e) {
|
||||
|
@ -125,10 +146,10 @@ public class TakeSellXMROfferTest extends AbstractTradeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
@Order(4)
|
||||
public void testBobsConfirmPaymentReceived(final TestInfo testInfo) {
|
||||
try {
|
||||
waitForSellerSeesPaymentInitiatedMessage(log, testInfo, bobClient, tradeId);
|
||||
waitUntilSellerSeesPaymentStartedMessage(log, testInfo, bobClient, tradeId);
|
||||
|
||||
var trade = bobClient.getTrade(tradeId);
|
||||
sleep(2_000);
|
||||
|
@ -154,7 +175,7 @@ public class TakeSellXMROfferTest extends AbstractTradeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@Order(5)
|
||||
public void testAlicesBtcWithdrawalToExternalAddress(final TestInfo testInfo) {
|
||||
try {
|
||||
genBtcBlocksThenWait(1, 1_000);
|
||||
|
|
|
@ -78,6 +78,7 @@ public class LongRunningTradesTest extends AbstractTradeTest {
|
|||
TakeSellBTCOfferTest test = new TakeSellBTCOfferTest();
|
||||
setLongRunningTest(true);
|
||||
test.testTakeAlicesSellOffer(testInfo);
|
||||
test.testPaymentMessagingPreconditions(testInfo);
|
||||
test.testBobsConfirmPaymentStarted(testInfo);
|
||||
test.testAlicesConfirmPaymentReceived(testInfo);
|
||||
test.testBobsBtcWithdrawalToExternalAddress(testInfo);
|
||||
|
|
|
@ -20,6 +20,7 @@ package bisq.apitest.scenario;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -55,6 +56,7 @@ public class TradeTest extends AbstractTradeTest {
|
|||
public void testTakeBuyBTCOffer(final TestInfo testInfo) {
|
||||
TakeBuyBTCOfferTest test = new TakeBuyBTCOfferTest();
|
||||
test.testTakeAlicesBuyOffer(testInfo);
|
||||
test.testPaymentMessagingPreconditions(testInfo);
|
||||
test.testAlicesConfirmPaymentStarted(testInfo);
|
||||
test.testBobsConfirmPaymentReceived(testInfo);
|
||||
test.testCloseTrade(testInfo);
|
||||
|
@ -65,11 +67,13 @@ public class TradeTest extends AbstractTradeTest {
|
|||
public void testTakeSellBTCOffer(final TestInfo testInfo) {
|
||||
TakeSellBTCOfferTest test = new TakeSellBTCOfferTest();
|
||||
test.testTakeAlicesSellOffer(testInfo);
|
||||
test.testPaymentMessagingPreconditions(testInfo);
|
||||
test.testBobsConfirmPaymentStarted(testInfo);
|
||||
test.testAlicesConfirmPaymentReceived(testInfo);
|
||||
test.testBobsBtcWithdrawalToExternalAddress(testInfo);
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testTakeBuyBSQOffer(final TestInfo testInfo) {
|
||||
|
@ -91,6 +95,7 @@ public class TradeTest extends AbstractTradeTest {
|
|||
test.testCloseTrade(testInfo);
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
@Order(5)
|
||||
public void testTakeSellBSQOffer(final TestInfo testInfo) {
|
||||
|
@ -107,6 +112,7 @@ public class TradeTest extends AbstractTradeTest {
|
|||
TakeBuyXMROfferTest test = new TakeBuyXMROfferTest();
|
||||
TakeBuyXMROfferTest.createXmrPaymentAccounts();
|
||||
test.testTakeAlicesSellBTCForXMROffer(testInfo);
|
||||
test.testPaymentMessagingPreconditions(testInfo);
|
||||
test.testBobsConfirmPaymentStarted(testInfo);
|
||||
test.testAlicesConfirmPaymentReceived(testInfo);
|
||||
test.testCloseTrade(testInfo);
|
||||
|
@ -118,6 +124,7 @@ public class TradeTest extends AbstractTradeTest {
|
|||
TakeSellXMROfferTest test = new TakeSellXMROfferTest();
|
||||
TakeBuyXMROfferTest.createXmrPaymentAccounts();
|
||||
test.testTakeAlicesBuyBTCForXMROffer(testInfo);
|
||||
test.testPaymentMessagingPreconditions(testInfo);
|
||||
test.testAlicesConfirmPaymentStarted(testInfo);
|
||||
test.testBobsConfirmPaymentReceived(testInfo);
|
||||
test.testAlicesBtcWithdrawalToExternalAddress(testInfo);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package bisq.core.api;
|
||||
|
||||
import bisq.core.api.exception.FailedPreconditionException;
|
||||
import bisq.core.api.exception.NotAvailableException;
|
||||
import bisq.core.api.exception.NotFoundException;
|
||||
import bisq.core.btc.model.AddressEntry;
|
||||
|
@ -177,6 +178,13 @@ class CoreTradesService {
|
|||
void confirmPaymentStarted(String tradeId) {
|
||||
var trade = getTrade(tradeId);
|
||||
if (isFollowingBuyerProtocol(trade)) {
|
||||
if (!trade.isDepositConfirmed()) {
|
||||
throw new FailedPreconditionException(
|
||||
format("cannot send a payment started message for trade '%s'%n"
|
||||
+ "until trade deposit tx '%s' is confirmed",
|
||||
trade.getId(),
|
||||
trade.getDepositTxId()));
|
||||
}
|
||||
var tradeProtocol = tradeManager.getTradeProtocol(trade);
|
||||
((BuyerProtocol) tradeProtocol).onPaymentStarted(
|
||||
() -> {
|
||||
|
@ -186,15 +194,29 @@ class CoreTradesService {
|
|||
}
|
||||
);
|
||||
} else {
|
||||
throw new IllegalStateException("you are the seller and not sending payment");
|
||||
throw new FailedPreconditionException("you are the seller, and not sending payment");
|
||||
}
|
||||
}
|
||||
|
||||
void confirmPaymentReceived(String tradeId) {
|
||||
var trade = getTrade(tradeId);
|
||||
if (isFollowingBuyerProtocol(trade)) {
|
||||
throw new IllegalStateException("you are the buyer, and not receiving payment");
|
||||
throw new FailedPreconditionException("you are the buyer, and not receiving payment");
|
||||
} else {
|
||||
if (!trade.isDepositConfirmed()) {
|
||||
throw new FailedPreconditionException(
|
||||
format("cannot send a payment received message for trade '%s'%n"
|
||||
+ "until trade deposit tx '%s' is confirmed",
|
||||
trade.getId(),
|
||||
trade.getDepositTxId()));
|
||||
}
|
||||
|
||||
if (!trade.isFiatSent()) {
|
||||
throw new FailedPreconditionException(
|
||||
format("cannot send a payment received confirmation message for trade '%s'%n"
|
||||
+ "until after a trade payment started message has been sent",
|
||||
trade.getId()));
|
||||
}
|
||||
var tradeProtocol = tradeManager.getTradeProtocol(trade);
|
||||
((SellerProtocol) tradeProtocol).onPaymentReceived(
|
||||
() -> {
|
||||
|
|
Loading…
Add table
Reference in a new issue