diff --git a/src/main/java/org/stellar/sdk/SorobanServer.java b/src/main/java/org/stellar/sdk/SorobanServer.java index 4750891d5..cf7f46586 100644 --- a/src/main/java/org/stellar/sdk/SorobanServer.java +++ b/src/main/java/org/stellar/sdk/SorobanServer.java @@ -31,6 +31,7 @@ import org.stellar.sdk.requests.sorobanrpc.GetEventsRequest; import org.stellar.sdk.requests.sorobanrpc.GetLedgerEntriesRequest; import org.stellar.sdk.requests.sorobanrpc.GetTransactionRequest; +import org.stellar.sdk.requests.sorobanrpc.GetTransactionsRequest; import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SimulateTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SorobanRpcRequest; @@ -41,6 +42,7 @@ import org.stellar.sdk.responses.sorobanrpc.GetLedgerEntriesResponse; import org.stellar.sdk.responses.sorobanrpc.GetNetworkResponse; import org.stellar.sdk.responses.sorobanrpc.GetTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.GetTransactionsResponse; import org.stellar.sdk.responses.sorobanrpc.SendTransactionResponse; import org.stellar.sdk.responses.sorobanrpc.SimulateTransactionResponse; import org.stellar.sdk.responses.sorobanrpc.SorobanRpcResponse; @@ -160,8 +162,8 @@ public GetHealthResponse getHealth() { * @throws RequestTimeoutException If the request timed out. * @throws ConnectionErrorException When the request cannot be executed due to cancellation or * connectivity problems, etc. - * @see getHealth - * documentation + * @see getFeeStats documentation */ public GetFeeStatsResponse getFeeStats() { return this.sendRequest( @@ -287,6 +289,31 @@ public GetTransactionResponse getTransaction(String hash) { "getTransaction", params, new TypeToken>() {}); } + /** + * Gets a detailed list of transactions 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 getTransactionsRequest The {@link GetEventsRequest} 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 + * 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 getTransactions documentation + */ + public GetTransactionsResponse getTransactions(GetTransactionsRequest getTransactionsRequest) { + return this.sendRequest( + "getTransactions", + getTransactionsRequest, + new TypeToken>() {}); + } + /** * Fetches all events that match the given {@link GetEventsRequest}. * diff --git a/src/main/java/org/stellar/sdk/requests/sorobanrpc/GetTransactionsRequest.java b/src/main/java/org/stellar/sdk/requests/sorobanrpc/GetTransactionsRequest.java new file mode 100644 index 000000000..8c21dd5d9 --- /dev/null +++ b/src/main/java/org/stellar/sdk/requests/sorobanrpc/GetTransactionsRequest.java @@ -0,0 +1,27 @@ +package org.stellar.sdk.requests.sorobanrpc; + +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; + +/** + * Request for JSON-RPC method getTransactions. + * + * @see getEvents documentation + */ +@Value +@Builder(toBuilder = true) +public class GetTransactionsRequest { + @NonNull Long startLedger; + + PaginationOptions pagination; + + @Value + @Builder(toBuilder = true) + public static class PaginationOptions { + Long limit; + + String cursor; + } +} diff --git a/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetTransactionsResponse.java b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetTransactionsResponse.java new file mode 100644 index 000000000..d0d5e2405 --- /dev/null +++ b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetTransactionsResponse.java @@ -0,0 +1,96 @@ +package org.stellar.sdk.responses.sorobanrpc; + +import java.util.List; +import java.util.stream.Collectors; +import lombok.Value; +import org.stellar.sdk.Util; +import org.stellar.sdk.xdr.DiagnosticEvent; +import org.stellar.sdk.xdr.TransactionEnvelope; +import org.stellar.sdk.xdr.TransactionMeta; +import org.stellar.sdk.xdr.TransactionResult; + +/** + * Response for JSON-RPC method getTransactions. + * + * @see getTransactions documentation + */ +@Value +public class GetTransactionsResponse { + List transactions; + Long latestLedger; + Long latestLedgerCloseTimestamp; + Long oldestLedger; + Long oldestLedgerCloseTimestamp; + String cursor; + + @Value + public static class Transaction { + TransactionStatus status; + Integer applicationOrder; + Boolean feeBump; + + /** The field can be parsed as {@link org.stellar.sdk.xdr.TransactionEnvelope} object. */ + String envelopeXdr; + + /** The field can be parsed as {@link org.stellar.sdk.xdr.TransactionResult} object. */ + String resultXdr; + + /** The field can be parsed as {@link org.stellar.sdk.xdr.TransactionMeta} object. */ + String resultMetaXdr; + + Long ledger; + Long createdAt; + List diagnosticEventsXdr; + + /** + * Parses the {@code envelopeXdr} field from a string to an {@link + * org.stellar.sdk.xdr.TransactionEnvelope} object. + * + * @return the parsed {@link org.stellar.sdk.xdr.TransactionEnvelope} object + */ + public TransactionEnvelope parseEnvelopeXdr() { + return Util.parseXdr(envelopeXdr, TransactionEnvelope::fromXdrBase64); + } + + /** + * Parses the {@code resultXdr} field from a string to an {@link + * org.stellar.sdk.xdr.TransactionResult} object. + * + * @return the parsed {@link org.stellar.sdk.xdr.TransactionResult} object + */ + public TransactionResult parseResultXdr() { + return Util.parseXdr(resultXdr, TransactionResult::fromXdrBase64); + } + + /** + * Parses the {@code resultMetaXdr} field from a string to an {@link + * org.stellar.sdk.xdr.TransactionMeta} object. + * + * @return the parsed {@link org.stellar.sdk.xdr.TransactionMeta} object + */ + public TransactionMeta parseResultMetaXdr() { + return Util.parseXdr(resultMetaXdr, TransactionMeta::fromXdrBase64); + } + + /** + * Parses the {@code diagnosticEventsXdr} field from a list of strings to a list of {@link + * org.stellar.sdk.xdr.DiagnosticEvent} objects. + * + * @return a list of parsed {@link org.stellar.sdk.xdr.DiagnosticEvent} objects + */ + public List parseDiagnosticEventsXdr() { + if (diagnosticEventsXdr == null) { + return null; + } + return diagnosticEventsXdr.stream() + .map(xdr -> Util.parseXdr(xdr, DiagnosticEvent::fromXdrBase64)) + .collect(Collectors.toList()); + } + } + + public enum TransactionStatus { + SUCCESS, + FAILED + } +} diff --git a/src/test/java/org/stellar/sdk/SorobanServerTest.java b/src/test/java/org/stellar/sdk/SorobanServerTest.java index 2e0556849..1ce434281 100644 --- a/src/test/java/org/stellar/sdk/SorobanServerTest.java +++ b/src/test/java/org/stellar/sdk/SorobanServerTest.java @@ -32,6 +32,7 @@ import org.stellar.sdk.requests.sorobanrpc.GetEventsRequest; import org.stellar.sdk.requests.sorobanrpc.GetLedgerEntriesRequest; import org.stellar.sdk.requests.sorobanrpc.GetTransactionRequest; +import org.stellar.sdk.requests.sorobanrpc.GetTransactionsRequest; import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SimulateTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SorobanRpcRequest; @@ -41,6 +42,7 @@ import org.stellar.sdk.responses.sorobanrpc.GetLatestLedgerResponse; import org.stellar.sdk.responses.sorobanrpc.GetLedgerEntriesResponse; import org.stellar.sdk.responses.sorobanrpc.GetNetworkResponse; +import org.stellar.sdk.responses.sorobanrpc.GetTransactionsResponse; import org.stellar.sdk.responses.sorobanrpc.SendTransactionResponse; import org.stellar.sdk.responses.sorobanrpc.SimulateTransactionResponse; import org.stellar.sdk.xdr.ContractDataDurability; @@ -654,6 +656,178 @@ public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) mockWebServer.close(); } + @Test + public void testGetTransactions() throws IOException, SorobanRpcException { + String json = + "{\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"id\": \"198cb1a8-9104-4446-a269-88bf000c2721\",\n" + + " \"result\": {\n" + + " \"transactions\": [\n" + + " {\n" + + " \"status\": \"FAILED\",\n" + + " \"applicationOrder\": 1,\n" + + " \"feeBump\": false,\n" + + " \"envelopeXdr\": \"AAAAAgAAAACDz21Q3CTITlGqRus3/96/05EDivbtfJncNQKt64BTbAAAASwAAKkyAAXlMwAAAAEAAAAAAAAAAAAAAABmWeASAAAAAQAAABR3YWxsZXQ6MTcxMjkwNjMzNjUxMAAAAAEAAAABAAAAAIPPbVDcJMhOUapG6zf/3r/TkQOK9u18mdw1Aq3rgFNsAAAAAQAAAABwOSvou8mtwTtCkysVioO35TSgyRir2+WGqO8FShG/GAAAAAFVQUgAAAAAAO371tlrHUfK+AvmQvHje1jSUrvJb3y3wrJ7EplQeqTkAAAAAAX14QAAAAAAAAAAAeuAU2wAAABAn+6A+xXvMasptAm9BEJwf5Y9CLLQtV44TsNqS8ocPmn4n8Rtyb09SBiFoMv8isYgeQU5nAHsIwBNbEKCerusAQ==\",\n" + + " \"resultXdr\": \"AAAAAAAAAGT/////AAAAAQAAAAAAAAAB////+gAAAAA=\",\n" + + " \"resultMetaXdr\": \"AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAAIPPbVDcJMhOUapG6zf/3r/TkQOK9u18mdw1Aq3rgFNsAAAAF0YpYBQAAKkyAAXlMgAAAAsAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzRGgAAAABmWd/VAAAAAAAAAAEAHNEbAAAAAAAAAACDz21Q3CTITlGqRus3/96/05EDivbtfJncNQKt64BTbAAAABdGKWAUAACpMgAF5TMAAAALAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAAAAAAAAAAAAAA=\",\n" + + " \"ledger\": 1888539,\n" + + " \"createdAt\": 1717166042\n" + + " },\n" + + " {\n" + + " \"status\": \"SUCCESS\",\n" + + " \"applicationOrder\": 2,\n" + + " \"feeBump\": false,\n" + + " \"envelopeXdr\": \"AAAAAgAAAAC4EZup+ewCs/doS3hKbeAa4EviBHqAFYM09oHuLtqrGAAPQkAAGgQZAAAANgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAAAq6aHAHZ2sd9aPbRsskrlXMLWIwqs4Sv2Bk+VwuIR+9wAAABdIdugAAAAAAAAAAAIu2qsYAAAAQERzKOqYYiPXNwsiL8ADAG/f45RBssmf3umGzw4qKkLGlObuPdX0buWmTGrhI13SG38F2V8Mp9DI+eDkcCjMSAOGVuCcAAAAQHnm0o/r+Gsl+6oqBgSbqoSY37gflvQB3zZRghuir0N75UVerd0Q50yG5Zfu08i2crhx6uk+5HYTl8/Sa7uZ+Qc=\",\n" + + " \"resultXdr\": \"AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=\",\n" + + " \"resultMetaXdr\": \"AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAALgRm6n57AKz92hLeEpt4BrgS+IEeoAVgzT2ge4u2qsYAAAAADwzS2gAGgQZAAAANQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzPVAAAAABmWdZ2AAAAAAAAAAEAHNEbAAAAAAAAAAC4EZup+ewCs/doS3hKbeAa4EviBHqAFYM09oHuLtqrGAAAAAA8M0toABoEGQAAADYAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAABAAAAAwAAAAMAHNEaAAAAAAAAAAAQfdFrLDgzSIIugR73qs8U0ZiKbwBUclTTPh5thlbgnABZJUSd0V2hAAAAawAAAlEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAaBGEAAAAAZkspCwAAAAAAAAABABzRGwAAAAAAAAAAEH3Rayw4M0iCLoEe96rPFNGYim8AVHJU0z4ebYZW4JwAWSUtVVp1oQAAAGsAAAJRAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAAGgRhAAAAAGZLKQsAAAAAAAAAAAAc0RsAAAAAAAAAACrpocAdnax31o9tGyySuVcwtYjCqzhK/YGT5XC4hH73AAAAF0h26AAAHNEbAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\n" + + " \"ledger\": 1888539,\n" + + " \"createdAt\": 1717166042\n" + + " },\n" + + " {\n" + + " \"status\": \"SUCCESS\",\n" + + " \"applicationOrder\": 3,\n" + + " \"feeBump\": false,\n" + + " \"envelopeXdr\": \"AAAAAgAAAACwtG/IRC5DZE1UdekijEsoQEPM/uOwZ3iY/Y8UZ3b9xAAPQkAAGgRHAAAANgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAADgdupKeB04lazKXCOb+E1JfxaM3tI4Xsb/qDa1MWOvXgAAABdIdugAAAAAAAAAAAJndv3EAAAAQKcTimw6KKcM0AeCMxXJcEK/hS9ROoj/qpMFppGNAr4W3ifSOSTGAFbA+cIVHmaV4p7xGcR+9JnUN1YjamvJZwSGVuCcAAAAQK9Cp775JbnYA793SXkkWWbmvnEFTiDPiFyTHxTphCwBDB1zqkXqGG6Q5O3dAyqkNJvj1XNRDsmY4pKV41qijQU=\",\n" + + " \"resultXdr\": \"AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=\",\n" + + " \"resultMetaXdr\": \"AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAALC0b8hELkNkTVR16SKMSyhAQ8z+47BneJj9jxRndv3EAAAAADwzS2gAGgRHAAAANQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzPVAAAAABmWdZ2AAAAAAAAAAEAHNEbAAAAAAAAAACwtG/IRC5DZE1UdekijEsoQEPM/uOwZ3iY/Y8UZ3b9xAAAAAA8M0toABoERwAAADYAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAABAAAAAwAAAAMAHNEbAAAAAAAAAAAQfdFrLDgzSIIugR73qs8U0ZiKbwBUclTTPh5thlbgnABZJS1VWnWhAAAAawAAAlEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAaBGEAAAAAZkspCwAAAAAAAAABABzRGwAAAAAAAAAAEH3Rayw4M0iCLoEe96rPFNGYim8AVHJU0z4ebYZW4JwAWSUWDOONoQAAAGsAAAJRAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAAGgRhAAAAAGZLKQsAAAAAAAAAAAAc0RsAAAAAAAAAAOB26kp4HTiVrMpcI5v4TUl/Foze0jhexv+oNrUxY69eAAAAF0h26AAAHNEbAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\n" + + " \"ledger\": 1888539,\n" + + " \"createdAt\": 1717166042\n" + + " },\n" + + " {\n" + + " \"status\": \"SUCCESS\",\n" + + " \"applicationOrder\": 4,\n" + + " \"feeBump\": false,\n" + + " \"envelopeXdr\": \"AAAAAgAAAACxMt2gKYOehEoVbmh9vfvZ4mVzXFSNTbAU5S4a8zorrAA4wrwAHLqRAAAADAAAAAAAAAAAAAAAAQAAAAAAAAAYAAAAAQAAAAAAAAAAAAAAALEy3aApg56EShVuaH29+9niZXNcVI1NsBTlLhrzOiusz3K+BVgRzXig/Bhz1TL5Qy+Ibv6cDvCfdaAtBMMFPcYAAAAAHXUVmJM11pdJSKKV52UJrVYlvxaPLmmg17nMe0HGy0MAAAABAAAAAAAAAAEAAAAAAAAAAAAAAACxMt2gKYOehEoVbmh9vfvZ4mVzXFSNTbAU5S4a8zorrM9yvgVYEc14oPwYc9Uy+UMviG7+nA7wn3WgLQTDBT3GAAAAAB11FZiTNdaXSUiiledlCa1WJb8Wjy5poNe5zHtBxstDAAAAAAAAAAEAAAAAAAAAAQAAAAcddRWYkzXWl0lIopXnZQmtViW/Fo8uaaDXucx7QcbLQwAAAAEAAAAGAAAAAbolCtTsMrJvK0M2SaskFsaMajj3iAZbXxELZHwDyE5dAAAAFAAAAAEABf2jAAAd1AAAAGgAAAAAADjCWAAAAAHzOiusAAAAQM+qaiMKxMoCVNjdRIh3X9CSxkjAm0BpXYDB9Fd+DS0guYKiY3TMaVe243UB008iBn5ynQv724rReXlg7iFqXQA=\",\n" + + " \"resultXdr\": \"AAAAAAAw3cUAAAAAAAAAAQAAAAAAAAAYAAAAAKg/pGuhtOG27rIpG8xhUIp46CStGWOcsGlNsTQv44UOAAAAAA==\",\n" + + " \"resultMetaXdr\": \"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\",\n" + + " \"diagnosticEventsXdr\": [\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACnJlYWRfZW50cnkAAAAAAAUAAAAAAAAAAg==\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAC3dyaXRlX2VudHJ5AAAAAAUAAAAAAAAAAQ==\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEGxlZGdlcl9yZWFkX2J5dGUAAAAFAAAAAAAAHdQ=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEWxlZGdlcl93cml0ZV9ieXRlAAAAAAAABQAAAAAAAABo\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADXJlYWRfa2V5X2J5dGUAAAAAAAAFAAAAAAAAAFQ=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADndyaXRlX2tleV9ieXRlAAAAAAAFAAAAAAAAAAA=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADnJlYWRfZGF0YV9ieXRlAAAAAAAFAAAAAAAAAAA=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD3dyaXRlX2RhdGFfYnl0ZQAAAAAFAAAAAAAAAGg=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADnJlYWRfY29kZV9ieXRlAAAAAAAFAAAAAAAAHdQ=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD3dyaXRlX2NvZGVfYnl0ZQAAAAAFAAAAAAAAAAA=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACmVtaXRfZXZlbnQAAAAAAAUAAAAAAAAAAA==\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD2VtaXRfZXZlbnRfYnl0ZQAAAAAFAAAAAAAAAAA=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACGNwdV9pbnNuAAAABQAAAAAABTO4\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACG1lbV9ieXRlAAAABQAAAAAAAPkD\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEWludm9rZV90aW1lX25zZWNzAAAAAAAABQAAAAAAAmiz\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD21heF9yd19rZXlfYnl0ZQAAAAAFAAAAAAAAADA=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEG1heF9yd19kYXRhX2J5dGUAAAAFAAAAAAAAAGg=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEG1heF9yd19jb2RlX2J5dGUAAAAFAAAAAAAAHdQ=\",\n" + + " \"AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAE21heF9lbWl0X2V2ZW50X2J5dGUAAAAABQAAAAAAAAAA\"\n" + + " ],\n" + + " \"ledger\": 1888539,\n" + + " \"createdAt\": 1717166042\n" + + " },\n" + + " {\n" + + " \"status\": \"FAILED\",\n" + + " \"applicationOrder\": 1,\n" + + " \"feeBump\": false,\n" + + " \"envelopeXdr\": \"AAAAAgAAAAAxLMEcxmfUgNzL687Js4sX/jmFQDqTo1Lj4KDoC1PeSQAehIAAAAIJAAtMUQAAAAEAAAAAAAAAAAAAAABmWeAVAAAAAQAAAAlwc3BiOjMyMTcAAAAAAAACAAAAAQAAAACKlutUN5GT3UOoE2BUkNtJEwoipGOinBFsQtXgpIZMxQAAAAEAAAAA433o+yremWU3t88cKpfpHR+JMFR44JHzmBGni6hqCEYAAAACQVRVQUgAAAAAAAAAAAAAAGfK1mN4mg51jbX6by6TWghGynQ463doEDgzriqZo9bzAAAAAAaOd4AAAAABAAAAAIqW61Q3kZPdQ6gTYFSQ20kTCiKkY6KcEWxC1eCkhkzFAAAAAQAAAADjfej7Kt6ZZTe3zxwql+kdH4kwVHjgkfOYEaeLqGoIRgAAAAJBVFVTRAAAAAAAAAAAAAAAZ8rWY3iaDnWNtfpvLpNaCEbKdDjrd2gQODOuKpmj1vMAAAAAADh1IAAAAAAAAAACC1PeSQAAAEBoad/kqj/4Sqq5tC6HyeMm5LJKM1VqKRGZc3e4uvA3ITThwn2nNMRJRegdQrLrPBTSgw51nY8npilXVIds7I0OpIZMxQAAAEDTZNaLjIDMWPDdCxa1ZB28vUxTcS/0xykOFTI/JAz096vX6Y7wI0QvnbPM7KCoL0cJAciD+pJxNqXQ2Aff1hoO\",\n" + + " \"resultXdr\": \"AAAAAAAAAMj/////AAAAAgAAAAAAAAAB////+wAAAAAAAAAB////+wAAAAA=\",\n" + + " \"resultMetaXdr\": \"AAAAAwAAAAAAAAACAAAAAwAc0RwAAAAAAAAAADEswRzGZ9SA3Mvrzsmzixf+OYVAOpOjUuPgoOgLU95JAAAAFxzxIbUAAAIJAAtMUAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzRGgAAAABmWd/VAAAAAAAAAAEAHNEcAAAAAAAAAAAxLMEcxmfUgNzL687Js4sX/jmFQDqTo1Lj4KDoC1PeSQAAABcc8SG1AAACCQALTFEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RwAAAAAZlnf3wAAAAAAAAAAAAAAAAAAAAA=\",\n" + + " \"ledger\": 1888540,\n" + + " \"createdAt\": 1717166047\n" + + " }\n" + + " ],\n" + + " \"latestLedger\": 1888542,\n" + + " \"latestLedgerCloseTimestamp\": 1717166057,\n" + + " \"oldestLedger\": 1871263,\n" + + " \"oldestLedgerCloseTimestamp\": 1717075350,\n" + + " \"cursor\": \"8111217537191937\"\n" + + " }\n" + + "}"; + + GetTransactionsRequest.PaginationOptions paginationOptions = + GetTransactionsRequest.PaginationOptions.builder().limit(5L).build(); + GetTransactionsRequest getTransactionsRequest = + GetTransactionsRequest.builder() + .startLedger(1888539L) + .pagination(paginationOptions) + .build(); + + MockWebServer mockWebServer = new MockWebServer(); + Dispatcher dispatcher = + new Dispatcher() { + @NotNull + @Override + public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) + throws InterruptedException { + SorobanRpcRequest sorobanRpcRequest = + gson.fromJson( + recordedRequest.getBody().readUtf8(), + new TypeToken>() {}.getType()); + if ("POST".equals(recordedRequest.getMethod()) + && sorobanRpcRequest.getMethod().equals("getTransactions") + && sorobanRpcRequest.getParams().equals(getTransactionsRequest)) { + 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()); + GetTransactionsResponse resp = server.getTransactions(getTransactionsRequest); + assertEquals(resp.getLatestLedger().longValue(), 1888542L); + assertEquals(resp.getLatestLedgerCloseTimestamp().longValue(), 1717166057L); + assertEquals(resp.getOldestLedger().longValue(), 1871263L); + assertEquals(resp.getOldestLedgerCloseTimestamp().longValue(), 1717075350L); + assertEquals(resp.getCursor(), "8111217537191937"); + assertEquals(resp.getTransactions().size(), 5); + assertEquals( + resp.getTransactions().get(0).getStatus(), + GetTransactionsResponse.TransactionStatus.FAILED); + assertEquals(resp.getTransactions().get(0).getApplicationOrder().longValue(), 1L); + assertEquals(resp.getTransactions().get(0).getFeeBump(), false); + assertEquals( + resp.getTransactions().get(0).getEnvelopeXdr(), + resp.getTransactions().get(0).parseEnvelopeXdr().toXdrBase64()); + assertEquals( + resp.getTransactions().get(0).getResultXdr(), + resp.getTransactions().get(0).parseResultXdr().toXdrBase64()); + assertEquals( + resp.getTransactions().get(0).getResultMetaXdr(), + resp.getTransactions().get(0).parseResultMetaXdr().toXdrBase64()); + assertEquals(resp.getTransactions().get(0).getLedger().longValue(), 1888539L); + assertEquals(resp.getTransactions().get(1).getCreatedAt().longValue(), 1717166042L); + + assertEquals( + resp.getTransactions().get(3).getStatus(), + GetTransactionsResponse.TransactionStatus.SUCCESS); + assertEquals(resp.getTransactions().get(3).getApplicationOrder().longValue(), 4L); + assertEquals(resp.getTransactions().get(3).getFeeBump(), false); + assertEquals( + resp.getTransactions().get(3).getEnvelopeXdr(), + resp.getTransactions().get(3).parseEnvelopeXdr().toXdrBase64()); + assertEquals( + resp.getTransactions().get(3).getResultXdr(), + resp.getTransactions().get(3).parseResultXdr().toXdrBase64()); + assertEquals( + resp.getTransactions().get(3).getResultMetaXdr(), + resp.getTransactions().get(3).parseResultMetaXdr().toXdrBase64()); + assertEquals(resp.getTransactions().get(3).getLedger().longValue(), 1888539L); + assertEquals(resp.getTransactions().get(3).getDiagnosticEventsXdr().size(), 19); + for (int i = 0; i < 19; i++) { + assertEquals( + resp.getTransactions().get(3).getDiagnosticEventsXdr().get(i), + resp.getTransactions().get(3).parseDiagnosticEventsXdr().get(i).toXdrBase64()); + } + assertEquals(resp.getTransactions().get(0).getLedger().longValue(), 1888539L); + assertEquals(resp.getTransactions().get(1).getCreatedAt().longValue(), 1717166042L); + + server.close(); + mockWebServer.close(); + } + @Test public void testGetEvents() throws IOException, SorobanRpcException { String json =