Skip to content

Commit

Permalink
Add Providers Support for Querying All Transactions Data by Payment/S…
Browse files Browse the repository at this point in the history
…taking Address
  • Loading branch information
Dudi Edri committed May 15, 2024
1 parent ef25de9 commit 2845c00
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.bloxbean.cardano.client.api.exception.ApiException;
import com.bloxbean.cardano.client.api.model.Result;
import com.bloxbean.cardano.client.backend.api.AccountService;
import com.bloxbean.cardano.client.backend.api.AddressService;
import com.bloxbean.cardano.client.backend.blockfrost.service.http.AccountApi;
import com.bloxbean.cardano.client.backend.model.*;
import retrofit2.Call;
Expand All @@ -16,10 +17,12 @@
public class BFAccountService extends BFBaseService implements AccountService {

private final AccountApi accountApi;
private final AddressService addressService;

public BFAccountService(String baseUrl, String projectId) {
public BFAccountService(String baseUrl, String projectId, AddressService addressService) {
super(baseUrl, projectId);
this.accountApi = getRetrofit().create(AccountApi.class);
this.addressService = addressService;
}

@Override
Expand Down Expand Up @@ -138,4 +141,56 @@ public Result<List<AccountAsset>> getAccountAssets(String stakeAddress, int coun
throw new ApiException("Error getting accountInformation", e);
}
}

@Override
public Result<List<AddressTransactionContent>> getAccountTransactions(String stakeAddress, int count, int page, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException {
Result<List<AccountAddress>> accountAddressesResult = getAllAccountAddresses(stakeAddress);
if (accountAddressesResult.isSuccessful()) {
List<AddressTransactionContent> transactionContents = new ArrayList<>();
List<AccountAddress> accountAddresses = accountAddressesResult.getValue();
try {
for (AccountAddress accountAddress : accountAddresses) {
Result<List<AddressTransactionContent>> listResult = addressService.getTransactions(accountAddress.getAddress(), 100, page, order, fromBlockHeight.toString(), toBlockHeight.toString());
if (listResult.isSuccessful()) {
transactionContents.addAll(listResult.getValue());
}
}
} catch (ApiException e) {
throw new RuntimeException(e);
}
transactionContents.sort((o1, o2) ->
order == OrderEnum.asc ?
Long.compare(o1.getBlockHeight(), o2.getBlockHeight()) :
Long.compare(o2.getBlockHeight(), o1.getBlockHeight()));
return Result.success("SUCCESS").withValue(transactionContents).code(200);
} else {
return Result.error(accountAddressesResult.getResponse()).code(accountAddressesResult.code());
}
}

@Override
public Result<List<AddressTransactionContent>> getAllAccountTransactions(String stakeAddress, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException {
Result<List<AccountAddress>> accountAddressesResult = getAllAccountAddresses(stakeAddress);
if (accountAddressesResult.isSuccessful()) {
List<AddressTransactionContent> transactionContents = new ArrayList<>();
List<AccountAddress> accountAddresses = accountAddressesResult.getValue();
try {
for (AccountAddress accountAddress : accountAddresses) {
Result<List<AddressTransactionContent>> listResult = addressService.getAllTransactions(accountAddress.getAddress(), order, fromBlockHeight, toBlockHeight);
if (listResult.isSuccessful()) {
transactionContents.addAll(listResult.getValue());
}
}
} catch (ApiException e) {
throw new RuntimeException(e);
}
transactionContents.sort((o1, o2) ->
order == OrderEnum.asc ?
Long.compare(o1.getBlockHeight(), o2.getBlockHeight()) :
Long.compare(o2.getBlockHeight(), o1.getBlockHeight()));
return Result.success("SUCCESS").withValue(transactionContents).code(200);
} else {
return Result.error(accountAddressesResult.getResponse()).code(accountAddressesResult.code());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.bloxbean.cardano.client.backend.blockfrost.service;

import com.bloxbean.cardano.client.backend.api.AddressService;
import com.bloxbean.cardano.client.api.common.OrderEnum;
import com.bloxbean.cardano.client.api.exception.ApiException;
import com.bloxbean.cardano.client.api.model.Result;
import com.bloxbean.cardano.client.backend.api.AddressService;
import com.bloxbean.cardano.client.backend.blockfrost.service.http.AddressesApi;
import com.bloxbean.cardano.client.backend.model.AddressContent;
import com.bloxbean.cardano.client.backend.model.AddressDetails;
import com.bloxbean.cardano.client.backend.model.AddressTransactionContent;
import com.bloxbean.cardano.client.api.model.Result;
import retrofit2.Call;
import retrofit2.Response;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class BFAddressService extends BFBaseService implements AddressService {
Expand Down Expand Up @@ -68,4 +69,28 @@ public Result<List<AddressTransactionContent>> getTransactions(String address, i
throw new ApiException("Error getting transactions for the address", e);
}
}

public Result<List<AddressTransactionContent>> getAllTransactions(String address, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException {
List<AddressTransactionContent> addressTransactionContents = new ArrayList<>();
int page = 1;
Result<List<AddressTransactionContent>> addressTransactionContentsResult = getTransactions(address, 100, page, order, String.valueOf(fromBlockHeight), String.valueOf(toBlockHeight));
while (addressTransactionContentsResult.isSuccessful()) {
addressTransactionContents.addAll(addressTransactionContentsResult.getValue());
if (addressTransactionContentsResult.getValue().size() != 100) {
break;
} else {
page++;
addressTransactionContentsResult = getTransactions(address, 100, page, order, String.valueOf(fromBlockHeight), String.valueOf(toBlockHeight));
}
}
if (!addressTransactionContentsResult.isSuccessful()) {
return addressTransactionContentsResult;
} else {
addressTransactionContents.sort((o1, o2) ->
order == OrderEnum.asc ?
Long.compare(o1.getBlockHeight(), o2.getBlockHeight()) :
Long.compare(o2.getBlockHeight(), o1.getBlockHeight()));
return Result.success(addressTransactionContentsResult.toString()).withValue(addressTransactionContents).code(addressTransactionContentsResult.code());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public AddressService getAddressService() {

@Override
public AccountService getAccountService() {
return new BFAccountService(getBaseUrl(), getProjectId());
return new BFAccountService(getBaseUrl(), getProjectId(), getAddressService());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bloxbean.cardano.client.backend.koios.it;

import com.bloxbean.cardano.client.api.common.OrderEnum;
import com.bloxbean.cardano.client.api.exception.ApiException;
import com.bloxbean.cardano.client.api.model.Result;
import com.bloxbean.cardano.client.backend.api.AccountService;
Expand All @@ -10,6 +11,7 @@

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class KoiosAccountServiceIT extends KoiosBaseTest {
Expand Down Expand Up @@ -83,4 +85,15 @@ void testGetAllAccountAssets() throws ApiException {
System.out.println(JsonUtil.getPrettyJson(accountAssets));
//TODO Find account with more than 1000 assets
}

@Test
void testGetAllAccountTransactions() throws ApiException {
String stakeAddress = "stake_test1upxeg0r67z4wca682l28ghg69jxaxgswdmpvnher7at697qmhymyp";
Result<List<AddressTransactionContent>> result = accountService.getAllAccountTransactions(stakeAddress, OrderEnum.asc, 605746, 615700);
assertTrue(result.isSuccessful());
List<AddressTransactionContent> addressTransactionContents = result.getValue();
assertEquals(22, addressTransactionContents.size());
assertEquals("bef3e28ad884c3e50d40465726da389c4c288d486a47bc700c5d273d0516ea01", addressTransactionContents.get(0).getTxHash());
System.out.println(JsonUtil.getPrettyJson(addressTransactionContents));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,16 @@ public void testGetTransactionsWithOrder_whenFromAndToBlocksProvided() throws Ap
assertTrue(txns.get(0).getBlockHeight() != 0);
assertTrue(txns.get(0).getBlockTime() != 0);
}

@Test
public void testGetAllTransactions() throws ApiException {
String address = "addr_test1qzx9hu8j4ah3auytk0mwcupd69hpc52t0cw39a65ndrah86djs784u92a3m5w475w3w35tyd6v3qumkze80j8a6h5tuqq5xe8y";
List<AddressTransactionContent> txns = addressService.getAllTransactions(address, OrderEnum.desc, 357475, 357479).getValue();

System.out.println(txns);
assertThat(txns.size()).isEqualTo(3);
assertEquals("002dbdb2d294a61c03ec7b0876bc5d40ec3ae07ef5b72d08c107cce7566c4f96", txns.get(0).getTxHash());
assertTrue(txns.get(0).getBlockHeight() != 0);
assertTrue(txns.get(0).getBlockTime() != 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import com.bloxbean.cardano.client.api.common.OrderEnum;
import com.bloxbean.cardano.client.api.exception.ApiException;
import com.bloxbean.cardano.client.api.model.Result;
import com.bloxbean.cardano.client.backend.model.AccountAddress;
import com.bloxbean.cardano.client.backend.model.AccountAsset;
import com.bloxbean.cardano.client.backend.model.AccountHistory;
import com.bloxbean.cardano.client.backend.model.*;
import rest.koios.client.backend.api.account.AccountService;
import rest.koios.client.backend.api.account.model.AccountHistoryInner;
import rest.koios.client.backend.api.account.model.AccountInfo;
import rest.koios.client.backend.api.account.model.AccountReward;
import rest.koios.client.backend.api.account.model.AccountRewards;
import rest.koios.client.backend.factory.options.Limit;
import rest.koios.client.backend.factory.options.Offset;
import rest.koios.client.backend.factory.options.Options;
import rest.koios.client.backend.api.account.model.*;
import rest.koios.client.backend.factory.options.*;
import rest.koios.client.backend.factory.options.filters.Filter;
import rest.koios.client.backend.factory.options.filters.FilterType;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -253,6 +253,73 @@ public Result<List<AccountAsset>> getAccountAssets(String stakeAddress, int coun
}
}

@Override
public Result<List<AddressTransactionContent>> getAccountTransactions(String stakeAddress, int count, int page, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException {
try {
Options options = Options.builder()
.option(Limit.of(count))
.option(Offset.of((long) (page - 1) * count))
.build();
if (order != null) {
options.getOptionList().add(Order.by("block_height", order == OrderEnum.asc ? SortType.ASC : SortType.DESC));
}
if (toBlockHeight != null) {
options.getOptionList().add(Filter.of("block_height", FilterType.LTE, toBlockHeight.toString()));
}
rest.koios.client.backend.api.base.Result<List<rest.koios.client.backend.api.account.model.AccountTx>> accountTxsResult =
accountService.getAccountTxs(stakeAddress, fromBlockHeight, options);
if (!accountTxsResult.isSuccessful()) {
return Result.error(accountTxsResult.getResponse()).code(accountTxsResult.getCode());
}
if (accountTxsResult.getValue().isEmpty()) {
return Result.error("Not Found").code(404);
}
return convertToAddressTransactionContent(accountTxsResult.getValue(), order);
} catch (rest.koios.client.backend.api.base.exception.ApiException e) {
throw new ApiException(e.getMessage(), e);
}
}

@Override
public Result<List<AddressTransactionContent>> getAllAccountTransactions(String stakeAddress, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException {
List<AddressTransactionContent> addressTransactionContents = new ArrayList<>();
int page = 1;
Result<List<AddressTransactionContent>> addressTransactionsResult = getAccountTransactions(stakeAddress, 1000, page, order, fromBlockHeight, toBlockHeight);
while (addressTransactionsResult.isSuccessful()) {
addressTransactionContents.addAll(addressTransactionsResult.getValue());
if (addressTransactionsResult.getValue().size() != 1000) {
break;
} else {
page++;
addressTransactionsResult = getAccountTransactions(stakeAddress, 1000, page, order, fromBlockHeight, toBlockHeight);
}
}
if (!addressTransactionsResult.isSuccessful()) {
return addressTransactionsResult;
} else {
return Result.success(addressTransactionsResult.toString()).withValue(addressTransactionContents).code(addressTransactionsResult.code());
}
}

private Result<List<AddressTransactionContent>> convertToAddressTransactionContent(List<AccountTx> accountTxs, OrderEnum order) {
List<AddressTransactionContent> transactionContents = new ArrayList<>();
if (accountTxs != null) {
accountTxs.forEach(accountTx -> {
AddressTransactionContent transactionContent = new AddressTransactionContent();
transactionContent.setTxHash(accountTx.getTxHash());
transactionContent.setBlockHeight(accountTx.getBlockHeight());
transactionContent.setBlockTime(accountTx.getBlockTime());
transactionContents.add(transactionContent);
});
}
Comparator<AddressTransactionContent> comparator = Comparator.comparing(AddressTransactionContent::getBlockHeight);
if (order != OrderEnum.asc) {
comparator = comparator.reversed();
}
transactionContents.sort(comparator);
return Result.success("OK").withValue(transactionContents).code(200);
}

private Result<List<AccountAsset>> convertToAccountAssets(List<rest.koios.client.backend.api.account.model.AccountAsset> accountAssetList) {
List<AccountAsset> accountAssets = new ArrayList<>();
if (accountAssetList != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,31 @@ public Result<List<AddressTransactionContent>> getTransactions(String address, i
}
}

@Override
public Result<List<AddressTransactionContent>> getAllTransactions(String address, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException {
List<AddressTransactionContent> addressTransactionContents = new ArrayList<>();
int page = 1;
Result<List<AddressTransactionContent>> addressTransactionsResult = getTransactions(address, 1000, page, order, fromBlockHeight.toString(), toBlockHeight.toString());
while (addressTransactionsResult.isSuccessful()) {
addressTransactionContents.addAll(addressTransactionsResult.getValue());
if (addressTransactionsResult.getValue().size() != 1000) {
break;
} else {
page++;
addressTransactionsResult = getTransactions(address, 1000, page, order, fromBlockHeight.toString(), toBlockHeight.toString());
}
}
if (!addressTransactionsResult.isSuccessful()) {
return addressTransactionsResult;
} else {
addressTransactionContents.sort((o1, o2) ->
order == OrderEnum.asc ?
Long.compare(o1.getBlockHeight(), o2.getBlockHeight()) :
Long.compare(o2.getBlockHeight(), o1.getBlockHeight()));
return Result.success(addressTransactionsResult.toString()).withValue(addressTransactionContents).code(addressTransactionsResult.code());
}
}

private Result<List<AddressTransactionContent>> convertToAddressTransactionContent(List<TxHash> txHashes) throws ParseException {
List<AddressTransactionContent> addressTransactionContents = new ArrayList<>();
for (TxHash txHash : txHashes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,25 @@ public interface AccountService {
* @return List of Used Addresses
*/
Result<List<AccountAsset>> getAccountAssets(String stakeAddress, int count, int page, OrderEnum order) throws ApiException;

/**
* Obtain information about transactions associated with a specific account.
* @param stakeAddress Bech32 stake address.
* @param count count
* @param page page
* @param order The ordering of items from the point of view of the blockchain, not the page listing itself. By default, we return oldest first, newest last.
* @param fromBlockHeight from block number
* @param toBlockHeight to block number
* @return List of {@link TransactionContent}
*/
Result<List<AddressTransactionContent>> getAccountTransactions(String stakeAddress, int count, int page, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException;

/**
* Obtain All information about transactions associated with a specific account.
* @param stakeAddress Bech32 stake address.
* @param order The ordering of items from the point of view of the blockchain, not the page listing itself. By default, we return oldest first, newest last.
* @param fromBlockHeight from block number
* @return List of {@link TransactionContent}
*/
Result<List<AddressTransactionContent>> getAllAccountTransactions(String stakeAddress, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,14 @@ public interface AddressService {
default Result<List<AddressTransactionContent>> getTransactions(String address, int count, int page, OrderEnum order, String from, String to) throws ApiException {
return getTransactions(address, count, page, order);
}

/**
* getAllTransactions
* @param address paymentAddress
* @param order order
* @param fromBlockHeight from block number
* @param toBlockHeight to block number
* @return List of {@link AddressTransactionContent}
*/
Result<List<AddressTransactionContent>> getAllTransactions(String address, OrderEnum order, Integer fromBlockHeight, Integer toBlockHeight) throws ApiException;
}
Loading

0 comments on commit 2845c00

Please sign in to comment.