From 575a93786adb0360a77b8b56a2ccc4602c20bc52 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 22 Oct 2024 02:42:00 +0900 Subject: [PATCH 1/6] WIP: Get account balance endpoints --- .../kotlin/org/onflow/flow/sdk/FlowAccessApi.kt | 4 ++++ .../org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt index f18239c..200cda2 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt @@ -26,6 +26,10 @@ interface FlowAccessApi { fun getLatestBlock(sealed: Boolean = true): AccessApiCallResponse + fun getAccountBalanceAtLatestBlock(address: FlowAddress): AccessApiCallResponse + + fun getAccountBalanceAtBlockHeight(address: FlowAddress, height: Long): AccessApiCallResponse + fun getBlockById(id: FlowId): AccessApiCallResponse fun getBlockByHeight(height: Long): AccessApiCallResponse diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt index 751cb94..7df7e09 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt @@ -96,6 +96,19 @@ class FlowAccessApiImpl( FlowAccessApi.AccessApiCallResponse.Error("Failed to get latest block", e) } + override fun getAccountBalanceAtLatestBlock(address: FlowAddress): FlowAccessApi.AccessApiCallResponse = + try { + val ret = api.getAccountBalanceAtLatestBlock( + Access.GetAccountBalanceAtLatestBlockRequest + .newBuilder() + .setAddress(address.byteStringValue) + .build() + ) + FlowAccessApi.AccessApiCallResponse.Success(ret.balance) + } catch (e: Exception) { + FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", e) + } + override fun getBlockById(id: FlowId): FlowAccessApi.AccessApiCallResponse = try { val ret = api.getBlockByID( From aa8a22616a0453c406dfd24c193bd83b14814a38 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 22 Oct 2024 02:49:37 +0900 Subject: [PATCH 2/6] WIP: Get account balance endpoints --- .../org/onflow/flow/sdk/AsyncFlowAccessApi.kt | 4 ++ .../flow/sdk/impl/AsyncFlowAccessApiImpl.kt | 51 +++++++++++++++++++ .../onflow/flow/sdk/impl/FlowAccessApiImpl.kt | 14 +++++ 3 files changed, 69 insertions(+) diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt index 78be56d..ebe72a6 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt @@ -14,6 +14,10 @@ interface AsyncFlowAccessApi { fun getLatestBlock(sealed: Boolean = true): CompletableFuture> + fun getAccountBalanceAtLatestBlock(address: FlowAddress): CompletableFuture> + + fun getAccountBalanceAtBlockHeight(address: FlowAddress, height: Long): CompletableFuture> + fun getBlockById(id: FlowId): CompletableFuture> fun getBlockByHeight(height: Long): CompletableFuture> diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt index f5fd81e..a2366fe 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt @@ -152,6 +152,57 @@ class AsyncFlowAccessApiImpl( } } + override fun getAccountBalanceAtLatestBlock(address: FlowAddress): CompletableFuture> { + return try { + completableFuture( + try { + api.getAccountBalanceAtLatestBlock( + Access.GetAccountBalanceAtLatestBlockRequest + .newBuilder() + .setAddress(address.byteStringValue) + .build() + ) + } catch (e: Exception) { + return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", e)) + } + ).handle { response, ex -> + if (ex != null) { + FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", ex) + } else { + FlowAccessApi.AccessApiCallResponse.Success(response.balance) + } + } + } catch (e: Exception) { + CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", e)) + } + } + + override fun getAccountBalanceAtBlockHeight(address: FlowAddress, height: Long): CompletableFuture> { + return try { + completableFuture( + try { + api.getAccountBalanceAtBlockHeight( + Access.GetAccountBalanceAtBlockHeightRequest + .newBuilder() + .setAddress(address.byteStringValue) + .setBlockHeight(height) + .build() + ) + } catch (e: Exception) { + return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", e)) + } + ).handle { response, ex -> + if (ex != null) { + FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", ex) + } else { + FlowAccessApi.AccessApiCallResponse.Success(response.balance) + } + } + } catch (e: Exception) { + CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", e)) + } + } + override fun getBlockById(id: FlowId): CompletableFuture> { return try { completableFuture( diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt index 7df7e09..256ecbc 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt @@ -109,6 +109,20 @@ class FlowAccessApiImpl( FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", e) } + override fun getAccountBalanceAtBlockHeight(address: FlowAddress, height: Long): FlowAccessApi.AccessApiCallResponse = + try { + val ret = api.getAccountBalanceAtBlockHeight( + Access.GetAccountBalanceAtBlockHeightRequest + .newBuilder() + .setAddress(address.byteStringValue) + .setBlockHeight(height) + .build() + ) + FlowAccessApi.AccessApiCallResponse.Success(ret.balance) + } catch (e: Exception) { + FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", e) + } + override fun getBlockById(id: FlowId): FlowAccessApi.AccessApiCallResponse = try { val ret = api.getBlockByID( From 93e6aeefc2963b505b9d6dd4b4031fe2c7aae7f0 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Wed, 23 Oct 2024 01:41:56 +0900 Subject: [PATCH 3/6] Update unit tests for account balance endpoints --- .../org/onflow/flow/sdk/FlowAccessApiTest.kt | 62 +++++++++++++++ .../sdk/impl/AsyncFlowAccessApiImplTest.kt | 64 ++++++++++++++++ .../flow/sdk/impl/FlowAccessApiImplTest.kt | 75 +++++++++++++++++++ 3 files changed, 201 insertions(+) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt index 9c825ea..1cd2915 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt @@ -88,6 +88,68 @@ class FlowAccessApiTest { assertEquals(FlowAccessApi.AccessApiCallResponse.Success(block), result) } + @Test + fun `Test getAccountBalanceAtLatestBlock success`() { + val flowAccessApi = mock(FlowAccessApi::class.java) + val flowAddress = FlowAddress("01") + val expectedBalance = 1000L + val response = FlowAccessApi.AccessApiCallResponse.Success(expectedBalance) + + `when`(flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress)).thenReturn(response) + + val result = flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress) + + assertEquals(response, result) + verify(flowAccessApi).getAccountBalanceAtLatestBlock(flowAddress) + } + + @Test + fun `Test getAccountBalanceAtLatestBlock failure`() { + val flowAccessApi = mock(FlowAccessApi::class.java) + val flowAddress = FlowAddress("01") + val exception = RuntimeException("Test exception") + val response = FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", exception) + + `when`(flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress)).thenReturn(response) + + val result = flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress) + + assertEquals(response, result) + verify(flowAccessApi).getAccountBalanceAtLatestBlock(flowAddress) + } + + @Test + fun `Test getAccountBalanceAtBlockHeight success`() { + val flowAccessApi = mock(FlowAccessApi::class.java) + val flowAddress = FlowAddress("01") + val blockHeight = 123L + val expectedBalance = 1000L + val response = FlowAccessApi.AccessApiCallResponse.Success(expectedBalance) + + `when`(flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight)).thenReturn(response) + + val result = flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + + assertEquals(response, result) + verify(flowAccessApi).getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + } + + @Test + fun `Test getAccountBalanceAtBlockHeight failure`() { + val flowAccessApi = mock(FlowAccessApi::class.java) + val flowAddress = FlowAddress("01") + val blockHeight = 123L + val exception = RuntimeException("Test exception") + val response = FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", exception) + + `when`(flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight)).thenReturn(response) + + val result = flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + + assertEquals(response, result) + verify(flowAccessApi).getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + } + @Test fun `Test getCollectionById`() { val flowAccessApi = mock(FlowAccessApi::class.java) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index a0c98d0..24c4b0c 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -205,6 +205,70 @@ class AsyncFlowAccessApiImplTest { assertEquals(mockBlock, result.data) } + @Test + fun `test getAccountBalanceAtLatestBlock success`() { + val flowAddress = FlowAddress("01") + val expectedBalance = 1000L + val balanceResponse = Access.AccountBalanceResponse + .newBuilder() + .setBalance(expectedBalance) + .build() + + `when`(api.getAccountBalanceAtLatestBlock(any())).thenReturn(setupFutureMock(balanceResponse)) + + val result = asyncFlowAccessApi.getAccountBalanceAtLatestBlock(flowAddress).get() + assert(result is FlowAccessApi.AccessApiCallResponse.Success) + result as FlowAccessApi.AccessApiCallResponse.Success + assertEquals(expectedBalance, result.data) + } + + @Test + fun `test getAccountBalanceAtLatestBlock failure`() { + val flowAddress = FlowAddress("01") + val exception = RuntimeException("Test exception") + + `when`(api.getAccountBalanceAtLatestBlock(any())).thenThrow(exception) + + val result = asyncFlowAccessApi.getAccountBalanceAtLatestBlock(flowAddress).get() + assert(result is FlowAccessApi.AccessApiCallResponse.Error) + result as FlowAccessApi.AccessApiCallResponse.Error + assertEquals("Failed to get account balance at latest block", result.message) + assertEquals(exception, result.throwable) + } + + @Test + fun `test getAccountBalanceAtBlockHeight success`() { + val flowAddress = FlowAddress("01") + val blockHeight = 123L + val expectedBalance = 1000L + val balanceResponse = Access.AccountBalanceResponse + .newBuilder() + .setBalance(expectedBalance) + .build() + + `when`(api.getAccountBalanceAtBlockHeight(any())).thenReturn(setupFutureMock(balanceResponse)) + + val result = asyncFlowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight).get() + assert(result is FlowAccessApi.AccessApiCallResponse.Success) + result as FlowAccessApi.AccessApiCallResponse.Success + assertEquals(expectedBalance, result.data) + } + + @Test + fun `test getAccountBalanceAtBlockHeight failure`() { + val flowAddress = FlowAddress("01") + val blockHeight = 123L + val exception = RuntimeException("Test exception") + + `when`(api.getAccountBalanceAtBlockHeight(any())).thenThrow(exception) + + val result = asyncFlowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight).get() + assert(result is FlowAccessApi.AccessApiCallResponse.Error) + result as FlowAccessApi.AccessApiCallResponse.Error + assertEquals("Failed to get account balance at block height", result.message) + assertEquals(exception, result.throwable) + } + @Test fun `test getCollectionById`() { val collectionId = FlowId("01") diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt index 1a0afc6..743e165 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt @@ -163,6 +163,81 @@ class FlowAccessApiImplTest { assertResultSuccess(result) { assertEquals(mockBlock, it) } } + @Test + fun `Test getAccountBalanceAtLatestBlock success`() { + val flowAddress = FlowAddress("01") + val expectedBalance = 1000L + val response = Access.AccountBalanceResponse + .newBuilder() + .setBalance(expectedBalance) + .build() + + `when`(mockApi.getAccountBalanceAtLatestBlock(any())).thenReturn(response) + + val result = flowAccessApiImpl.getAccountBalanceAtLatestBlock(flowAddress) + assertResultSuccess(result) { assertEquals(expectedBalance, it) } + + verify(mockApi).getAccountBalanceAtLatestBlock( + Access.GetAccountBalanceAtLatestBlockRequest + .newBuilder() + .setAddress(flowAddress.byteStringValue) + .build() + ) + } + + @Test + fun `Test getAccountBalanceAtLatestBlock failure`() { + val flowAddress = FlowAddress("01") + val exception = RuntimeException("Test exception") + + `when`(mockApi.getAccountBalanceAtLatestBlock(any())).thenThrow(exception) + + val result = flowAccessApiImpl.getAccountBalanceAtLatestBlock(flowAddress) + + assertTrue(result is FlowAccessApi.AccessApiCallResponse.Error) + assertEquals("Failed to get account balance at latest block", (result as FlowAccessApi.AccessApiCallResponse.Error).message) + assertEquals(exception, result.throwable) + } + + @Test + fun `Test getAccountBalanceAtBlockHeight success`() { + val flowAddress = FlowAddress("01") + val blockHeight = 123L + val expectedBalance = 1000L + val response = Access.AccountBalanceResponse + .newBuilder() + .setBalance(expectedBalance) + .build() + + `when`(mockApi.getAccountBalanceAtBlockHeight(any())).thenReturn(response) + + val result = flowAccessApiImpl.getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + assertResultSuccess(result) { assertEquals(expectedBalance, it) } + + verify(mockApi).getAccountBalanceAtBlockHeight( + Access.GetAccountBalanceAtBlockHeightRequest + .newBuilder() + .setAddress(flowAddress.byteStringValue) + .setBlockHeight(blockHeight) + .build() + ) + } + + @Test + fun `Test getAccountBalanceAtBlockHeight failure`() { + val flowAddress = FlowAddress("01") + val blockHeight = 123L + val exception = RuntimeException("Test exception") + + `when`(mockApi.getAccountBalanceAtBlockHeight(any())).thenThrow(exception) + + val result = flowAccessApiImpl.getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + + assertTrue(result is FlowAccessApi.AccessApiCallResponse.Error) + assertEquals("Failed to get account balance at block height", (result as FlowAccessApi.AccessApiCallResponse.Error).message) + assertEquals(exception, result.throwable) + } + @Test fun `Test getCollectionById`() { val collectionId = FlowId("01") From 26f6a897acb484080fafdf238460063715c60071 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Wed, 23 Oct 2024 02:10:57 +0900 Subject: [PATCH 4/6] Update integration tests --- .../GetAccountBalanceAccessAPIConnector.kt | 21 ++++++ .../transaction/TransactionIntegrationTest.kt | 70 +++++++++++++++++++ .../org/onflow/flow/sdk/AsyncFlowAccessApi.kt | 4 +- 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt diff --git a/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt new file mode 100644 index 0000000..255f3d4 --- /dev/null +++ b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt @@ -0,0 +1,21 @@ +package org.onflow.examples.kotlin.getAccountBalance + +import org.onflow.flow.sdk.* + +internal class GetBalanceAccessAPIConnector( + private val accessAPI: FlowAccessApi +) { + fun getBalanceAtLatestBlock(address: FlowAddress): Long { + return when (val response = accessAPI.getAccountBalanceAtLatestBlock(address)) { + is FlowAccessApi.AccessApiCallResponse.Success -> response.data + is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) + } + } + + fun getBalanceAtBlockHeight(address: FlowAddress, height: Long): Long { + return when (val response = accessAPI.getAccountBalanceAtBlockHeight(address, height)) { + is FlowAccessApi.AccessApiCallResponse.Success -> response.data + is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) + } + } +} diff --git a/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt b/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt index 9471bc6..79f96c6 100644 --- a/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt +++ b/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt @@ -141,6 +141,76 @@ class TransactionIntegrationTest { assertThat(blockHeader.height).isEqualTo(latestBlock.height) } + @Test + fun `Can get account balance at latest block`() { + val address = serviceAccount.flowAddress + + val balanceResponse = try { + handleResult( + accessAPI.getAccountBalanceAtLatestBlock(address), + "Failed to get account balance at latest block" + ) + } catch (e: Exception) { + fail("Failed to retrieve account balance at latest block: ${e.message}") + } + + assertThat(balanceResponse).isNotNull + + val account = try { + handleResult( + accessAPI.getAccountAtLatestBlock(address), + "Failed to get account at latest block" + ) + } catch (e: Exception) { + fail("Failed to retrieve account at latest block: ${e.message}") + } + + val normalizedBalance = balanceResponse / 100_000_000L + + assertThat(normalizedBalance).isEqualTo(account.balance.toBigInteger().longValueExact()) + } + + @Test + fun `Can get account balance at block height`() { + val address = serviceAccount.flowAddress + + val latestBlock = try { + handleResult( + accessAPI.getLatestBlock(true), + "Failed to get latest block" + ) + } catch (e: Exception) { + fail("Failed to retrieve latest block: ${e.message}") + } + + val height = latestBlock.height + + val balanceResponse = try { + handleResult( + accessAPI.getAccountBalanceAtBlockHeight(address, height), + "Failed to get account balance at block height" + ) + } catch (e: Exception) { + fail("Failed to retrieve account balance at block height: ${e.message}") + } + + assertThat(balanceResponse).isNotNull + + val account = try { + handleResult( + accessAPI.getAccountByBlockHeight(address, height), + "Failed to get account by block height" + ) + } catch (e: Exception) { + fail("Failed to retrieve account by block height: ${e.message}") + } + + val normalizedBalance = balanceResponse / 100_000_000L + + assertThat(normalizedBalance).isEqualTo(account.balance.toBigInteger().longValueExact()) + } + + @Test fun `Can get latest block`() { val latestBlock = try { diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt index ebe72a6..edf2214 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt @@ -14,9 +14,9 @@ interface AsyncFlowAccessApi { fun getLatestBlock(sealed: Boolean = true): CompletableFuture> - fun getAccountBalanceAtLatestBlock(address: FlowAddress): CompletableFuture> + fun getAccountBalanceAtLatestBlock(address: FlowAddress): CompletableFuture> - fun getAccountBalanceAtBlockHeight(address: FlowAddress, height: Long): CompletableFuture> + fun getAccountBalanceAtBlockHeight(address: FlowAddress, height: Long): CompletableFuture> fun getBlockById(id: FlowId): CompletableFuture> From 90ce567ee650b955d08ea84516bf00f59870ef4c Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Wed, 23 Oct 2024 02:17:05 +0900 Subject: [PATCH 5/6] Setup kotlin examples --- .../GetAccountBalanceAccessAPIConnector.kt | 12 ++- ...GetAccountBalanceAccessAPIConnectorTest.kt | 73 +++++++++++++++++++ 2 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt diff --git a/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt index 255f3d4..89ce67c 100644 --- a/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt +++ b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnector.kt @@ -2,20 +2,18 @@ package org.onflow.examples.kotlin.getAccountBalance import org.onflow.flow.sdk.* -internal class GetBalanceAccessAPIConnector( +internal class GetAccountBalanceAccessAPIConnector( private val accessAPI: FlowAccessApi ) { - fun getBalanceAtLatestBlock(address: FlowAddress): Long { - return when (val response = accessAPI.getAccountBalanceAtLatestBlock(address)) { + fun getBalanceAtLatestBlock(address: FlowAddress): Long = + when (val response = accessAPI.getAccountBalanceAtLatestBlock(address)) { is FlowAccessApi.AccessApiCallResponse.Success -> response.data is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) } - } - fun getBalanceAtBlockHeight(address: FlowAddress, height: Long): Long { - return when (val response = accessAPI.getAccountBalanceAtBlockHeight(address, height)) { + fun getBalanceAtBlockHeight(address: FlowAddress, height: Long): Long = + when (val response = accessAPI.getAccountBalanceAtBlockHeight(address, height)) { is FlowAccessApi.AccessApiCallResponse.Success -> response.data is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) } - } } diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt new file mode 100644 index 0000000..923f07b --- /dev/null +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt @@ -0,0 +1,73 @@ +package org.onflow.examples.kotlin.getAccountBalance + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.onflow.flow.common.test.FlowEmulatorProjectTest +import org.onflow.flow.common.test.FlowServiceAccountCredentials +import org.onflow.flow.common.test.FlowTestClient +import org.onflow.flow.common.test.TestAccount +import org.onflow.flow.sdk.FlowAccessApi + +@FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json") +internal class GetAccountBalanceAccessAPIConnectorTest { + @FlowServiceAccountCredentials + lateinit var serviceAccount: TestAccount + + @FlowTestClient + lateinit var accessAPI: FlowAccessApi + + private lateinit var balanceAPIConnector: GetAccountBalanceAccessAPIConnector + + @BeforeEach + fun setup() { + balanceAPIConnector = GetAccountBalanceAccessAPIConnector(accessAPI) + } + + @Test + fun `Can fetch account balance at the latest block`() { + val address = serviceAccount.flowAddress + val balance = balanceAPIConnector.getBalanceAtLatestBlock(address) + + Assertions.assertNotNull(balance, "Balance should not be null") + Assertions.assertTrue(balance >= 0, "Balance should be non-negative") + } + + @Test + fun `Can fetch account balance at a specific block height`() { + val address = serviceAccount.flowAddress + val latestBlock = accessAPI.getLatestBlock(true) // Fetch the latest sealed block + + when (latestBlock) { + is FlowAccessApi.AccessApiCallResponse.Success -> { + val balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, latestBlock.data.height) + + Assertions.assertNotNull(balanceAtHeight, "Balance at specific block height should not be null") + Assertions.assertTrue(balanceAtHeight >= 0, "Balance at specific block height should be non-negative") + } + is FlowAccessApi.AccessApiCallResponse.Error -> Assertions.fail("Failed to retrieve the latest block: ${latestBlock.message}") + } + } + + @Test + fun `Balances at the latest block and specific block height should match`() { + val address = serviceAccount.flowAddress + + // Fetch balance at latest block + val balanceAtLatest = balanceAPIConnector.getBalanceAtLatestBlock(address) + + // Fetch latest block height + val latestBlock = accessAPI.getLatestBlock(true) + when (latestBlock) { + is FlowAccessApi.AccessApiCallResponse.Success -> { + val blockHeight = latestBlock.data.height + + // Fetch balance at the same block height + val balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, blockHeight) + + Assertions.assertEquals(balanceAtLatest, balanceAtHeight, "Balance at latest block and specific block height should match") + } + is FlowAccessApi.AccessApiCallResponse.Error -> Assertions.fail("Failed to retrieve the latest block: ${latestBlock.message}") + } + } +} From 397339e4367b28ac2ab1f0580369aba62a89bf21 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Wed, 23 Oct 2024 17:34:14 +0900 Subject: [PATCH 6/6] Setup java examples --- .../GetAccountBalanceAccessAPIConnector.java | 34 ++++++++ ...tAccountBalanceAccessAPIConnectorTest.java | 77 +++++++++++++++++++ .../transaction/TransactionIntegrationTest.kt | 1 - 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 java-example/src/main/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnector.java create mode 100644 java-example/src/test/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.java diff --git a/java-example/src/main/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnector.java b/java-example/src/main/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnector.java new file mode 100644 index 0000000..cee6b61 --- /dev/null +++ b/java-example/src/main/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnector.java @@ -0,0 +1,34 @@ +package org.onflow.examples.java.getAccountBalance; + +import org.onflow.flow.sdk.FlowAccessApi; +import org.onflow.flow.sdk.FlowAddress; + +public class GetAccountBalanceAccessAPIConnector { + private final FlowAccessApi accessAPI; + + public GetAccountBalanceAccessAPIConnector(FlowAccessApi accessAPI) { + this.accessAPI = accessAPI; + } + + public long getBalanceAtLatestBlock(FlowAddress address) { + FlowAccessApi.AccessApiCallResponse response = accessAPI.getAccountBalanceAtLatestBlock(address); + + if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) { + return ((FlowAccessApi.AccessApiCallResponse.Success) response).getData(); + } else { + FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response; + throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable()); + } + } + + public long getBalanceAtBlockHeight(FlowAddress address, long height) { + FlowAccessApi.AccessApiCallResponse response = accessAPI.getAccountBalanceAtBlockHeight(address, height); + + if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) { + return ((FlowAccessApi.AccessApiCallResponse.Success) response).getData(); + } else { + FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response; + throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable()); + } + } +} diff --git a/java-example/src/test/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.java b/java-example/src/test/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.java new file mode 100644 index 0000000..6b0eb15 --- /dev/null +++ b/java-example/src/test/java/org/onflow/examples/java/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.java @@ -0,0 +1,77 @@ +package org.onflow.examples.java.getAccountBalance; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onflow.flow.common.test.FlowEmulatorProjectTest; +import org.onflow.flow.common.test.FlowServiceAccountCredentials; +import org.onflow.flow.common.test.FlowTestClient; +import org.onflow.flow.common.test.TestAccount; +import org.onflow.flow.sdk.FlowAccessApi; +import org.onflow.flow.sdk.FlowAddress; +import org.onflow.flow.sdk.FlowBlock; + +@FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json") +public class GetAccountBalanceAccessAPIConnectorTest { + + @FlowTestClient + private FlowAccessApi accessAPI; + + @FlowServiceAccountCredentials + private TestAccount serviceAccount; + + private GetAccountBalanceAccessAPIConnector balanceAPIConnector; + + @BeforeEach + public void setup() { + balanceAPIConnector = new GetAccountBalanceAccessAPIConnector(accessAPI); + } + + @Test + public void testCanFetchBalanceAtLatestBlock() { + FlowAddress address = serviceAccount.getFlowAddress(); + long balance = balanceAPIConnector.getBalanceAtLatestBlock(address); + + Assertions.assertTrue(balance >= 0, "Balance at the latest block should be non-negative"); + } + + @Test + public void testCanFetchBalanceAtSpecificBlockHeight() { + FlowAddress address = serviceAccount.getFlowAddress(); + + FlowAccessApi.AccessApiCallResponse latestBlockResponse = accessAPI.getLatestBlock(true); + + if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Success) { + FlowBlock latestBlock = ((FlowAccessApi.AccessApiCallResponse.Success) latestBlockResponse).getData(); + long blockHeight = latestBlock.getHeight(); + long balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, blockHeight); + + Assertions.assertTrue(balanceAtHeight >= 0, "Balance at specific block height should be non-negative"); + } else { + FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) latestBlockResponse; + Assertions.fail("Failed to fetch the latest block: " + errorResponse.getMessage()); + } + } + + @Test + public void testBalancesAtLatestBlockAndSpecificHeightShouldMatch() { + FlowAddress address = serviceAccount.getFlowAddress(); + + long balanceAtLatest = balanceAPIConnector.getBalanceAtLatestBlock(address); + FlowAccessApi.AccessApiCallResponse latestBlockResponse = accessAPI.getLatestBlock(true); + + if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Success) { + FlowBlock latestBlock = ((FlowAccessApi.AccessApiCallResponse.Success) latestBlockResponse).getData(); + long blockHeight = latestBlock.getHeight(); + + // Fetch balance at the same block height + long balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, blockHeight); + + // Ensure balances match + Assertions.assertEquals(balanceAtLatest, balanceAtHeight, "Balance at latest block and specific block height should match"); + } else { + FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) latestBlockResponse; + Assertions.fail("Failed to fetch the latest block: " + errorResponse.getMessage()); + } + } +} diff --git a/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt b/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt index 79f96c6..ab5a504 100644 --- a/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt +++ b/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt @@ -210,7 +210,6 @@ class TransactionIntegrationTest { assertThat(normalizedBalance).isEqualTo(account.balance.toBigInteger().longValueExact()) } - @Test fun `Can get latest block`() { val latestBlock = try {