From 951a1a1bd3ede251bc066c5f955baacfe046bf21 Mon Sep 17 00:00:00 2001 From: tplansky Date: Fri, 23 Aug 2024 17:45:07 +0200 Subject: [PATCH] BATM-6424 Transaction has at sell via bitgo --- .../extensions/payment/ReceivedAmount.java | 16 +++++++++ .../v2/BitgoWalletWithUniqueAddresses.java | 35 ++++++++++++++++--- .../bitcoin/wallets/bitgo/v2/IBitgoAPI.java | 19 ++++++++-- .../wallets/bitgo/v2/dto/BitGoTransfer.java | 30 ++++++++++++++++ .../bitgo/v2/dto/BitGoTransfersResponse.java | 18 ++++++++++ .../common/QueryableWalletPaymentSupport.java | 10 ++++++ 6 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfer.java create mode 100644 server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfersResponse.java diff --git a/server_extensions_api/src/main/java/com/generalbytes/batm/server/extensions/payment/ReceivedAmount.java b/server_extensions_api/src/main/java/com/generalbytes/batm/server/extensions/payment/ReceivedAmount.java index 73dfd7c0a..465d8ff33 100644 --- a/server_extensions_api/src/main/java/com/generalbytes/batm/server/extensions/payment/ReceivedAmount.java +++ b/server_extensions_api/src/main/java/com/generalbytes/batm/server/extensions/payment/ReceivedAmount.java @@ -18,6 +18,7 @@ package com.generalbytes.batm.server.extensions.payment; import java.math.BigDecimal; +import java.util.List; import java.util.Objects; /** @@ -28,6 +29,7 @@ public class ReceivedAmount { private final BigDecimal totalAmountReceived; private final int confirmations; + private List transactionHashes; public ReceivedAmount(BigDecimal totalAmountReceived, int confirmations) { this.totalAmountReceived = Objects.requireNonNull(totalAmountReceived); @@ -49,4 +51,18 @@ public BigDecimal getTotalAmountReceived() { public int getConfirmations() { return confirmations; } + + /** + * @return hashes of all incoming transactions + */ + public List getTransactionHashes() { + return transactionHashes; + } + + /** + * @param transactionHashes hashes of all incoming transactions + */ + public void setTransactionHashes(List transactionHashes) { + this.transactionHashes = transactionHashes; + } } diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/BitgoWalletWithUniqueAddresses.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/BitgoWalletWithUniqueAddresses.java index 213f7dffa..e754f827b 100644 --- a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/BitgoWalletWithUniqueAddresses.java +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/BitgoWalletWithUniqueAddresses.java @@ -20,8 +20,10 @@ import com.generalbytes.batm.common.currencies.CryptoCurrency; import com.generalbytes.batm.server.extensions.IGeneratesNewDepositCryptoAddress; import com.generalbytes.batm.server.extensions.IQueryableWallet; -import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoCreateAddressRequest; import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoAddressResponse; +import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoCreateAddressRequest; +import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoTransfer; +import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoTransfersResponse; import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.ErrorResponseException; import com.generalbytes.batm.server.extensions.payment.ReceivedAmount; import org.slf4j.Logger; @@ -29,12 +31,16 @@ import si.mazi.rescu.HttpStatusIOException; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class BitgoWalletWithUniqueAddresses extends BitgoWallet implements IGeneratesNewDepositCryptoAddress, IQueryableWallet { private static final Logger log = LoggerFactory.getLogger(BitgoWalletWithUniqueAddresses.class); + private static final String TRANSFER_STATE_CONFIRMED = "confirmed"; + private static final String TRANSFER_TYPE_RECEIVE = "receive"; private static final Map newAddressCryptoCurrency = new HashMap() { { put(CryptoCurrency.USDT.getCode(), "eth"); @@ -93,11 +99,30 @@ public ReceivedAmount getReceivedAmount(String address, String cryptoCurrency) { } try { - BitGoAddressResponse resp = api.getAddress(bitgoCryptoCurrency, walletId, address); - if (resp.getBalance().getConfirmedBalance().compareTo(BigDecimal.ZERO) > 0) { - return new ReceivedAmount(fromSatoshis(cryptoCurrency, resp.getBalance().getConfirmedBalance()), 999); + BitGoTransfersResponse transfersResponse = api.getTransfers( + bitgoCryptoCurrency, + walletId, + TRANSFER_STATE_CONFIRMED, + TRANSFER_TYPE_RECEIVE, + address + ); + BigDecimal totalInBaseUnits = BigDecimal.ZERO; + int confirmations = 0; + List transactionHashes = new ArrayList<>(); + + for (BitGoTransfer confirmedTransfer : transfersResponse.getTransfers()) { + BigDecimal valueInBaseUnits = fromSatoshis(cryptoCurrency, confirmedTransfer.getValue()); + + totalInBaseUnits = totalInBaseUnits.add(valueInBaseUnits); + if (confirmations == 0 || confirmedTransfer.getConfirmations() < confirmations) { + confirmations = confirmedTransfer.getConfirmations(); + } + transactionHashes.add(confirmedTransfer.getTransactionHash()); } - return new ReceivedAmount(fromSatoshis(cryptoCurrency, resp.getBalance().getBalance()), 0); + + ReceivedAmount receivedAmount = new ReceivedAmount(totalInBaseUnits, confirmations); + receivedAmount.setTransactionHashes(transactionHashes); + return receivedAmount; } catch (HttpStatusIOException e) { log.debug("get address error: {}", e.getHttpBody()); } catch (ErrorResponseException e) { diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/IBitgoAPI.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/IBitgoAPI.java index bc1fad96d..0721d2df4 100644 --- a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/IBitgoAPI.java +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/IBitgoAPI.java @@ -17,13 +17,20 @@ ************************************************************************************/ package com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2; +import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoAddressResponse; import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoCoinRequest; import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoCreateAddressRequest; -import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoAddressResponse; import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoSendManyRequest; +import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.BitGoTransfersResponse; import com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto.ErrorResponseException; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import java.io.IOException; import java.util.Map; @@ -54,6 +61,14 @@ public interface IBitgoAPI { @Path("/{coin}/wallet/{id}") Map getWalletById(@PathParam("coin") String coin, @PathParam("id") String id) throws IOException, ErrorResponseException; + @GET + @Path("/{coin}/wallet/{walletId}/transfer") + BitGoTransfersResponse getTransfers(@PathParam("coin") String coin, + @PathParam("walletId") String walletId, + @QueryParam("state") String state, + @QueryParam("type") String type, + @QueryParam("address") String address) throws IOException, ErrorResponseException; + @GET @Path("/{coin}/wallet/{walletId}/address/{addressOrId}") BitGoAddressResponse getAddress(@PathParam("coin") String coin, @PathParam("walletId") String walletId, @PathParam("addressOrId") String addressOrId) throws IOException, ErrorResponseException; diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfer.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfer.java new file mode 100644 index 000000000..8f4a67b80 --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfer.java @@ -0,0 +1,30 @@ +package com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.math.BigDecimal; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class BitGoTransfer { + + @JsonProperty("txid") + private String transactionHash; + @JsonProperty("valueString") + private BigDecimal value; + @JsonProperty("confirmations") + private int confirmations; + + public String getTransactionHash() { + return transactionHash; + } + + public BigDecimal getValue() { + return value; + } + + public int getConfirmations() { + return confirmations; + } + +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfersResponse.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfersResponse.java new file mode 100644 index 000000000..67fbc3c7c --- /dev/null +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/bitcoin/wallets/bitgo/v2/dto/BitGoTransfersResponse.java @@ -0,0 +1,18 @@ +package com.generalbytes.batm.server.extensions.extra.bitcoin.wallets.bitgo.v2.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class BitGoTransfersResponse { + + @JsonProperty("transfers") + private List transfers; + + public List getTransfers() { + return transfers; + } + +} diff --git a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/common/QueryableWalletPaymentSupport.java b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/common/QueryableWalletPaymentSupport.java index f52b41a20..65811a931 100644 --- a/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/common/QueryableWalletPaymentSupport.java +++ b/server_extensions_extra/src/main/java/com/generalbytes/batm/server/extensions/extra/common/QueryableWalletPaymentSupport.java @@ -7,6 +7,7 @@ import com.generalbytes.batm.server.extensions.payment.ReceivedAmount; import java.math.BigDecimal; +import java.util.List; public abstract class QueryableWalletPaymentSupport extends PollingPaymentSupport { @@ -46,6 +47,7 @@ public void poll(PaymentRequest request) { if (request.getState() == PaymentRequest.STATE_NEW) { log.info("Received: {}, amounts matches. {}", totalReceived, request); request.setTxValue(totalReceived); + request.setIncomingTransactionHash(getLastTransactionHash(receivedAmount)); setState(request, PaymentRequest.STATE_SEEN_TRANSACTION); } @@ -63,6 +65,14 @@ public void poll(PaymentRequest request) { } } + private String getLastTransactionHash(ReceivedAmount receivedAmount) { + List transactionHashes = receivedAmount.getTransactionHashes(); + if (transactionHashes != null && !transactionHashes.isEmpty()) { + return transactionHashes.get(transactionHashes.size() - 1); + } + return null; + } + private boolean receivedAmountMatchesRequestedAmountInTolerance(PaymentRequest request, BigDecimal totalReceived) { BigDecimal requestedAmount = request.getAmount(); BigDecimal tolerance = request.getTolerance();