mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-03 10:46:54 +01:00
Adjust API 'gettrade' for Bsq swaps
- Made several adjustments to CLI's 'gettrade' output related code so it can show single trade details for either Bisq v1 trades, or BSQ swap trades. - Did minor refactoring of API's core to retrieve # tx confirmations for an addresses and transactions. - Show # of tx confirmations in bsq swap trade detail.
This commit is contained in:
parent
fc53ca48c1
commit
4ca878a8e1
13 changed files with 275 additions and 96 deletions
|
@ -111,21 +111,39 @@ public class BsqSwapTradeTest extends AbstractTradeTest {
|
|||
var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId(),
|
||||
bobsBsqSwapAcct.getId(),
|
||||
BISQ_FEE_CURRENCY_CODE);
|
||||
log.debug("BsqSwap Trade at PREPARATION: {}", swapTrade);
|
||||
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);
|
||||
|
||||
swapTrade = getBsqSwapTrade(bobClient, swapTrade.getTradeId());
|
||||
log.debug("BsqSwap Trade at COMPLETION: {}", swapTrade);
|
||||
log.debug("BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(swapTrade));
|
||||
assertEquals(COMPLETED.name(), swapTrade.getState());
|
||||
}
|
||||
|
||||
@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() {
|
||||
genBtcBlocksThenWait(1, 5_000);
|
||||
var alicesBalances = aliceClient.getBalances();
|
||||
log.debug("Alice's After Trade Balance:\n{}", formatBalancesTbls(alicesBalances));
|
||||
var bobsBalances = bobClient.getBalances();
|
||||
|
|
|
@ -102,6 +102,15 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
@Nullable
|
||||
protected final Column<String> colAltcoinReceiveAddressColumn;
|
||||
|
||||
// BSQ swap trade detail specific columns
|
||||
|
||||
@Nullable
|
||||
protected final Column<String> status;
|
||||
@Nullable
|
||||
protected final Column<String> colTxId;
|
||||
@Nullable
|
||||
protected final Column<Long> colNumConfirmations;
|
||||
|
||||
AbstractTradeListBuilder(TableType tableType, List<?> protos) {
|
||||
super(tableType, protos);
|
||||
validate();
|
||||
|
@ -125,7 +134,9 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
this.colRole = colSupplier.roleColumn.get();
|
||||
this.colOfferType = colSupplier.offerTypeColumn.get();
|
||||
this.colStatusDescription = colSupplier.statusDescriptionColumn.get();
|
||||
// Trade detail specific columns
|
||||
|
||||
// Trade detail specific columns, some in common with BSQ swap trades detail.
|
||||
|
||||
this.colIsDepositPublished = colSupplier.depositPublishedColumn.get();
|
||||
this.colIsDepositConfirmed = colSupplier.depositConfirmedColumn.get();
|
||||
this.colIsPayoutPublished = colSupplier.payoutPublishedColumn.get();
|
||||
|
@ -135,6 +146,12 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
this.colIsPaymentSent = colSupplier.paymentSentColumn.get();
|
||||
this.colIsPaymentReceived = colSupplier.paymentReceivedColumn.get();
|
||||
this.colAltcoinReceiveAddressColumn = colSupplier.altcoinReceiveAddressColumn.get();
|
||||
|
||||
// BSQ swap trade detail specific columns
|
||||
|
||||
this.status = colSupplier.bsqSwapStatusColumn.get();
|
||||
this.colTxId = colSupplier.bsqSwapTxIdColumn.get();
|
||||
this.colNumConfirmations = colSupplier.numConfirmationsColumn.get();
|
||||
}
|
||||
|
||||
protected void validate() {
|
||||
|
@ -149,9 +166,8 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
// Helper Functions
|
||||
|
||||
private final Supplier<Boolean> isTradeDetailTblBuilder = () -> tableType.equals(TRADE_DETAIL_TBL);
|
||||
|
||||
protected final Predicate<TradeInfo> isFiatTrade = (t) -> isFiatOffer.test(t.getOffer());
|
||||
|
||||
protected final Predicate<TradeInfo> isBsqSwapTrade = (t) -> t.getOffer().getIsBsqSwapOffer();
|
||||
protected final Predicate<TradeInfo> isTaker = (t) -> t.getRole().toLowerCase().contains("taker");
|
||||
|
||||
// Column Value Functions
|
||||
|
@ -185,7 +201,6 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO Move to TradeUtil ?
|
||||
protected final Function<TradeInfo, String> toPriceDeviation = (t) ->
|
||||
t.getOffer().getUseMarketBasedPrice()
|
||||
? formatToPercent(t.getOffer().getMarketPriceMargin())
|
||||
|
@ -196,8 +211,6 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
? t.getTxFeeAsLong()
|
||||
: t.getOffer().getTxFee();
|
||||
|
||||
|
||||
// TODO Move to TradeUtil ?
|
||||
protected final BiFunction<TradeInfo, Boolean, Long> toTradeFeeBsq = (t, isMyOffer) -> {
|
||||
if (isMyOffer) {
|
||||
return t.getOffer().getIsCurrencyForMakerFeeBtc()
|
||||
|
@ -210,7 +223,6 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO Move to TradeUtil ?
|
||||
protected final BiFunction<TradeInfo, Boolean, Long> toTradeFeeBtc = (t, isMyOffer) -> {
|
||||
if (isMyOffer) {
|
||||
return t.getOffer().getIsCurrencyForMakerFeeBtc()
|
||||
|
@ -223,12 +235,18 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
}
|
||||
};
|
||||
|
||||
protected final Function<TradeInfo, Long> toMyMakerOrTakerFee = (t) ->
|
||||
isTaker.test(t)
|
||||
protected final Function<TradeInfo, Long> toMyMakerOrTakerFee = (t) -> {
|
||||
if (isBsqSwapTrade.test(t)) {
|
||||
return isTaker.test(t)
|
||||
? t.getBsqSwapTradeInfo().getBsqTakerTradeFee()
|
||||
: t.getBsqSwapTradeInfo().getBsqMakerTradeFee();
|
||||
} else {
|
||||
return isTaker.test(t)
|
||||
? t.getTakerFeeAsLong()
|
||||
: t.getOffer().getMakerFee();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO Move to TradeUtil ? SEE ClosedTradesViewModel # getDirectionLabel
|
||||
protected final Function<TradeInfo, String> toOfferType = (t) -> {
|
||||
if (isFiatTrade.test(t)) {
|
||||
return t.getOffer().getDirection() + " " + t.getOffer().getBaseCurrencyCode();
|
||||
|
@ -267,7 +285,7 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO Stuff to move into bisq/cli/CurrencyFormat.java ?
|
||||
// TODO Move to bisq/cli/CurrencyFormat.java ?
|
||||
|
||||
public static String formatToPercent(double value) {
|
||||
DecimalFormat decimalFormat = new DecimalFormat("#.##");
|
||||
|
|
|
@ -35,6 +35,7 @@ class TableBuilderConstants {
|
|||
static final String COL_HEADER_LOCKUP_BONDS_BALANCE = "Lockup Bonds Balance";
|
||||
static final String COL_HEADER_UNLOCKING_BONDS_BALANCE = "Unlocking Bonds Balance";
|
||||
static final String COL_HEADER_UNVERIFIED_BALANCE = "Unverified Balance";
|
||||
static final String COL_HEADER_BSQ_SWAP_TRADE_ROLE = "My BSQ Swap Role";
|
||||
static final String COL_HEADER_BUYER_DEPOSIT = "Buyer Deposit";
|
||||
static final String COL_HEADER_SELLER_DEPOSIT = "Seller Deposit";
|
||||
static final String COL_HEADER_CONFIRMATIONS = "Confirmations";
|
||||
|
@ -65,8 +66,6 @@ class TableBuilderConstants {
|
|||
static final String COL_HEADER_TRADE_ID = "Trade ID";
|
||||
static final String COL_HEADER_TRADE_ROLE = "My Role";
|
||||
static final String COL_HEADER_TRADE_SHORT_ID = "ID";
|
||||
@Deprecated
|
||||
static final String COL_HEADER_TRADE_TX_FEE = "Tx Fee(BTC)";
|
||||
static final String COL_HEADER_TRADE_MAKER_FEE = "Maker Fee(%-3s)";
|
||||
static final String COL_HEADER_TRADE_TAKER_FEE = "Taker Fee(%-3s)";
|
||||
static final String COL_HEADER_TRADE_FEE = "Trade Fee";
|
||||
|
|
|
@ -17,10 +17,16 @@
|
|||
|
||||
package bisq.cli.table.builder;
|
||||
|
||||
import bisq.proto.grpc.TradeInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static bisq.cli.table.builder.TableType.TRADE_DETAIL_TBL;
|
||||
import static java.lang.String.format;
|
||||
import static protobuf.BsqSwapTrade.State.COMPLETED;
|
||||
import static protobuf.BsqSwapTrade.State.PREPARATION;
|
||||
|
||||
|
||||
|
||||
|
@ -30,8 +36,12 @@ import bisq.cli.table.column.Column;
|
|||
/**
|
||||
* Builds a {@code bisq.cli.table.Table} from a {@code bisq.proto.grpc.TradeInfo} object.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
class TradeDetailTableBuilder extends AbstractTradeListBuilder {
|
||||
|
||||
private final Predicate<TradeInfo> isPendingBsqSwap = (t) -> t.getState().equals(PREPARATION.name());
|
||||
private final Predicate<TradeInfo> isCompletedBsqSwap = (t) -> t.getState().equals(COMPLETED.name());
|
||||
|
||||
TradeDetailTableBuilder(List<?> protos) {
|
||||
super(TRADE_DETAIL_TBL, protos);
|
||||
}
|
||||
|
@ -41,33 +51,70 @@ class TradeDetailTableBuilder extends AbstractTradeListBuilder {
|
|||
* @return Table containing one row
|
||||
*/
|
||||
public Table build() {
|
||||
populateColumns();
|
||||
List<Column<?>> columns = defineColumnList();
|
||||
// A trade detail table only has one row.
|
||||
var trade = trades.get(0);
|
||||
populateColumns(trade);
|
||||
List<Column<?>> columns = defineColumnList(trade);
|
||||
return new Table(columns.toArray(new Column<?>[0]));
|
||||
}
|
||||
|
||||
private void populateColumns() {
|
||||
trades.stream().forEachOrdered(t -> {
|
||||
colTradeId.addRow(t.getShortId());
|
||||
colRole.addRow(t.getRole());
|
||||
colPrice.addRow(t.getTradePrice());
|
||||
colAmountInBtc.addRow(toAmount.apply(t));
|
||||
colMinerTxFee.addRow(toMyMinerTxFee.apply(t));
|
||||
colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(t));
|
||||
colIsDepositPublished.addRow(t.getIsDepositPublished());
|
||||
colIsDepositConfirmed.addRow(t.getIsDepositConfirmed());
|
||||
colTradeCost.addRow(toTradeVolume.apply(t));
|
||||
colIsPaymentSent.addRow(t.getIsFiatSent());
|
||||
colIsPaymentReceived.addRow(t.getIsFiatReceived());
|
||||
colIsPayoutPublished.addRow(t.getIsPayoutPublished());
|
||||
colIsFundsWithdrawn.addRow(t.getIsWithdrawn());
|
||||
|
||||
if (colAltcoinReceiveAddressColumn != null)
|
||||
colAltcoinReceiveAddressColumn.addRow(toAltcoinReceiveAddress.apply(t));
|
||||
});
|
||||
private void populateColumns(TradeInfo trade) {
|
||||
if (isBsqSwapTrade.test(trade)) {
|
||||
var isPending = isPendingBsqSwap.test(trade);
|
||||
var isCompleted = isCompletedBsqSwap.test(trade);
|
||||
if (isPending == isCompleted)
|
||||
throw new IllegalStateException(
|
||||
format("programmer error: trade must be either pending or completed, is pending=%s and completed=%s",
|
||||
isPending,
|
||||
isCompleted));
|
||||
populateBsqSwapTradeColumns(trade);
|
||||
} else {
|
||||
populateBisqV1TradeColumns(trade);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Column<?>> defineColumnList() {
|
||||
private void populateBisqV1TradeColumns(TradeInfo trade) {
|
||||
colTradeId.addRow(trade.getShortId());
|
||||
colRole.addRow(trade.getRole());
|
||||
colPrice.addRow(trade.getTradePrice());
|
||||
colAmountInBtc.addRow(toAmount.apply(trade));
|
||||
colMinerTxFee.addRow(toMyMinerTxFee.apply(trade));
|
||||
colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(trade));
|
||||
colIsDepositPublished.addRow(trade.getIsDepositPublished());
|
||||
colIsDepositConfirmed.addRow(trade.getIsDepositConfirmed());
|
||||
colTradeCost.addRow(toTradeVolume.apply(trade));
|
||||
colIsPaymentSent.addRow(trade.getIsFiatSent());
|
||||
colIsPaymentReceived.addRow(trade.getIsFiatReceived());
|
||||
colIsPayoutPublished.addRow(trade.getIsPayoutPublished());
|
||||
colIsFundsWithdrawn.addRow(trade.getIsWithdrawn());
|
||||
if (colAltcoinReceiveAddressColumn != null)
|
||||
colAltcoinReceiveAddressColumn.addRow(toAltcoinReceiveAddress.apply(trade));
|
||||
}
|
||||
|
||||
private void populateBsqSwapTradeColumns(TradeInfo trade) {
|
||||
colTradeId.addRow(trade.getShortId());
|
||||
colRole.addRow(trade.getRole());
|
||||
colPrice.addRow(trade.getTradePrice());
|
||||
colAmountInBtc.addRow(toAmount.apply(trade));
|
||||
colMinerTxFee.addRow(toMyMinerTxFee.apply(trade));
|
||||
colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(trade));
|
||||
colTradeCost.addRow(toTradeVolume.apply(trade));
|
||||
|
||||
var isCompleted = isCompletedBsqSwap.test(trade);
|
||||
status.addRow(isCompleted ? "COMPLETED" : "PENDING");
|
||||
if (isCompleted) {
|
||||
colTxId.addRow(trade.getBsqSwapTradeInfo().getTxId());
|
||||
colNumConfirmations.addRow(trade.getBsqSwapTradeInfo().getNumConfirmations());
|
||||
}
|
||||
}
|
||||
|
||||
private List<Column<?>> defineColumnList(TradeInfo trade) {
|
||||
return isBsqSwapTrade.test(trade)
|
||||
? getBsqSwapTradeColumnList(isCompletedBsqSwap.test(trade))
|
||||
: getBisqV1TradeColumnList();
|
||||
}
|
||||
|
||||
private List<Column<?>> getBisqV1TradeColumnList() {
|
||||
List<Column<?>> columns = new ArrayList<>() {{
|
||||
add(colTradeId);
|
||||
add(colRole);
|
||||
|
@ -89,4 +136,25 @@ class TradeDetailTableBuilder extends AbstractTradeListBuilder {
|
|||
|
||||
return columns;
|
||||
}
|
||||
|
||||
private List<Column<?>> getBsqSwapTradeColumnList(boolean isCompleted) {
|
||||
List<Column<?>> columns = new ArrayList<>() {{
|
||||
add(colTradeId);
|
||||
add(colRole);
|
||||
add(colPrice.asStringColumn());
|
||||
add(colAmountInBtc.asStringColumn());
|
||||
add(colMinerTxFee.asStringColumn());
|
||||
add(colBisqTradeFee.asStringColumn());
|
||||
add(colTradeCost.asStringColumn());
|
||||
add(status);
|
||||
}};
|
||||
|
||||
if (isCompleted)
|
||||
columns.add(colTxId);
|
||||
|
||||
if (!colNumConfirmations.isEmpty())
|
||||
columns.add(colNumConfirmations.asStringColumn());
|
||||
|
||||
return columns;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import static bisq.cli.table.column.AltcoinColumn.DISPLAY_MODE.ALTCOIN_OFFER_VOL
|
|||
import static bisq.cli.table.column.Column.JUSTIFICATION.LEFT;
|
||||
import static bisq.cli.table.column.Column.JUSTIFICATION.RIGHT;
|
||||
import static bisq.cli.table.column.FiatColumn.DISPLAY_MODE.VOLUME;
|
||||
import static java.lang.String.format;
|
||||
|
||||
|
||||
|
||||
|
@ -49,6 +50,7 @@ import bisq.cli.table.column.BtcColumn;
|
|||
import bisq.cli.table.column.Column;
|
||||
import bisq.cli.table.column.FiatColumn;
|
||||
import bisq.cli.table.column.Iso8601DateTimeColumn;
|
||||
import bisq.cli.table.column.LongColumn;
|
||||
import bisq.cli.table.column.MixedPriceColumn;
|
||||
import bisq.cli.table.column.MixedTradeFeeColumn;
|
||||
import bisq.cli.table.column.MixedVolumeColumn;
|
||||
|
@ -79,7 +81,10 @@ class TradeTableColumnSupplier {
|
|||
private final Supplier<TradeInfo> firstRow = () -> getTrades().get(0);
|
||||
private final Predicate<OfferInfo> isFiatOffer = (o) -> o.getBaseCurrencyCode().equals("BTC");
|
||||
private final Predicate<TradeInfo> isFiatTrade = (t) -> isFiatOffer.test(t.getOffer());
|
||||
private final Predicate<TradeInfo> isBsqSwapTrade = (t) -> t.getOffer().getIsBsqSwapOffer();
|
||||
private final Predicate<TradeInfo> isTaker = (t) -> t.getRole().toLowerCase().contains("taker");
|
||||
private final Supplier<Boolean> isSwapTradeDetail = () ->
|
||||
isTradeDetailTblBuilder.get() && isBsqSwapTrade.test(firstRow.get());
|
||||
|
||||
final Supplier<StringColumn> tradeIdColumn = () -> isTradeDetailTblBuilder.get()
|
||||
? new StringColumn(COL_HEADER_TRADE_SHORT_ID)
|
||||
|
@ -95,8 +100,8 @@ class TradeTableColumnSupplier {
|
|||
|
||||
private final Function<TradeInfo, Column<Long>> toDetailedPriceColumn = (t) -> {
|
||||
String colHeader = isFiatTrade.test(t)
|
||||
? String.format(COL_HEADER_DETAILED_PRICE, t.getOffer().getCounterCurrencyCode())
|
||||
: String.format(COL_HEADER_DETAILED_PRICE_OF_ALTCOIN, t.getOffer().getBaseCurrencyCode());
|
||||
? format(COL_HEADER_DETAILED_PRICE, t.getOffer().getCounterCurrencyCode())
|
||||
: format(COL_HEADER_DETAILED_PRICE_OF_ALTCOIN, t.getOffer().getBaseCurrencyCode());
|
||||
return isFiatTrade.test(t)
|
||||
? new FiatColumn(colHeader)
|
||||
: new AltcoinColumn(colHeader);
|
||||
|
@ -116,7 +121,7 @@ class TradeTableColumnSupplier {
|
|||
|
||||
private final Function<TradeInfo, Column<Long>> toDetailedAmountColumn = (t) -> {
|
||||
String headerCurrencyCode = t.getOffer().getBaseCurrencyCode();
|
||||
String colHeader = String.format(COL_HEADER_DETAILED_AMOUNT, headerCurrencyCode);
|
||||
String colHeader = format(COL_HEADER_DETAILED_AMOUNT, headerCurrencyCode);
|
||||
return isFiatTrade.test(t)
|
||||
? new SatoshiColumn(colHeader)
|
||||
: new AltcoinColumn(colHeader, ALTCOIN_OFFER_VOLUME);
|
||||
|
@ -142,10 +147,14 @@ class TradeTableColumnSupplier {
|
|||
? null
|
||||
: new StringColumn(COL_HEADER_PAYMENT_METHOD, LEFT);
|
||||
|
||||
final Supplier<StringColumn> roleColumn = () ->
|
||||
isTradeDetailTblBuilder.get() || isOpenTradeTblBuilder.get() || isFailedTradeTblBuilder.get()
|
||||
final Supplier<StringColumn> roleColumn = () -> {
|
||||
if (isSwapTradeDetail.get())
|
||||
return new StringColumn(COL_HEADER_BSQ_SWAP_TRADE_ROLE);
|
||||
else
|
||||
return isTradeDetailTblBuilder.get() || isOpenTradeTblBuilder.get() || isFailedTradeTblBuilder.get()
|
||||
? new StringColumn(COL_HEADER_TRADE_ROLE)
|
||||
: null;
|
||||
};
|
||||
|
||||
final Function<String, Column<Long>> toSecurityDepositColumn = (name) -> isClosedTradeTblBuilder.get()
|
||||
? new SatoshiColumn(name)
|
||||
|
@ -161,21 +170,42 @@ class TradeTableColumnSupplier {
|
|||
|
||||
private final Function<String, Column<Boolean>> toBooleanColumn = BooleanColumn::new;
|
||||
|
||||
final Supplier<Column<Boolean>> depositPublishedColumn = () -> isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_PUBLISHED)
|
||||
: null;
|
||||
final Supplier<Column<Boolean>> depositPublishedColumn = () -> {
|
||||
if (isSwapTradeDetail.get())
|
||||
return null;
|
||||
else
|
||||
return isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_PUBLISHED)
|
||||
: null;
|
||||
};
|
||||
|
||||
final Supplier<Column<Boolean>> depositConfirmedColumn = () -> isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_CONFIRMED)
|
||||
: null;
|
||||
final Supplier<Column<Boolean>> depositConfirmedColumn = () -> {
|
||||
if (isSwapTradeDetail.get())
|
||||
return null;
|
||||
else
|
||||
return isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_CONFIRMED)
|
||||
: null;
|
||||
|
||||
final Supplier<Column<Boolean>> payoutPublishedColumn = () -> isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_PAYOUT_PUBLISHED)
|
||||
: null;
|
||||
};
|
||||
|
||||
final Supplier<Column<Boolean>> fundsWithdrawnColumn = () -> isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_WITHDRAWN)
|
||||
: null;
|
||||
final Supplier<Column<Boolean>> payoutPublishedColumn = () -> {
|
||||
if (isSwapTradeDetail.get())
|
||||
return null;
|
||||
else
|
||||
return isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_PAYOUT_PUBLISHED)
|
||||
: null;
|
||||
};
|
||||
|
||||
final Supplier<Column<Boolean>> fundsWithdrawnColumn = () -> {
|
||||
if (isSwapTradeDetail.get())
|
||||
return null;
|
||||
else
|
||||
return isTradeDetailTblBuilder.get()
|
||||
? toBooleanColumn.apply(COL_HEADER_TRADE_WITHDRAWN)
|
||||
: null;
|
||||
};
|
||||
|
||||
final Supplier<Column<Long>> bisqTradeDetailFeeColumn = () -> {
|
||||
if (isTradeDetailTblBuilder.get()) {
|
||||
|
@ -184,8 +214,8 @@ class TradeTableColumnSupplier {
|
|||
? t.getIsCurrencyForTakerFeeBtc() ? "BTC" : "BSQ"
|
||||
: t.getOffer().getIsCurrencyForMakerFeeBtc() ? "BTC" : "BSQ";
|
||||
String colHeader = isTaker.test(t)
|
||||
? String.format(COL_HEADER_TRADE_TAKER_FEE, headerCurrencyCode)
|
||||
: String.format(COL_HEADER_TRADE_MAKER_FEE, headerCurrencyCode);
|
||||
? format(COL_HEADER_TRADE_TAKER_FEE, headerCurrencyCode)
|
||||
: format(COL_HEADER_TRADE_MAKER_FEE, headerCurrencyCode);
|
||||
boolean isBsqSatoshis = headerCurrencyCode.equals("BSQ");
|
||||
return new SatoshiColumn(colHeader, isBsqSatoshis);
|
||||
} else {
|
||||
|
@ -201,7 +231,7 @@ class TradeTableColumnSupplier {
|
|||
final Supplier<Column<Boolean>> paymentSentColumn = () -> {
|
||||
if (isTradeDetailTblBuilder.get()) {
|
||||
String headerCurrencyCode = toPaymentCurrencyCode.apply(firstRow.get());
|
||||
String colHeader = String.format(COL_HEADER_TRADE_PAYMENT_SENT, headerCurrencyCode);
|
||||
String colHeader = format(COL_HEADER_TRADE_PAYMENT_SENT, headerCurrencyCode);
|
||||
return new BooleanColumn(colHeader);
|
||||
} else {
|
||||
return null;
|
||||
|
@ -211,7 +241,7 @@ class TradeTableColumnSupplier {
|
|||
final Supplier<Column<Boolean>> paymentReceivedColumn = () -> {
|
||||
if (isTradeDetailTblBuilder.get()) {
|
||||
String headerCurrencyCode = toPaymentCurrencyCode.apply(firstRow.get());
|
||||
String colHeader = String.format(COL_HEADER_TRADE_PAYMENT_RECEIVED, headerCurrencyCode);
|
||||
String colHeader = format(COL_HEADER_TRADE_PAYMENT_RECEIVED, headerCurrencyCode);
|
||||
return new BooleanColumn(colHeader);
|
||||
} else {
|
||||
return null;
|
||||
|
@ -222,7 +252,7 @@ class TradeTableColumnSupplier {
|
|||
if (isTradeDetailTblBuilder.get()) {
|
||||
TradeInfo t = firstRow.get();
|
||||
String headerCurrencyCode = t.getOffer().getCounterCurrencyCode();
|
||||
String colHeader = String.format(COL_HEADER_TRADE_BUYER_COST, headerCurrencyCode);
|
||||
String colHeader = format(COL_HEADER_TRADE_BUYER_COST, headerCurrencyCode);
|
||||
return isFiatTrade.test(t)
|
||||
? new FiatColumn(colHeader, VOLUME)
|
||||
: new SatoshiColumn(colHeader);
|
||||
|
@ -231,6 +261,18 @@ class TradeTableColumnSupplier {
|
|||
}
|
||||
};
|
||||
|
||||
final Supplier<Column<String>> bsqSwapTxIdColumn = () -> isSwapTradeDetail.get()
|
||||
? new StringColumn(COL_HEADER_TX_ID)
|
||||
: null;
|
||||
|
||||
final Supplier<Column<String>> bsqSwapStatusColumn = () -> isSwapTradeDetail.get()
|
||||
? new StringColumn(COL_HEADER_STATUS)
|
||||
: null;
|
||||
|
||||
final Supplier<Column<Long>> numConfirmationsColumn = () -> isSwapTradeDetail.get()
|
||||
? new LongColumn(COL_HEADER_CONFIRMATIONS)
|
||||
: null;
|
||||
|
||||
final Predicate<TradeInfo> showAltCoinBuyerAddress = (t) -> {
|
||||
if (isFiatTrade.test(t)) {
|
||||
return false;
|
||||
|
@ -251,7 +293,7 @@ class TradeTableColumnSupplier {
|
|||
TradeInfo t = firstRow.get();
|
||||
if (showAltCoinBuyerAddress.test(t)) {
|
||||
String headerCurrencyCode = toPaymentCurrencyCode.apply(t);
|
||||
String colHeader = String.format(COL_HEADER_TRADE_ALTCOIN_BUYER_ADDRESS, headerCurrencyCode);
|
||||
String colHeader = format(COL_HEADER_TRADE_ALTCOIN_BUYER_ADDRESS, headerCurrencyCode);
|
||||
return new StringColumn(colHeader);
|
||||
} else {
|
||||
return null;
|
||||
|
|
|
@ -401,6 +401,10 @@ public class CoreApi {
|
|||
return walletsService.getTransaction(txId);
|
||||
}
|
||||
|
||||
public int getTransactionConfirmations(String txId) {
|
||||
return walletsService.getTransactionConfirmations(txId);
|
||||
}
|
||||
|
||||
public void setWalletPassword(String password, String newPassword) {
|
||||
walletsService.setWalletPassword(password, newPassword);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ import javax.annotation.Nullable;
|
|||
import static bisq.core.btc.wallet.Restrictions.getMinNonDustOutput;
|
||||
import static bisq.core.util.ParsingUtils.parseToCoin;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
@Singleton
|
||||
|
@ -209,10 +210,10 @@ class CoreWalletsService {
|
|||
}
|
||||
|
||||
return addressStrings.stream().map(address ->
|
||||
new AddressBalanceInfo(address,
|
||||
balances.getUnchecked(address),
|
||||
getNumConfirmationsForMostRecentTransaction(address),
|
||||
btcWalletService.isAddressUnused(getAddressEntry(address).getAddress())))
|
||||
new AddressBalanceInfo(address,
|
||||
balances.getUnchecked(address),
|
||||
getNumConfirmationsForMostRecentTransaction(address),
|
||||
btcWalletService.isAddressUnused(getAddressEntry(address).getAddress())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -324,7 +325,7 @@ class CoreWalletsService {
|
|||
for (TransactionOutput txOut : spendableBsqTxOutputs) {
|
||||
if (isTxOutputAddressMatch.test(txOut) && isTxOutputValueMatch.test(txOut)) {
|
||||
log.info("\t\tTx {} output has matching address {} and value {}.",
|
||||
txOut.getParentTransaction().getTxId(),
|
||||
requireNonNull(txOut.getParentTransaction()).getTxId(),
|
||||
address,
|
||||
txOut.getValue().toPlainString());
|
||||
numMatches++;
|
||||
|
@ -346,6 +347,7 @@ class CoreWalletsService {
|
|||
@SuppressWarnings({"unchecked", "Convert2MethodRef"})
|
||||
ListenableFuture<Void> future =
|
||||
(ListenableFuture<Void>) executor.submit(() -> feeService.requestFees());
|
||||
//noinspection NullableProblems
|
||||
Futures.addCallback(future, new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void ignored) {
|
||||
|
@ -393,23 +395,11 @@ class CoreWalletsService {
|
|||
}
|
||||
|
||||
Transaction getTransaction(String txId) {
|
||||
if (txId.length() != 64)
|
||||
throw new IllegalArgumentException(format("%s is not a transaction id", txId));
|
||||
return getTransactionWithId(txId);
|
||||
}
|
||||
|
||||
try {
|
||||
Transaction tx = btcWalletService.getTransaction(txId);
|
||||
if (tx == null)
|
||||
throw new IllegalArgumentException(format("tx with id %s not found", txId));
|
||||
else
|
||||
return tx;
|
||||
|
||||
} catch (IllegalArgumentException ex) {
|
||||
log.error("", ex);
|
||||
throw new IllegalArgumentException(
|
||||
format("could not get transaction with id %s%ncause: %s",
|
||||
txId,
|
||||
ex.getMessage().toLowerCase()));
|
||||
}
|
||||
int getTransactionConfirmations(String txId) {
|
||||
return getTransactionWithId(txId).getConfidence().getDepthInBlocks();
|
||||
}
|
||||
|
||||
int getNumConfirmationsForMostRecentTransaction(String addressString) {
|
||||
|
@ -654,12 +644,32 @@ class CoreWalletsService {
|
|||
return addressEntry.get();
|
||||
}
|
||||
|
||||
private Transaction getTransactionWithId(String txId) {
|
||||
if (txId.length() != 64)
|
||||
throw new IllegalArgumentException(format("%s is not a transaction id", txId));
|
||||
|
||||
try {
|
||||
Transaction tx = btcWalletService.getTransaction(txId);
|
||||
if (tx == null)
|
||||
throw new IllegalArgumentException(format("tx with id %s not found", txId));
|
||||
else
|
||||
return tx;
|
||||
|
||||
} catch (IllegalArgumentException ex) {
|
||||
log.error("", ex);
|
||||
throw new IllegalArgumentException(
|
||||
format("could not get transaction with id %s%ncause: %s",
|
||||
txId,
|
||||
ex.getMessage().toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Memoization stores the results of expensive function calls and returns
|
||||
* the cached result when the same input occurs again.
|
||||
*
|
||||
* Resulting LoadingCache is used by calling `.get(input I)` or
|
||||
* `.getUnchecked(input I)`, depending on whether or not `f` can return null.
|
||||
* `.getUnchecked(input I)`, depending on whether `f` can return null.
|
||||
* That's because CacheLoader throws an exception on null output from `f`.
|
||||
*/
|
||||
private static <I, O> LoadingCache<I, O> memoize(Function<I, O> f) {
|
||||
|
|
|
@ -39,6 +39,7 @@ public class BsqSwapTradeInfo implements Payload {
|
|||
private final String makerBtcAddress;
|
||||
private final String takerBsqAddress;
|
||||
private final String takerBtcAddress;
|
||||
private final long numConfirmations;
|
||||
private final String errorMessage;
|
||||
|
||||
public BsqSwapTradeInfo(BsqSwapTradeInfoBuilder builder) {
|
||||
|
@ -52,10 +53,13 @@ public class BsqSwapTradeInfo implements Payload {
|
|||
this.makerBtcAddress = builder.getMakerBtcAddress();
|
||||
this.takerBsqAddress = builder.getTakerBsqAddress();
|
||||
this.takerBtcAddress = builder.getTakerBtcAddress();
|
||||
this.numConfirmations = builder.getNumConfirmations();
|
||||
this.errorMessage = builder.getErrorMessage();
|
||||
}
|
||||
|
||||
public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, boolean wasMyOffer) {
|
||||
public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade,
|
||||
boolean wasMyOffer,
|
||||
int numConfirmations) {
|
||||
var protocolModel = trade.getBsqSwapProtocolModel();
|
||||
var swapPeer = protocolModel.getTradePeer();
|
||||
var makerBsqAddress = wasMyOffer ? protocolModel.getBsqAddress() : swapPeer.getBsqAddress();
|
||||
|
@ -73,6 +77,7 @@ public class BsqSwapTradeInfo implements Payload {
|
|||
.withMakerBtcAddress(makerBtcAddress)
|
||||
.withTakerBsqAddress(takerBsqAddress)
|
||||
.withTakerBtcAddress(takerBtcAddress)
|
||||
.withNumConfirmations(numConfirmations)
|
||||
.withErrorMessage(trade.getErrorMessage())
|
||||
.build();
|
||||
}
|
||||
|
@ -94,7 +99,8 @@ public class BsqSwapTradeInfo implements Payload {
|
|||
.setTakerBsqAddress(takerBsqAddress != null ? takerBsqAddress : "")
|
||||
.setMakerBtcAddress(makerBtcAddress != null ? makerBtcAddress : "")
|
||||
.setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "")
|
||||
.setErrorMessage(errorMessage != null ? errorMessage : "")
|
||||
.setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "")
|
||||
.setNumConfirmations(numConfirmations)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -110,6 +116,7 @@ public class BsqSwapTradeInfo implements Payload {
|
|||
.withMakerBtcAddress(proto.getMakerBtcAddress())
|
||||
.withTakerBsqAddress(proto.getTakerBsqAddress())
|
||||
.withTakerBtcAddress(proto.getTakerBtcAddress())
|
||||
.withNumConfirmations(proto.getNumConfirmations())
|
||||
.withErrorMessage(proto.getErrorMessage())
|
||||
.build();
|
||||
}
|
||||
|
@ -127,6 +134,7 @@ public class BsqSwapTradeInfo implements Payload {
|
|||
", makerBtcAddress='" + makerBtcAddress + '\'' +
|
||||
", takerBsqAddress='" + takerBsqAddress + '\'' +
|
||||
", takerBtcAddress='" + takerBtcAddress + '\'' +
|
||||
", numConfirmations='" + numConfirmations + '\'' +
|
||||
", errorMessage='" + errorMessage + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@ import bisq.core.util.coin.CoinUtil;
|
|||
|
||||
import bisq.common.Payload;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
@ -141,13 +139,13 @@ public class OfferInfo implements Payload {
|
|||
return new OfferInfoBuilder()
|
||||
.withId(offer.getId())
|
||||
.withDirection(offer.getDirection().name())
|
||||
.withPrice(Objects.requireNonNull(offer.getPrice()).getValue())
|
||||
.withPrice(requireNonNull(offer.getPrice()).getValue())
|
||||
.withUseMarketBasedPrice(offer.isUseMarketBasedPrice())
|
||||
.withMarketPriceMargin(offer.getMarketPriceMargin())
|
||||
.withAmount(offer.getAmount().value)
|
||||
.withMinAmount(offer.getMinAmount().value)
|
||||
.withVolume(Objects.requireNonNull(offer.getVolume()).getValue())
|
||||
.withMinVolume(Objects.requireNonNull(offer.getMinVolume()).getValue())
|
||||
.withVolume(requireNonNull(offer.getVolume()).getValue())
|
||||
.withMinVolume(requireNonNull(offer.getMinVolume()).getValue())
|
||||
.withMakerFee(getMakerFee(offer, isMyOffer))
|
||||
.withTxFee(offer.getTxFee().value)
|
||||
.withOfferFeePaymentTxId(offer.getOfferFeePaymentTxId())
|
||||
|
|
|
@ -104,7 +104,7 @@ public class TradeInfo implements Payload {
|
|||
|
||||
public static TradeInfo toNewTradeInfo(BsqSwapTrade trade, String role) {
|
||||
// Always called by the taker, isMyOffer=false.
|
||||
return toTradeInfo(trade, role, false);
|
||||
return toTradeInfo(trade, role, false, 0);
|
||||
}
|
||||
|
||||
public static TradeInfo toNewTradeInfo(Trade trade) {
|
||||
|
@ -116,12 +116,15 @@ public class TradeInfo implements Payload {
|
|||
if (tradeModel instanceof Trade)
|
||||
return toTradeInfo((Trade) tradeModel, role, isMyOffer);
|
||||
else if (tradeModel instanceof BsqSwapTrade)
|
||||
return toTradeInfo((BsqSwapTrade) tradeModel, role, isMyOffer);
|
||||
return toTradeInfo(tradeModel, role, isMyOffer);
|
||||
else
|
||||
throw new IllegalStateException("unsupported trade type: " + tradeModel.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
public static TradeInfo toTradeInfo(BsqSwapTrade bsqSwapTrade, String role, boolean isMyOffer) {
|
||||
public static TradeInfo toTradeInfo(BsqSwapTrade bsqSwapTrade,
|
||||
String role,
|
||||
boolean isMyOffer,
|
||||
int numConfirmations) {
|
||||
OfferInfo offerInfo = isMyOffer ? toMyOfferInfo(bsqSwapTrade.getOffer()) : toOfferInfo(bsqSwapTrade.getOffer());
|
||||
TradeInfo tradeInfo = new TradeInfoV1Builder()
|
||||
.withOffer(offerInfo)
|
||||
|
@ -143,7 +146,7 @@ public class TradeInfo implements Payload {
|
|||
// N/A: .withIsFiatSent(false), .withIsFiatReceived(false), .withIsPayoutPublished(false)
|
||||
// N/A: .withIsWithdrawn(false), .withContractAsJson(""), .withContract(null)
|
||||
.build();
|
||||
tradeInfo.bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, isMyOffer);
|
||||
tradeInfo.bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, isMyOffer, numConfirmations);
|
||||
return tradeInfo;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ public final class BsqSwapTradeInfoBuilder {
|
|||
private String makerBtcAddress;
|
||||
private String takerBsqAddress;
|
||||
private String takerBtcAddress;
|
||||
private long numConfirmations;
|
||||
private String errorMessage;
|
||||
|
||||
public BsqSwapTradeInfoBuilder withTxId(String txId) {
|
||||
|
@ -95,6 +96,11 @@ public final class BsqSwapTradeInfoBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public BsqSwapTradeInfoBuilder withNumConfirmations(long numConfirmations) {
|
||||
this.numConfirmations = numConfirmations;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BsqSwapTradeInfoBuilder withErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
return this;
|
||||
|
|
|
@ -78,7 +78,11 @@ class GrpcTradesService extends TradesImplBase {
|
|||
var bsqSwapTrade = coreApi.getBsqSwapTrade(req.getTradeId());
|
||||
boolean wasMyOffer = coreApi.isMyOffer(bsqSwapTrade.getOffer().getId());
|
||||
String role = coreApi.getBsqSwapTradeRole(req.getTradeId());
|
||||
var tradeInfo = toTradeInfo(bsqSwapTrade, role, wasMyOffer);
|
||||
var numConfirmations = coreApi.getTransactionConfirmations(bsqSwapTrade.getTxId());
|
||||
var tradeInfo = toTradeInfo(bsqSwapTrade,
|
||||
role,
|
||||
wasMyOffer,
|
||||
numConfirmations);
|
||||
var reply = GetBsqSwapTradeReply.newBuilder()
|
||||
.setBsqSwapTrade(tradeInfo.toProtoMessage())
|
||||
.build();
|
||||
|
|
|
@ -524,7 +524,8 @@ message BsqSwapTradeInfo {
|
|||
string makerBtcAddress = 8;
|
||||
string takerBsqAddress = 9;
|
||||
string takerBtcAddress = 10;
|
||||
string errorMessage = 11;
|
||||
uint64 numConfirmations = 11;
|
||||
string errorMessage = 12;
|
||||
}
|
||||
|
||||
message PaymentAccountPayloadInfo {
|
||||
|
|
Loading…
Add table
Reference in a new issue