Skip to content

Commit

Permalink
feat: add support for Soroban PRC's getLedgers API interface. (#660)
Browse files Browse the repository at this point in the history
  • Loading branch information
overcat authored Nov 14, 2024
1 parent 0fa5290 commit 54442eb
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
## Pending

### Update
refactor!: change the type of `AbstractTransaction.MIN_BASE_FEE` from `int` to `long`. ([#657](https://github.com/stellar/java-stellar-sdk/pull/657))
- refactor!: change the type of `AbstractTransaction.MIN_BASE_FEE` from `int` to `long`. ([#657](https://github.com/stellar/java-stellar-sdk/pull/657))
- feat: add support for Soroban PRC's `getLedgers` API interface.

## 1.0.0-beta1

Expand Down
27 changes: 26 additions & 1 deletion src/main/java/org/stellar/sdk/SorobanServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.stellar.sdk.requests.ResponseHandler;
import org.stellar.sdk.requests.sorobanrpc.GetEventsRequest;
import org.stellar.sdk.requests.sorobanrpc.GetLedgerEntriesRequest;
import org.stellar.sdk.requests.sorobanrpc.GetLedgersRequest;
import org.stellar.sdk.requests.sorobanrpc.GetTransactionRequest;
import org.stellar.sdk.requests.sorobanrpc.GetTransactionsRequest;
import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest;
Expand All @@ -40,6 +41,7 @@
import org.stellar.sdk.responses.sorobanrpc.GetHealthResponse;
import org.stellar.sdk.responses.sorobanrpc.GetLatestLedgerResponse;
import org.stellar.sdk.responses.sorobanrpc.GetLedgerEntriesResponse;
import org.stellar.sdk.responses.sorobanrpc.GetLedgersResponse;
import org.stellar.sdk.responses.sorobanrpc.GetNetworkResponse;
import org.stellar.sdk.responses.sorobanrpc.GetTransactionResponse;
import org.stellar.sdk.responses.sorobanrpc.GetTransactionsResponse;
Expand Down Expand Up @@ -297,7 +299,7 @@ public GetTransactionResponse getTransaction(String hash) {
* can paginate as long as the pages fall within the history retention of their corresponding RPC
* provider.
*
* @param getTransactionsRequest The {@link GetEventsRequest} to use for the request.
* @param getTransactionsRequest The {@link GetTransactionsRequest} to use for the request.
* @return A {@link GetTransactionsResponse} object containing the transactions that match the
* request.
* @throws org.stellar.sdk.exception.NetworkException All the exceptions below are subclasses of
Expand All @@ -317,6 +319,29 @@ public GetTransactionsResponse getTransactions(GetTransactionsRequest getTransac
new TypeToken<SorobanRpcResponse<GetTransactionsResponse>>() {});
}

/**
* Gets a detailed list of ledgers starting from the user specified starting point that you can
* paginate as long as the pages fall within the history retention of their corresponding RPC
* provider.
*
* @param getLedgersRequest The {@link GetEventsRequest} to use for the request.
* @return A {@link GetLedgersResponse} object containing the ledgers that match the request.
* @throws org.stellar.sdk.exception.NetworkException All the exceptions below are subclasses of
* NetworkError
* @throws SorobanRpcException If the Soroban-RPC instance returns an error response.
* @throws RequestTimeoutException If the request timed out.
* @throws ConnectionErrorException When the request cannot be executed due to cancellation or
* connectivity problems, etc.
* @see <a href="https://developers.stellar.org/docs/data/rpc/api-reference/methods/getLedgers"
* target="_blank">getLedgers documentation</a>
*/
public GetLedgersResponse getLedgers(GetLedgersRequest getLedgersRequest) {
return this.sendRequest(
"getLedgers",
getLedgersRequest,
new TypeToken<SorobanRpcResponse<GetLedgersResponse>>() {});
}

/**
* Fetches all events that match the given {@link GetEventsRequest}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.stellar.sdk.requests.sorobanrpc;

import lombok.Builder;
import lombok.NonNull;
import lombok.Value;

/**
* Request for JSON-RPC method getLedgers.
*
* @see <a href="https://developers.stellar.org/docs/data/rpc/api-reference/methods/getLedgers"
* target="_blank">getLedgers documentation</a>
*/
@Value
@Builder(toBuilder = true)
public class GetLedgersRequest {
@NonNull Long startLedger;

PaginationOptions pagination;

@Value
@Builder(toBuilder = true)
public static class PaginationOptions {
Long limit;

String cursor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Request for JSON-RPC method getTransactions.
*
* @see <a href="https://developers.stellar.org/docs/data/rpc/api-reference/methods/getTransactions"
* target="_blank">getEvents documentation</a>
* target="_blank">getTransactions documentation</a>
*/
@Value
@Builder(toBuilder = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.stellar.sdk.responses.sorobanrpc;

import java.util.List;
import lombok.Value;
import org.stellar.sdk.Util;
import org.stellar.sdk.xdr.LedgerCloseMeta;
import org.stellar.sdk.xdr.LedgerHeaderHistoryEntry;

/**
* Response for JSON-RPC method getLedgers.
*
* @see <a href="https://developers.stellar.org/docs/data/rpc/api-reference/methods/getLedgers"
* target="_blank">getLedgers documentation</a>
*/
@Value
public class GetLedgersResponse {
List<LedgerInfo> ledgers;
Long latestLedger;
Long latestLedgerCloseTime;
Long oldestLedger;
Long oldestLedgerCloseTime;
String cursor;

@Value
public static class LedgerInfo {
String hash;
Long sequence;
Long ledgerCloseTime;

/** The field can be parsed as {@link LedgerHeaderHistoryEntry} object. */
String headerXdr;

/** The field can be parsed as {@link LedgerCloseMeta} object. */
String metadataXdr;

/**
* Parses the {@code envelopeXdr} field from a string to an {@link LedgerHeaderHistoryEntry}
* object.
*
* @return the parsed {@link LedgerHeaderHistoryEntry} object
*/
public LedgerHeaderHistoryEntry parseHeaderXdr() {
return Util.parseXdr(headerXdr, LedgerHeaderHistoryEntry::fromXdrBase64);
}

/**
* Parses the {@code metadataXdr} field from a string to an {@link LedgerCloseMeta} object.
*
* @return the parsed {@link LedgerCloseMeta} object
*/
public LedgerCloseMeta parseMetadataXdr() {
return Util.parseXdr(metadataXdr, LedgerCloseMeta::fromXdrBase64);
}
}
}
57 changes: 57 additions & 0 deletions src/test/java/org/stellar/sdk/SorobanServerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.stellar.sdk.requests.sorobanrpc.EventFilterType;
import org.stellar.sdk.requests.sorobanrpc.GetEventsRequest;
import org.stellar.sdk.requests.sorobanrpc.GetLedgerEntriesRequest;
import org.stellar.sdk.requests.sorobanrpc.GetLedgersRequest;
import org.stellar.sdk.requests.sorobanrpc.GetTransactionRequest;
import org.stellar.sdk.requests.sorobanrpc.GetTransactionsRequest;
import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest;
Expand All @@ -43,6 +44,7 @@
import org.stellar.sdk.responses.sorobanrpc.GetHealthResponse;
import org.stellar.sdk.responses.sorobanrpc.GetLatestLedgerResponse;
import org.stellar.sdk.responses.sorobanrpc.GetLedgerEntriesResponse;
import org.stellar.sdk.responses.sorobanrpc.GetLedgersResponse;
import org.stellar.sdk.responses.sorobanrpc.GetNetworkResponse;
import org.stellar.sdk.responses.sorobanrpc.GetTransactionResponse;
import org.stellar.sdk.responses.sorobanrpc.GetTransactionsResponse;
Expand Down Expand Up @@ -604,6 +606,61 @@ public MockResponse dispatch(@NotNull RecordedRequest recordedRequest)
mockWebServer.close();
}

@Test
public void testGetLedgers() throws IOException, SorobanRpcException {
String filePath = "src/test/resources/soroban_server/get_ledgers.json";
String json = new String(Files.readAllBytes(Paths.get(filePath)));
GetLedgersRequest.PaginationOptions paginationOptions =
GetLedgersRequest.PaginationOptions.builder().limit(2L).build();
GetLedgersRequest getLedgersRequest =
GetLedgersRequest.builder().startLedger(10L).pagination(paginationOptions).build();

MockWebServer mockWebServer = new MockWebServer();
Dispatcher dispatcher =
new Dispatcher() {
@NotNull
@Override
public MockResponse dispatch(@NotNull RecordedRequest recordedRequest)
throws InterruptedException {
SorobanRpcRequest<GetLedgersRequest> sorobanRpcRequest =
gson.fromJson(
recordedRequest.getBody().readUtf8(),
new TypeToken<SorobanRpcRequest<GetLedgersRequest>>() {}.getType());
if ("POST".equals(recordedRequest.getMethod())
&& sorobanRpcRequest.getMethod().equals("getLedgers")
&& sorobanRpcRequest.getParams().equals(getLedgersRequest)) {
return new MockResponse().setResponseCode(200).setBody(json);
}
return new MockResponse().setResponseCode(404);
}
};
mockWebServer.setDispatcher(dispatcher);
mockWebServer.start();

HttpUrl baseUrl = mockWebServer.url("");
SorobanServer server = new SorobanServer(baseUrl.toString());
GetLedgersResponse resp = server.getLedgers(getLedgersRequest);
assertEquals(resp.getLatestLedger().longValue(), 113L);
assertEquals(resp.getLatestLedgerCloseTime().longValue(), 1731554518L);
assertEquals(resp.getOldestLedger().longValue(), 8L);
assertEquals(resp.getOldestLedgerCloseTime().longValue(), 1731554412L);
assertEquals(resp.getCursor(), "11");
assertEquals(resp.getLedgers().size(), 2);
assertEquals(
resp.getLedgers().get(0).getHash(),
"59ccafc5641a44826608a882da10b08f585b2b614be91976ade3927d4422413d");
assertEquals(resp.getLedgers().get(0).getSequence().longValue(), 10L);
assertEquals(resp.getLedgers().get(0).getLedgerCloseTime().longValue(), 1731554414L);
assertEquals(
resp.getLedgers().get(0).getHeaderXdr(),
resp.getLedgers().get(0).parseHeaderXdr().toXdrBase64());
assertEquals(
resp.getLedgers().get(0).getMetadataXdr(),
resp.getLedgers().get(0).parseMetadataXdr().toXdrBase64());
server.close();
mockWebServer.close();
}

@Test
public void testGetEvents() throws IOException, SorobanRpcException {
String filePath = "src/test/resources/soroban_server/get_events.json";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.stellar.sdk.responses.sorobanrpc;

import static org.junit.Assert.assertEquals;

import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.junit.Test;
import org.stellar.sdk.responses.gson.GsonSingleton;

public class GetLedgersDeserializerTest {
@Test
public void testDeserialize() throws IOException {
String filePath = "src/test/resources/responses/sorobanrpc/get_ledgers.json";
String json = new String(Files.readAllBytes(Paths.get(filePath)));

SorobanRpcResponse<GetLedgersResponse> getLedgersResponseSorobanRpcResponse =
GsonSingleton.getInstance()
.fromJson(json, new TypeToken<SorobanRpcResponse<GetLedgersResponse>>() {}.getType());

GetLedgersResponse getLedgersResponse = getLedgersResponseSorobanRpcResponse.getResult();
assertEquals(getLedgersResponse.getLatestLedger().longValue(), 113L);
assertEquals(getLedgersResponse.getLatestLedgerCloseTime().longValue(), 1731554518L);
assertEquals(getLedgersResponse.getOldestLedger().longValue(), 8L);
assertEquals(getLedgersResponse.getOldestLedgerCloseTime().longValue(), 1731554412L);
assertEquals(getLedgersResponse.getCursor(), "11");
assertEquals(getLedgersResponse.getLedgers().size(), 2);
assertEquals(
getLedgersResponse.getLedgers().get(0).getHash(),
"59ccafc5641a44826608a882da10b08f585b2b614be91976ade3927d4422413d");
assertEquals(getLedgersResponse.getLedgers().get(0).getSequence().longValue(), 10L);
assertEquals(
getLedgersResponse.getLedgers().get(0).getLedgerCloseTime().longValue(), 1731554414L);
for (GetLedgersResponse.LedgerInfo ledgerInfo : getLedgersResponse.getLedgers()) {
assertEquals(ledgerInfo.getHeaderXdr(), ledgerInfo.parseHeaderXdr().toXdrBase64());
assertEquals(ledgerInfo.getMetadataXdr(), ledgerInfo.parseMetadataXdr().toXdrBase64());
}
}
}
28 changes: 28 additions & 0 deletions src/test/resources/responses/sorobanrpc/get_ledgers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"jsonrpc": "2.0",
"id": "0ce70038b1804b3c93ca7abc137f3061",
"result": {
"ledgers": [
{
"hash": "59ccafc5641a44826608a882da10b08f585b2b614be91976ade3927d4422413d",
"sequence": 10,
"ledgerCloseTime": "1731554414",
"headerXdr": "WcyvxWQaRIJmCKiC2hCwj1hbK2FL6Rl2reOSfUQiQT0AAAAVwLYrLkYHkh0rJ+GmAbGkeHIQpyDsekpf68ThNNsCXYI2jMO8189Z2jYaMg/mttiL9SVfJXThDGEIYe/klkKWMwAAAABnNWxuAAAAAAAAAAEAAAAApo8dlon1AzCqtWnWdzJ01L+/6QHyNiUhUM5rTILgk/cAAABAnJJp+kohsfTVKJYclwggQFe/Eie6zoL43O0xvKlYoYsd1I09szNQBqserhqzq+9WSTNS3wUZ8YC4U4e8O5+7AN8/YZgEqS/bQFcZLcQ910jqd4rcUrxJjOgFJMAUuBEZTxx260gYA3GwBr7nqsHUDnR+DGVQDc1IyOubd/pi5zcAAAAKDeC2s6dkAAAAAAAAAAPpLwAAAAAAAAAAAAAAAAAAAGQATEtAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"metadataXdr": "AAAAAQAAAABZzK/FZBpEgmYIqILaELCPWFsrYUvpGXat45J9RCJBPQAAABXAtisuRgeSHSsn4aYBsaR4chCnIOx6Sl/rxOE02wJdgjaMw7zXz1naNhoyD+a22Iv1JV8ldOEMYQhh7+SWQpYzAAAAAGc1bG4AAAAAAAAAAQAAAACmjx2WifUDMKq1adZ3MnTUv7/pAfI2JSFQzmtMguCT9wAAAECckmn6SiGx9NUolhyXCCBAV78SJ7rOgvjc7TG8qVihix3UjT2zM1AGqx6uGrOr71ZJM1LfBRnxgLhTh7w7n7sA3z9hmASpL9tAVxktxD3XSOp3itxSvEmM6AUkwBS4ERlPHHbrSBgDcbAGvueqwdQOdH4MZVANzUjI65t3+mLnNwAAAAoN4Lazp2QAAAAAAAAAA+kvAAAAAAAAAAAAAAAAAAAAZABMS0AAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAtisuRgeSHSsn4aYBsaR4chCnIOx6Sl/rxOE02wJdggAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAAAAAA=="
},
{
"hash": "76b188897ab785d81a85508ad4434bb0c33a74c9c0874165120ccd3158f76ed3",
"sequence": 11,
"ledgerCloseTime": "1731554415",
"headerXdr": "drGIiXq3hdgahVCK1ENLsMM6dMnAh0FlEgzNMVj3btMAAAAVWcyvxWQaRIJmCKiC2hCwj1hbK2FL6Rl2reOSfUQiQT37/jXH2AmHKzOU33bzTVlQU8zUjm7dqF8UMsn+7c+c5QAAAABnNWxvAAAAAAAAAAEAAAAApo8dlon1AzCqtWnWdzJ01L+/6QHyNiUhUM5rTILgk/cAAABA/jgs2CQswku2XhYsIi8JODW/Fe9P6di07ZXI2pWjCPNjqZ4/PHVASh4R360tEJKNDerKq4N+8sULaM2TwxrABt8/YZgEqS/bQFcZLcQ910jqd4rcUrxJjOgFJMAUuBEZQZ8jWama0eWGWYdhBgDMBWlFpkK440lHonFcFQm0FpUAAAALDeC2s6dkAAAAAAAAAAPpLwAAAAAAAAAAAAAAAAAAAGQATEtAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"metadataXdr": "AAAAAQAAAAB2sYiJereF2BqFUIrUQ0uwwzp0ycCHQWUSDM0xWPdu0wAAABVZzK/FZBpEgmYIqILaELCPWFsrYUvpGXat45J9RCJBPfv+NcfYCYcrM5TfdvNNWVBTzNSObt2oXxQyyf7tz5zlAAAAAGc1bG8AAAAAAAAAAQAAAACmjx2WifUDMKq1adZ3MnTUv7/pAfI2JSFQzmtMguCT9wAAAED+OCzYJCzCS7ZeFiwiLwk4Nb8V70/p2LTtlcjalaMI82Opnj88dUBKHhHfrS0Qko0N6sqrg37yxQtozZPDGsAG3z9hmASpL9tAVxktxD3XSOp3itxSvEmM6AUkwBS4ERlBnyNZqZrR5YZZh2EGAMwFaUWmQrjjSUeicVwVCbQWlQAAAAsN4Lazp2QAAAAAAAAAA+kvAAAAAAAAAAAAAAAAAAAAZABMS0AAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZzK/FZBpEgmYIqILaELCPWFsrYUvpGXat45J9RCJBPQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAAAAAA=="
}
],
"latestLedger": 113,
"latestLedgerCloseTime": 1731554518,
"oldestLedger": 8,
"oldestLedgerCloseTime": 1731554412,
"cursor": "11"
}
}

28 changes: 28 additions & 0 deletions src/test/resources/soroban_server/get_ledgers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"jsonrpc": "2.0",
"id": "0ce70038b1804b3c93ca7abc137f3061",
"result": {
"ledgers": [
{
"hash": "59ccafc5641a44826608a882da10b08f585b2b614be91976ade3927d4422413d",
"sequence": 10,
"ledgerCloseTime": "1731554414",
"headerXdr": "WcyvxWQaRIJmCKiC2hCwj1hbK2FL6Rl2reOSfUQiQT0AAAAVwLYrLkYHkh0rJ+GmAbGkeHIQpyDsekpf68ThNNsCXYI2jMO8189Z2jYaMg/mttiL9SVfJXThDGEIYe/klkKWMwAAAABnNWxuAAAAAAAAAAEAAAAApo8dlon1AzCqtWnWdzJ01L+/6QHyNiUhUM5rTILgk/cAAABAnJJp+kohsfTVKJYclwggQFe/Eie6zoL43O0xvKlYoYsd1I09szNQBqserhqzq+9WSTNS3wUZ8YC4U4e8O5+7AN8/YZgEqS/bQFcZLcQ910jqd4rcUrxJjOgFJMAUuBEZTxx260gYA3GwBr7nqsHUDnR+DGVQDc1IyOubd/pi5zcAAAAKDeC2s6dkAAAAAAAAAAPpLwAAAAAAAAAAAAAAAAAAAGQATEtAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"metadataXdr": "AAAAAQAAAABZzK/FZBpEgmYIqILaELCPWFsrYUvpGXat45J9RCJBPQAAABXAtisuRgeSHSsn4aYBsaR4chCnIOx6Sl/rxOE02wJdgjaMw7zXz1naNhoyD+a22Iv1JV8ldOEMYQhh7+SWQpYzAAAAAGc1bG4AAAAAAAAAAQAAAACmjx2WifUDMKq1adZ3MnTUv7/pAfI2JSFQzmtMguCT9wAAAECckmn6SiGx9NUolhyXCCBAV78SJ7rOgvjc7TG8qVihix3UjT2zM1AGqx6uGrOr71ZJM1LfBRnxgLhTh7w7n7sA3z9hmASpL9tAVxktxD3XSOp3itxSvEmM6AUkwBS4ERlPHHbrSBgDcbAGvueqwdQOdH4MZVANzUjI65t3+mLnNwAAAAoN4Lazp2QAAAAAAAAAA+kvAAAAAAAAAAAAAAAAAAAAZABMS0AAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAtisuRgeSHSsn4aYBsaR4chCnIOx6Sl/rxOE02wJdggAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAAAAAA=="
},
{
"hash": "76b188897ab785d81a85508ad4434bb0c33a74c9c0874165120ccd3158f76ed3",
"sequence": 11,
"ledgerCloseTime": "1731554415",
"headerXdr": "drGIiXq3hdgahVCK1ENLsMM6dMnAh0FlEgzNMVj3btMAAAAVWcyvxWQaRIJmCKiC2hCwj1hbK2FL6Rl2reOSfUQiQT37/jXH2AmHKzOU33bzTVlQU8zUjm7dqF8UMsn+7c+c5QAAAABnNWxvAAAAAAAAAAEAAAAApo8dlon1AzCqtWnWdzJ01L+/6QHyNiUhUM5rTILgk/cAAABA/jgs2CQswku2XhYsIi8JODW/Fe9P6di07ZXI2pWjCPNjqZ4/PHVASh4R360tEJKNDerKq4N+8sULaM2TwxrABt8/YZgEqS/bQFcZLcQ910jqd4rcUrxJjOgFJMAUuBEZQZ8jWama0eWGWYdhBgDMBWlFpkK440lHonFcFQm0FpUAAAALDeC2s6dkAAAAAAAAAAPpLwAAAAAAAAAAAAAAAAAAAGQATEtAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"metadataXdr": "AAAAAQAAAAB2sYiJereF2BqFUIrUQ0uwwzp0ycCHQWUSDM0xWPdu0wAAABVZzK/FZBpEgmYIqILaELCPWFsrYUvpGXat45J9RCJBPfv+NcfYCYcrM5TfdvNNWVBTzNSObt2oXxQyyf7tz5zlAAAAAGc1bG8AAAAAAAAAAQAAAACmjx2WifUDMKq1adZ3MnTUv7/pAfI2JSFQzmtMguCT9wAAAED+OCzYJCzCS7ZeFiwiLwk4Nb8V70/p2LTtlcjalaMI82Opnj88dUBKHhHfrS0Qko0N6sqrg37yxQtozZPDGsAG3z9hmASpL9tAVxktxD3XSOp3itxSvEmM6AUkwBS4ERlBnyNZqZrR5YZZh2EGAMwFaUWmQrjjSUeicVwVCbQWlQAAAAsN4Lazp2QAAAAAAAAAA+kvAAAAAAAAAAAAAAAAAAAAZABMS0AAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZzK/FZBpEgmYIqILaELCPWFsrYUvpGXat45J9RCJBPQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAAAAAA=="
}
],
"latestLedger": 113,
"latestLedgerCloseTime": 1731554518,
"oldestLedger": 8,
"oldestLedgerCloseTime": 1731554412,
"cursor": "11"
}
}

0 comments on commit 54442eb

Please sign in to comment.