Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API 'getoffer' & 'gettrade' support for BSQ swaps #2 #5863

Merged
merged 21 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5924312
Adjust bsq-swap-offer related gRPC services & msgs
ghubstan Nov 11, 2021
c6aceb0
Adjust bsq-swap-offer related gRPC daemon services
ghubstan Nov 11, 2021
5d63fd7
Partially adjust api proto wrappers for bsq-swap support
ghubstan Nov 11, 2021
713b309
Add String getRole(BsqSwapTrade trade) method
ghubstan Nov 11, 2021
521495c
Add conveniences isFiatOffer(offer), isAltcoinOffer(offer)
ghubstan Nov 11, 2021
3dfbf3f
Partially adjust core api for bsq-swap support
ghubstan Nov 11, 2021
16be357
Paritally adjust bsq-swap-offer related gRPC CLI side classes
ghubstan Nov 11, 2021
c5f50b5
Paritally adjust bsq-swap-offer related apitest cases
ghubstan Nov 11, 2021
564303a
Normalize API gRPC bsq-swap related protos & wrappers
ghubstan Nov 12, 2021
9f01279
Merge branch 'master' into 1-basic-api-bsqswap-support
ghubstan Nov 12, 2021
fc53ca4
Add CLI output IntegerColumn
ghubstan Nov 14, 2021
4ca878a
Adjust API 'gettrade' for Bsq swaps
ghubstan Nov 14, 2021
d8f1e44
Try to hide from pesky codacy
ghubstan Nov 14, 2021
b65cc9c
Merge branch 'master' into 1-basic-api-bsqswap-support
ghubstan Nov 23, 2021
17277c4
Remove Get/Take BSQSwap Offer/Trade rpc service defs
ghubstan Nov 24, 2021
f88c151
Refactor GrpcTradesService: use GetTrade & TakeOffer services for BSQ…
ghubstan Nov 24, 2021
3aae052
Refactor core.api trade service implemenentations for BSQ swaps
ghubstan Nov 24, 2021
0c5c343
Adjust CLI to support getting/taking BSQ swaps
ghubstan Nov 24, 2021
6403fc1
Adjust apitest cases to rpc BSQ wwap related changes
ghubstan Nov 24, 2021
c177b3b
Merge branch 'master' into 2-api-bsq-swap-scratch
ghubstan Nov 24, 2021
00a5e2b
Merge branch 'master' into 2-refactor-api-bsqswap-support
ghubstan Nov 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package bisq.apitest.method.offer;

import bisq.proto.grpc.BsqSwapOfferInfo;
import bisq.proto.grpc.OfferInfo;

import protobuf.PaymentAccount;
Expand All @@ -42,10 +41,12 @@
import static bisq.apitest.config.BisqAppConfig.seednode;
import static bisq.cli.table.builder.TableType.OFFER_TBL;
import static bisq.common.util.MathUtils.exactMultiply;
import static java.lang.System.out;



import bisq.apitest.method.MethodTest;
import bisq.cli.CliMain;
import bisq.cli.table.builder.TableBuilder;

@Slf4j
Expand Down Expand Up @@ -112,11 +113,6 @@ public static void setUp() {
protected final Function<List<OfferInfo>, String> toOffersTable = (offers) ->
new TableBuilder(OFFER_TBL, offers).build().toString();

// TODO
protected final Function<BsqSwapOfferInfo, String> toBsqSwapOfferTable = (offer) ->
new TableBuilder(OFFER_TBL, offer).build().toString();


public static void initSwapPaymentAccounts() {
// A bot may not know what the default 'BSQ Swap' account name is,
// but API test cases do: the value of the i18n property 'BSQ_SWAP'.
Expand All @@ -140,4 +136,11 @@ public static void createLegacyBsqPaymentAccounts() {
public static void tearDown() {
tearDownScaffold();
}

protected static void runCliGetOffer(String offerId) {
out.println("Alice's CLI 'getmyoffer' response:");
CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffer", "--offer-id=" + offerId});
out.println("Bob's CLI 'getoffer' response:");
CliMain.main(new String[]{"--password=xyz", "--port=9999", "getoffer", "--offer-id=" + offerId});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

package bisq.apitest.method.offer;

import bisq.proto.grpc.BsqSwapOfferInfo;
import bisq.proto.grpc.OfferInfo;

import lombok.extern.slf4j.Slf4j;

Expand Down Expand Up @@ -121,21 +121,20 @@ private void createBsqSwapOffer() {
assertEquals(5_000, bsqSwapOffer.getPrice());
assertEquals(1_000_000L, bsqSwapOffer.getAmount());
assertEquals(1_000_000L, bsqSwapOffer.getMinAmount());
// assertEquals(alicesBsqAcct.getId(), atomicOffer.getMakerPaymentAccountId());
assertEquals(BSQ, bsqSwapOffer.getBaseCurrencyCode());
assertEquals(BTC, bsqSwapOffer.getCounterCurrencyCode());

testGetMyBsqSwapOffer(bsqSwapOffer);
testGetBsqSwapOffer(bsqSwapOffer);
}

private void testGetMyBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
private void testGetMyBsqSwapOffer(OfferInfo bsqSwapOffer) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
var fetchedBsqSwapOffer = aliceClient.getMyBsqSwapOffer(bsqSwapOfferInfo.getId());
assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId());
var fetchedBsqSwapOffer = aliceClient.getMyOffer(bsqSwapOffer.getId());
assertEquals(bsqSwapOffer.getId(), fetchedBsqSwapOffer.getId());
log.debug("Alice found her (my) new bsq swap offer on attempt # {}.", numFetchAttempts);
break;
} catch (Exception ex) {
Expand All @@ -149,13 +148,13 @@ private void testGetMyBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
}
}

private void testGetBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
private void testGetBsqSwapOffer(OfferInfo bsqSwapOffer) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
var fetchedBsqSwapOffer = bobClient.getBsqSwapOffer(bsqSwapOfferInfo.getId());
assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId());
var fetchedBsqSwapOffer = bobClient.getOffer(bsqSwapOffer.getId());
assertEquals(bsqSwapOffer.getId(), fetchedBsqSwapOffer.getId());
log.debug("Bob found new available bsq swap offer on attempt # {}.", numFetchAttempts);
break;
} catch (Exception ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
import static bisq.core.trade.model.bisq_v1.Trade.State.DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN;
import static bisq.core.trade.model.bisq_v1.Trade.State.SELLER_RECEIVED_FIAT_PAYMENT_INITIATED_MSG;
import static java.lang.String.format;
import static java.lang.System.out;
import static org.junit.jupiter.api.Assertions.*;



import bisq.apitest.method.offer.AbstractOfferTest;
import bisq.cli.CliMain;
import bisq.cli.GrpcClient;
import bisq.cli.table.builder.TableBuilder;

Expand All @@ -37,7 +39,9 @@ public class AbstractTradeTest extends AbstractOfferTest {
protected static String tradeId;

protected final Supplier<Integer> maxTradeStateAndPhaseChecks = () -> isLongRunningTest ? 10 : 2;
private final Function<GrpcClient, String> toUserName = (client) -> client.equals(aliceClient) ? "Alice" : "Bob";
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";

@BeforeAll
public static void initStaticFixtures() {
Expand Down Expand Up @@ -241,4 +245,11 @@ protected final void logTrade(Logger log,
new TableBuilder(TRADE_DETAIL_TBL, trade).build()));
}
}

protected static void runCliGetTrade(String tradeId) {
out.println("Alice's CLI 'gettrade' response:");
CliMain.main(new String[]{"--password=xyz", "--port=9998", "gettrade", "--trade-id=" + tradeId});
out.println("Bob's CLI 'gettrade' response:");
CliMain.main(new String[]{"--password=xyz", "--port=9999", "gettrade", "--trade-id=" + tradeId});
}
}
110 changes: 74 additions & 36 deletions apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

package bisq.apitest.method.trade;

import bisq.proto.grpc.BsqSwapOfferInfo;
import bisq.proto.grpc.BsqSwapTradeInfo;
import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.TradeInfo;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -28,17 +28,18 @@

import org.junit.jupiter.api.BeforeAll;
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;
import org.junit.jupiter.api.TestMethodOrder;

import static bisq.apitest.config.ApiTestConfig.BSQ;
import static bisq.apitest.config.ApiTestConfig.BTC;
import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.BSQ_SWAP;
import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static protobuf.BsqSwapTrade.State.COMPLETED;
import static protobuf.BsqSwapTrade.State.PREPARATION;
Expand All @@ -47,13 +48,12 @@


import bisq.apitest.method.offer.AbstractOfferTest;
import bisq.cli.GrpcClient;

@Disabled
// @Disabled
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BsqSwapTradeTest extends AbstractOfferTest {

private static final String BISQ_FEE_CURRENCY_CODE = BSQ;
public class BsqSwapTradeTest extends AbstractTradeTest {

// Long-running swap trade tests might want to check node logs for exceptions.
@Setter
Expand All @@ -66,7 +66,7 @@ public static void setUp() {

@BeforeEach
public void generateBtcBlock() {
genBtcBlocksThenWait(1, 2000);
genBtcBlocksThenWait(1, 2_000);
}

@Test
Expand All @@ -81,54 +81,92 @@ public void testGetBalancesBeforeTrade() {
@Test
@Order(2)
public void testAliceCreateBsqSwapBuyOffer() {
var bsqSwapOffer = aliceClient.createBsqSwapOffer(BUY.name(),
1_000_000L,
var mySwapOffer = aliceClient.createBsqSwapOffer(BUY.name(),
1_000_000L, // 0.01 BTC
1_000_000L,
"0.00005",
alicesBsqSwapAcct.getId());
log.debug("BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", bsqSwapOffer);
var newOfferId = bsqSwapOffer.getId();
log.debug("Pending BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", toOfferTable.apply(mySwapOffer));
var newOfferId = mySwapOffer.getId();
assertNotEquals("", newOfferId);
assertEquals(BUY.name(), bsqSwapOffer.getDirection());
assertEquals(5_000, bsqSwapOffer.getPrice());
assertEquals(1_000_000L, bsqSwapOffer.getAmount());
assertEquals(1_000_000L, bsqSwapOffer.getMinAmount());
// assertEquals(alicesBsqAcct.getId(), atomicOffer.getMakerPaymentAccountId());
assertEquals(BSQ, bsqSwapOffer.getBaseCurrencyCode());
assertEquals(BTC, bsqSwapOffer.getCounterCurrencyCode());
assertEquals(BUY.name(), mySwapOffer.getDirection());
assertEquals(5_000, mySwapOffer.getPrice());
assertEquals(1_000_000L, mySwapOffer.getAmount());
assertEquals(1_000_000L, mySwapOffer.getMinAmount());
assertEquals(BSQ, mySwapOffer.getBaseCurrencyCode());
assertEquals(BTC, mySwapOffer.getCounterCurrencyCode());

genBtcBlocksThenWait(1, 2_500);

mySwapOffer = aliceClient.getMyOffer(newOfferId);
log.debug("My fetched BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", toOfferTable.apply(mySwapOffer));
assertNotEquals(0, mySwapOffer.getMakerFee());

runCliGetOffer(newOfferId);
}

@Test
@Order(3)
public void testBobTakesBsqSwapOffer() {
var bsqSwapOffer = getAvailableBsqSwapOffer();
var bsqSwapTradeInfo = bobClient.takeBsqSwapOffer(bsqSwapOffer.getId(),
bobsBsqSwapAcct.getId(),
BISQ_FEE_CURRENCY_CODE);
log.debug("Trade at t1: {}", bsqSwapTradeInfo);
assertEquals(PREPARATION.name(), bsqSwapTradeInfo.getState());
var availableSwapOffer = getAvailableBsqSwapOffer(bobClient);

// Before sending a TakeOfferRequest, the CLI needs to know what kind of Offer
// it is taking (v1 or BsqSwap). Only BSQ swap offers can be taken with a
// single offerId parameter. Taking v1 offers requires an additional
// paymentAccountId param. The test case knows what kind of offer is being taken,
// but we test the gRPC GetOfferCategory service here.
var availableOfferCategory = bobClient.getAvailableOfferCategory(availableSwapOffer.getId());
assertTrue(availableOfferCategory.equals(BSQ_SWAP));

sleep(30_000);

var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId());
tradeId = swapTrade.getTradeId(); // Cache the tradeId for following test case(s).
log.debug("BsqSwap Trade at PREPARATION:\n{}", toTradeDetailTable.apply(swapTrade));
assertEquals(PREPARATION.name(), swapTrade.getState());
genBtcBlocksThenWait(1, 3_000);

bsqSwapTradeInfo = getBsqSwapTrade(bsqSwapTradeInfo.getTradeId());
log.debug("Trade at t2: {}", bsqSwapTradeInfo);
assertEquals(COMPLETED.name(), bsqSwapTradeInfo.getState());
swapTrade = getBsqSwapTrade(bobClient, tradeId);
log.debug("BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(swapTrade));
assertEquals(COMPLETED.name(), swapTrade.getState());

runCliGetTrade(tradeId);
}

@Test
@Order(4)
public void testCompletedSwapTxConfirmations() {
sleep(2_000); // Wait for TX confirmation to happen on node.

var alicesTrade = getBsqSwapTrade(aliceClient, tradeId);
log.debug("Alice's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(alicesTrade));
assertEquals(1, alicesTrade.getBsqSwapTradeInfo().getNumConfirmations());

var bobsTrade = getBsqSwapTrade(bobClient, tradeId);
log.debug("Bob's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(bobsTrade));
assertEquals(1, bobsTrade.getBsqSwapTradeInfo().getNumConfirmations());

genBtcBlocksThenWait(1, 2_000);

bobsTrade = getBsqSwapTrade(bobClient, tradeId);
log.debug("Bob's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(bobsTrade));
assertEquals(2, bobsTrade.getBsqSwapTradeInfo().getNumConfirmations());
}

@Test
@Order(5)
public void testGetBalancesAfterTrade() {
sleep(2_500); // Give wallet time to finish processing TX.
var alicesBalances = aliceClient.getBalances();
log.debug("Alice's After Trade Balance:\n{}", formatBalancesTbls(alicesBalances));
var bobsBalances = bobClient.getBalances();
log.debug("Bob's After Trade Balance:\n{}", formatBalancesTbls(bobsBalances));
}

private BsqSwapOfferInfo getAvailableBsqSwapOffer() {
List<BsqSwapOfferInfo> bsqSwapOffers = new ArrayList<>();
private OfferInfo getAvailableBsqSwapOffer(GrpcClient client) {
List<OfferInfo> bsqSwapOffers = new ArrayList<>();
int numFetchAttempts = 0;
while (bsqSwapOffers.size() == 0) {
bsqSwapOffers.addAll(bobClient.getBsqSwapOffers(BUY.name(), BSQ));
bsqSwapOffers.addAll(client.getBsqSwapOffers(BUY.name()));
numFetchAttempts++;
if (bsqSwapOffers.size() == 0) {
log.warn("No available bsq swap offers found after {} fetch attempts.", numFetchAttempts);
Expand All @@ -138,7 +176,7 @@ private BsqSwapOfferInfo getAvailableBsqSwapOffer() {
}
fail(format("Bob gave up on fetching available bsq swap offers after %d attempts.", numFetchAttempts));
}
sleep(1000);
sleep(1_000);
} else {
assertEquals(1, bsqSwapOffers.size());
log.debug("Bob found new available bsq swap offer on attempt # {}.", numFetchAttempts);
Expand All @@ -150,12 +188,12 @@ private BsqSwapOfferInfo getAvailableBsqSwapOffer() {
return bsqSwapOffer;
}

private BsqSwapTradeInfo getBsqSwapTrade(String tradeId) {
private TradeInfo getBsqSwapTrade(GrpcClient client, String tradeId) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
return bobClient.getBsqSwapTrade(tradeId);
return client.getTrade(tradeId);
} catch (Exception ex) {
log.warn(ex.getMessage());
if (numFetchAttempts > 9) {
Expand All @@ -164,7 +202,7 @@ private BsqSwapTradeInfo getBsqSwapTrade(String tradeId) {
}
fail(format("Could not find new bsq swap trade after %d attempts.", numFetchAttempts));
} else {
sleep(1000);
sleep(1_000);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions apitest/src/test/java/bisq/apitest/scenario/TradeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ public void testTakeSellBSQOffer(final TestInfo testInfo) {
@Order(6)
public void testBsqSwapTradeTest(final TestInfo testInfo) {
BsqSwapTradeTest test = new BsqSwapTradeTest();
test.testGetBalancesBeforeTrade();
test.testAliceCreateBsqSwapBuyOffer();
test.testBobTakesBsqSwapOffer();
test.testGetBalancesAfterTrade();
}
}