From 0a8849e643d7e69caa3c3db40b2374ecfa865c82 Mon Sep 17 00:00:00 2001 From: Jamie Li Date: Thu, 22 May 2025 15:31:12 -0700 Subject: [PATCH 1/3] Add getSacBalance to SorobanServer --- .../java/org/stellar/sdk/SorobanServer.java | 68 +++++++++++++------ .../sorobanrpc/GetSacBalanceResponse.java | 21 ++++++ .../org/stellar/sdk/SorobanServerTest.java | 60 ++++++++++++---- .../soroban_server/get_sac_balance.json | 15 ++++ 4 files changed, 133 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSacBalanceResponse.java create mode 100644 src/test/resources/soroban_server/get_sac_balance.json diff --git a/src/main/java/org/stellar/sdk/SorobanServer.java b/src/main/java/org/stellar/sdk/SorobanServer.java index 05cef0c90..83a18476f 100644 --- a/src/main/java/org/stellar/sdk/SorobanServer.java +++ b/src/main/java/org/stellar/sdk/SorobanServer.java @@ -5,12 +5,7 @@ import java.io.Closeable; import java.io.IOException; import java.net.SocketTimeoutException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; import okhttp3.HttpUrl; import okhttp3.MediaType; @@ -36,19 +31,8 @@ import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SimulateTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SorobanRpcRequest; -import org.stellar.sdk.responses.sorobanrpc.GetEventsResponse; -import org.stellar.sdk.responses.sorobanrpc.GetFeeStatsResponse; -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; -import org.stellar.sdk.responses.sorobanrpc.GetVersionInfoResponse; -import org.stellar.sdk.responses.sorobanrpc.SendTransactionResponse; -import org.stellar.sdk.responses.sorobanrpc.SimulateTransactionResponse; -import org.stellar.sdk.responses.sorobanrpc.SorobanRpcResponse; +import org.stellar.sdk.responses.sorobanrpc.*; +import org.stellar.sdk.scval.Scv; import org.stellar.sdk.xdr.ContractDataDurability; import org.stellar.sdk.xdr.LedgerEntry; import org.stellar.sdk.xdr.LedgerEntryType; @@ -560,6 +544,52 @@ public SendTransactionResponse sendTransaction(Transaction transaction) { "sendTransaction", params, new TypeToken>() {}); } + public GetSacBalanceResponse getSacBalance(String contractId, Asset asset, Network network) + throws IOException { + + if (!StrKey.isValidContract(contractId)) { + throw new IllegalArgumentException("expected contract ID, got " + contractId); + } + + LedgerKey ledgerKey = + LedgerKey.builder() + .discriminant(LedgerEntryType.CONTRACT_DATA) + .contractData( + LedgerKey.LedgerKeyContractData.builder() + .contract(Scv.toAddress(asset.getContractId(network)).getAddress()) + .key( + Scv.toVec( + Arrays.asList(Scv.toSymbol("Balance"), Scv.toAddress(contractId)))) + .durability(ContractDataDurability.PERSISTENT) + .build()) + .build(); + + GetLedgerEntriesResponse response = this.getLedgerEntries(Collections.singleton(ledgerKey)); + + List entries = response.getEntries(); + if (entries == null || entries.isEmpty()) { + return null; + } + + GetLedgerEntriesResponse.LedgerEntryResult entry = entries.get(0); + LedgerEntry.LedgerEntryData ledgerEntryData = + LedgerEntry.LedgerEntryData.fromXdrBase64(entry.getXdr()); + LinkedHashMap balanceMap = + Scv.fromMap(ledgerEntryData.getContractData().getVal()); + + return GetSacBalanceResponse.builder() + .latestLedger(response.getLatestLedger()) + .balanceEntry( + GetSacBalanceResponse.BalanceEntry.builder() + .liveUntilLedgerSeq(entry.getLiveUntilLedger()) + .lastModifiedLedgerSeq(entry.getLastModifiedLedger()) + .amount(Scv.fromInt128(balanceMap.get(Scv.toSymbol("amount"))).toString()) + .authorized(Scv.fromBoolean(balanceMap.get(Scv.toSymbol("authorized")))) + .clawback(Scv.fromBoolean(balanceMap.get(Scv.toSymbol("clawback")))) + .build()) + .build(); + } + public static Transaction assembleTransaction( Transaction transaction, SimulateTransactionResponse simulateTransactionResponse) { if (!transaction.isSorobanTransaction()) { diff --git a/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSacBalanceResponse.java b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSacBalanceResponse.java new file mode 100644 index 000000000..d3d0f74e2 --- /dev/null +++ b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSacBalanceResponse.java @@ -0,0 +1,21 @@ +package org.stellar.sdk.responses.sorobanrpc; + +import lombok.Builder; +import lombok.Value; + +@Builder +@Value +public class GetSacBalanceResponse { + long latestLedger; + BalanceEntry balanceEntry; + + @Value + @Builder + public static class BalanceEntry { + Long liveUntilLedgerSeq; + Long lastModifiedLedgerSeq; + String amount; + Boolean authorized; + Boolean clawback; + } +} diff --git a/src/test/java/org/stellar/sdk/SorobanServerTest.java b/src/test/java/org/stellar/sdk/SorobanServerTest.java index 60d8cbfd7..7b712de49 100644 --- a/src/test/java/org/stellar/sdk/SorobanServerTest.java +++ b/src/test/java/org/stellar/sdk/SorobanServerTest.java @@ -39,18 +39,7 @@ import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SimulateTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SorobanRpcRequest; -import org.stellar.sdk.responses.sorobanrpc.GetEventsResponse; -import org.stellar.sdk.responses.sorobanrpc.GetFeeStatsResponse; -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; -import org.stellar.sdk.responses.sorobanrpc.GetVersionInfoResponse; -import org.stellar.sdk.responses.sorobanrpc.SendTransactionResponse; -import org.stellar.sdk.responses.sorobanrpc.SimulateTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.*; import org.stellar.sdk.xdr.ContractDataDurability; import org.stellar.sdk.xdr.ContractExecutable; import org.stellar.sdk.xdr.ContractExecutableType; @@ -1354,6 +1343,53 @@ public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) mockWebServer.close(); } + @Test + public void testGetSacBalance() throws IOException { + String filePath = "src/test/resources/soroban_server/get_sac_balance.json"; + String json = new String(Files.readAllBytes(Paths.get(filePath))); + MockWebServer mockWebServer = new MockWebServer(); + Dispatcher dispatcher = + new Dispatcher() { + @NotNull + @Override + public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) { + SorobanRpcRequest sorobanRpcRequest = + gson.fromJson( + recordedRequest.getBody().readUtf8(), + new TypeToken>() {}.getType()); + if ("POST".equals(recordedRequest.getMethod()) + && sorobanRpcRequest.getMethod().equals("getLedgerEntries") + && "AAAABgAAAAHXkotywnA8z+r365/0701QSlWouXn8m0UOoshCtNHOYQAAABAAAAABAAAAAgAAAA8AAAAHQmFsYW5jZQAAAAASAAAAATS6wvBZn2PXUHdI2oDWZqeECiy17cpcL6qrr1lqpqu6AAAAAQ==" + .equals( + sorobanRpcRequest.getParams().getKeys().stream() + .findFirst() + .orElse(null))) { + 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()); + GetSacBalanceResponse balance = + server.getSacBalance( + "CA2LVQXQLGPWHV2QO5ENVAGWM2TYICRMWXW4UXBPVKV26WLKU2V3UTH5", + Asset.createNativeAsset(), + Network.TESTNET); + assertEquals(1104160, balance.getLatestLedger()); + assertEquals((Long) 3163876L, balance.getBalanceEntry().getLiveUntilLedgerSeq()); + assertEquals((Long) 1090887L, balance.getBalanceEntry().getLastModifiedLedgerSeq()); + assertEquals("28", balance.getBalanceEntry().getAmount()); + assertTrue(balance.getBalanceEntry().getAuthorized()); + assertFalse(balance.getBalanceEntry().getClawback()); + + server.close(); + mockWebServer.close(); + } + @Test public void testSorobanRpcErrorResponseThrows() throws IOException { String filePath = "src/test/resources/soroban_server/soroban_rpc_error.json"; diff --git a/src/test/resources/soroban_server/get_sac_balance.json b/src/test/resources/soroban_server/get_sac_balance.json new file mode 100644 index 000000000..03ff4bb40 --- /dev/null +++ b/src/test/resources/soroban_server/get_sac_balance.json @@ -0,0 +1,15 @@ +{ + "jsonrpc": "2.0", + "id": "5715b491-e70c-483b-b000-315735c4129b", + "result": { + "entries": [ + { + "key": "AAAABgAAAAHXkotywnA8z+r365/0701QSlWouXn8m0UOoshCtNHOYQAAABAAAAABAAAAAgAAAA8AAAAHQmFsYW5jZQAAAAASAAAAATS6wvBZn2PXUHdI2oDWZqeECiy17cpcL6qrr1lqpqu6AAAAAQ==", + "xdr": "AAAABgAAAAAAAAAB15KLcsJwPM/q9+uf9O9NUEpVqLl5/JtFDqLIQrTRzmEAAAAQAAAAAQAAAAIAAAAPAAAAB0JhbGFuY2UAAAAAEgAAAAE0usLwWZ9j11B3SNqA1manhAoste3KXC+qq69ZaqarugAAAAEAAAARAAAAAQAAAAMAAAAPAAAABmFtb3VudAAAAAAACgAAAAAAAAAAAAAAAAAAABwAAAAPAAAACmF1dGhvcml6ZWQAAAAAAAAAAAABAAAADwAAAAhjbGF3YmFjawAAAAAAAAAA", + "lastModifiedLedgerSeq": 1090887, + "liveUntilLedgerSeq": 3163876 + } + ], + "latestLedger": 1104160 + } +} \ No newline at end of file From 957026f16d7d44060f4c6e0d14e6d6fd13487239 Mon Sep 17 00:00:00 2001 From: Jamie Li Date: Fri, 23 May 2025 08:33:22 -0700 Subject: [PATCH 2/3] PR comments #1 --- .../java/org/stellar/sdk/SorobanServer.java | 25 +++++++++++++------ ...sponse.java => GetSACBalanceResponse.java} | 4 +-- .../org/stellar/sdk/SorobanServerTest.java | 8 +++--- 3 files changed, 23 insertions(+), 14 deletions(-) rename src/main/java/org/stellar/sdk/responses/sorobanrpc/{GetSacBalanceResponse.java => GetSACBalanceResponse.java} (84%) diff --git a/src/main/java/org/stellar/sdk/SorobanServer.java b/src/main/java/org/stellar/sdk/SorobanServer.java index 83a18476f..1787f577b 100644 --- a/src/main/java/org/stellar/sdk/SorobanServer.java +++ b/src/main/java/org/stellar/sdk/SorobanServer.java @@ -544,11 +544,19 @@ public SendTransactionResponse sendTransaction(Transaction transaction) { "sendTransaction", params, new TypeToken>() {}); } - public GetSacBalanceResponse getSacBalance(String contractId, Asset asset, Network network) - throws IOException { - + /** + * Fetches the balance of a specific asset for a contract. This is useful for checking the balance + * of a contract in a specific asset. + * + * @param contractId The contract ID containing the asset balance. Encoded as Stellar Contract + * Address. e.g. CAB... + * @param asset The asset to check the balance for. This should be a valid asset object. + * @param network The network to use for the asset. + * @return A {@link GetSACBalanceResponse} object containing the balance information. + */ + public GetSACBalanceResponse getSACBalance(String contractId, Asset asset, Network network) { if (!StrKey.isValidContract(contractId)) { - throw new IllegalArgumentException("expected contract ID, got " + contractId); + throw new IllegalArgumentException("Invalid contract ID: " + contractId); } LedgerKey ledgerKey = @@ -568,19 +576,20 @@ public GetSacBalanceResponse getSacBalance(String contractId, Asset asset, Netwo List entries = response.getEntries(); if (entries == null || entries.isEmpty()) { - return null; + return GetSACBalanceResponse.builder().latestLedger(response.getLatestLedger()).build(); } GetLedgerEntriesResponse.LedgerEntryResult entry = entries.get(0); LedgerEntry.LedgerEntryData ledgerEntryData = - LedgerEntry.LedgerEntryData.fromXdrBase64(entry.getXdr()); + Util.parseXdr(entry.getXdr(), LedgerEntry.LedgerEntryData::fromXdrBase64); + LinkedHashMap balanceMap = Scv.fromMap(ledgerEntryData.getContractData().getVal()); - return GetSacBalanceResponse.builder() + return GetSACBalanceResponse.builder() .latestLedger(response.getLatestLedger()) .balanceEntry( - GetSacBalanceResponse.BalanceEntry.builder() + GetSACBalanceResponse.BalanceEntry.builder() .liveUntilLedgerSeq(entry.getLiveUntilLedger()) .lastModifiedLedgerSeq(entry.getLastModifiedLedger()) .amount(Scv.fromInt128(balanceMap.get(Scv.toSymbol("amount"))).toString()) diff --git a/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSacBalanceResponse.java b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSACBalanceResponse.java similarity index 84% rename from src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSacBalanceResponse.java rename to src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSACBalanceResponse.java index d3d0f74e2..e1e56ac69 100644 --- a/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSacBalanceResponse.java +++ b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSACBalanceResponse.java @@ -5,8 +5,8 @@ @Builder @Value -public class GetSacBalanceResponse { - long latestLedger; +public class GetSACBalanceResponse { + Long latestLedger; BalanceEntry balanceEntry; @Value diff --git a/src/test/java/org/stellar/sdk/SorobanServerTest.java b/src/test/java/org/stellar/sdk/SorobanServerTest.java index 7b712de49..8d8d9bb95 100644 --- a/src/test/java/org/stellar/sdk/SorobanServerTest.java +++ b/src/test/java/org/stellar/sdk/SorobanServerTest.java @@ -1344,7 +1344,7 @@ public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) } @Test - public void testGetSacBalance() throws IOException { + public void testGetSACBalance() throws IOException { String filePath = "src/test/resources/soroban_server/get_sac_balance.json"; String json = new String(Files.readAllBytes(Paths.get(filePath))); MockWebServer mockWebServer = new MockWebServer(); @@ -1374,12 +1374,12 @@ public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) { HttpUrl baseUrl = mockWebServer.url(""); SorobanServer server = new SorobanServer(baseUrl.toString()); - GetSacBalanceResponse balance = - server.getSacBalance( + GetSACBalanceResponse balance = + server.getSACBalance( "CA2LVQXQLGPWHV2QO5ENVAGWM2TYICRMWXW4UXBPVKV26WLKU2V3UTH5", Asset.createNativeAsset(), Network.TESTNET); - assertEquals(1104160, balance.getLatestLedger()); + assertEquals((Long) 1104160L, balance.getLatestLedger()); assertEquals((Long) 3163876L, balance.getBalanceEntry().getLiveUntilLedgerSeq()); assertEquals((Long) 1090887L, balance.getBalanceEntry().getLastModifiedLedgerSeq()); assertEquals("28", balance.getBalanceEntry().getAmount()); From c6fbaae4c6d58c3df590d411d66b86f355743cee Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 24 May 2025 16:20:17 +0800 Subject: [PATCH 3/3] remove wildcard import & add docs --- .../java/org/stellar/sdk/SorobanServer.java | 30 +++++++++++++++++-- .../sorobanrpc/GetSACBalanceResponse.java | 12 ++++++-- .../org/stellar/sdk/SorobanServerTest.java | 16 +++++++++- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/stellar/sdk/SorobanServer.java b/src/main/java/org/stellar/sdk/SorobanServer.java index 1787f577b..b6efe0bc3 100644 --- a/src/main/java/org/stellar/sdk/SorobanServer.java +++ b/src/main/java/org/stellar/sdk/SorobanServer.java @@ -5,7 +5,14 @@ import java.io.Closeable; import java.io.IOException; import java.net.SocketTimeoutException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import java.util.concurrent.TimeUnit; import okhttp3.HttpUrl; import okhttp3.MediaType; @@ -31,7 +38,20 @@ import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SimulateTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SorobanRpcRequest; -import org.stellar.sdk.responses.sorobanrpc.*; +import org.stellar.sdk.responses.sorobanrpc.GetEventsResponse; +import org.stellar.sdk.responses.sorobanrpc.GetFeeStatsResponse; +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.GetSACBalanceResponse; +import org.stellar.sdk.responses.sorobanrpc.GetTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.GetTransactionsResponse; +import org.stellar.sdk.responses.sorobanrpc.GetVersionInfoResponse; +import org.stellar.sdk.responses.sorobanrpc.SendTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.SimulateTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.SorobanRpcResponse; import org.stellar.sdk.scval.Scv; import org.stellar.sdk.xdr.ContractDataDurability; import org.stellar.sdk.xdr.LedgerEntry; @@ -552,7 +572,11 @@ public SendTransactionResponse sendTransaction(Transaction transaction) { * Address. e.g. CAB... * @param asset The asset to check the balance for. This should be a valid asset object. * @param network The network to use for the asset. - * @return A {@link GetSACBalanceResponse} object containing the balance information. + * @return A {@link GetSACBalanceResponse} which will contain the balance entry details if and + * only if the request returned a valid balance ledger entry. If it doesn't, the {@code + * balanceEntry} field will not exist. + * @see Stellar Asset Contract (SAC) documentation */ public GetSACBalanceResponse getSACBalance(String contractId, Asset asset, Network network) { if (!StrKey.isValidContract(contractId)) { diff --git a/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSACBalanceResponse.java b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSACBalanceResponse.java index e1e56ac69..82f2b2acf 100644 --- a/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSACBalanceResponse.java +++ b/src/main/java/org/stellar/sdk/responses/sorobanrpc/GetSACBalanceResponse.java @@ -2,15 +2,23 @@ import lombok.Builder; import lombok.Value; +import org.jetbrains.annotations.Nullable; +import org.stellar.sdk.Asset; +import org.stellar.sdk.Network; +/** Response for {@link org.stellar.sdk.SorobanServer#getSACBalance(String, Asset, Network)}. */ @Builder @Value public class GetSACBalanceResponse { Long latestLedger; - BalanceEntry balanceEntry; - @Value + /** + * The balance entry for the account. If there is not a valid balance entry, this will be null. + */ + @Nullable BalanceEntry balanceEntry; + @Builder + @Value public static class BalanceEntry { Long liveUntilLedgerSeq; Long lastModifiedLedgerSeq; diff --git a/src/test/java/org/stellar/sdk/SorobanServerTest.java b/src/test/java/org/stellar/sdk/SorobanServerTest.java index 8d8d9bb95..5e5a45b33 100644 --- a/src/test/java/org/stellar/sdk/SorobanServerTest.java +++ b/src/test/java/org/stellar/sdk/SorobanServerTest.java @@ -3,6 +3,7 @@ import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -39,7 +40,19 @@ import org.stellar.sdk.requests.sorobanrpc.SendTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SimulateTransactionRequest; import org.stellar.sdk.requests.sorobanrpc.SorobanRpcRequest; -import org.stellar.sdk.responses.sorobanrpc.*; +import org.stellar.sdk.responses.sorobanrpc.GetEventsResponse; +import org.stellar.sdk.responses.sorobanrpc.GetFeeStatsResponse; +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.GetSACBalanceResponse; +import org.stellar.sdk.responses.sorobanrpc.GetTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.GetTransactionsResponse; +import org.stellar.sdk.responses.sorobanrpc.GetVersionInfoResponse; +import org.stellar.sdk.responses.sorobanrpc.SendTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.SimulateTransactionResponse; import org.stellar.sdk.xdr.ContractDataDurability; import org.stellar.sdk.xdr.ContractExecutable; import org.stellar.sdk.xdr.ContractExecutableType; @@ -1380,6 +1393,7 @@ public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) { Asset.createNativeAsset(), Network.TESTNET); assertEquals((Long) 1104160L, balance.getLatestLedger()); + assertNotNull(balance.getBalanceEntry()); assertEquals((Long) 3163876L, balance.getBalanceEntry().getLiveUntilLedgerSeq()); assertEquals((Long) 1090887L, balance.getBalanceEntry().getLastModifiedLedgerSeq()); assertEquals("28", balance.getBalanceEntry().getAmount());