Skip to content

Commit

Permalink
Add balance refreshing
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandr7035 committed Jun 16, 2024
1 parent c6d380b commit 08e2ca7
Show file tree
Hide file tree
Showing 16 changed files with 315 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import by.alexandr7035.crypto.CryptoHelper
import by.alexandr7035.ethereum.core.EthereumClient
import by.alexandr7035.ethereum.model.Wei
import by.alexandr7035.votekt.data.cache.PrefKeys
import by.alexandr7035.votekt.domain.repository.AccountRepository
import by.alexandr7035.votekt.domain.model.account.MnemonicWord
import by.alexandr7035.votekt.domain.repository.AccountRepository
import cash.z.ecc.android.bip39.Mnemonics
import com.cioccarellia.ksprefs.KsPrefs
import kotlinx.coroutines.CoroutineDispatcher
Expand All @@ -32,21 +32,30 @@ class AccountRepositoryImpl(
}

override fun observeAccountBalance(): Flow<Wei> = flow {
while (coroutineContext.isActive) {
val recentBalance = ksPrefs.pull(PrefKeys.RECENT_BALANCE, "")
if (recentBalance.isNotBlank()) {
emit(Wei(recentBalance))
}
delay(balancePollingDelay)
}

val recentBalance = ksPrefs.pull(PrefKeys.RECENT_BALANCE, "")
if (recentBalance.isNotBlank()) {
emit(Wei(recentBalance))
}

while (coroutineContext.isActive) {
val updatedBalance = ethereumClient.getBalance(
address = Address(ksPrefs.pull(PrefKeys.ACCOUNT_ADDRESS_KEY))
)
ksPrefs.push(PrefKeys.RECENT_BALANCE, updatedBalance.value.toString())
emit(updatedBalance)
delay(balancePollingDelay)
}
}.flowOn(dispatcher)

override suspend fun refreshBalance() {
val updatedBalance = ethereumClient.getBalance(
address = Address(ksPrefs.pull(PrefKeys.ACCOUNT_ADDRESS_KEY))
)

println("refreshed balance $updatedBalance")

ksPrefs.push(PrefKeys.RECENT_BALANCE, updatedBalance.value.toString())
}

override suspend fun clearAccount() {
ksPrefs.clear()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package by.alexandr7035.votekt.data.repository

import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import by.alexandr7035.ethereum.model.EthTransactionReceipt
Expand All @@ -12,16 +10,14 @@ import by.alexandr7035.ethereum.model.transactionFee
import by.alexandr7035.votekt.data.cache.TransactionDao
import by.alexandr7035.votekt.data.cache.TransactionEntity
import by.alexandr7035.votekt.data.workers.AwaitTransactionWorker
import by.alexandr7035.votekt.data.workers.RefreshSelfBalanceWorker
import by.alexandr7035.votekt.data.workers.SyncProposalsWorker
import by.alexandr7035.votekt.domain.core.AppError
import by.alexandr7035.votekt.domain.core.ErrorType
import by.alexandr7035.votekt.domain.core.OperationResult
import by.alexandr7035.votekt.domain.model.transactions.TransactionDomain
import by.alexandr7035.votekt.domain.model.transactions.TransactionHash
import by.alexandr7035.votekt.domain.repository.TransactionRepository
import by.alexandr7035.votekt.domain.model.transactions.TransactionStatus
import by.alexandr7035.votekt.domain.model.transactions.TransactionType
import by.alexandr7035.votekt.domain.model.transactions.isContractInteraction
import by.alexandr7035.votekt.domain.repository.TransactionRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
Expand All @@ -39,11 +35,6 @@ class TransactionRepositoryImpl(
}.flowOn(dispatcher)
}

override suspend fun getTransactionStatus(transactionHash: TransactionHash): TransactionStatus? {
// TODO
return null
}

override suspend fun addNewTransaction(
transactionHash: TransactionHash,
transactionType: TransactionType,
Expand All @@ -62,12 +53,7 @@ class TransactionRepositoryImpl(
)

val checkForReceiptWork = OneTimeWorkRequestBuilder<AwaitTransactionWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(false)
.build()
)
.setConstraints(AwaitTransactionWorker.CONSTRAINTS)
.setInitialDelay(
duration = AwaitTransactionWorker.INITIAL_DELAY,
timeUnit = TimeUnit.SECONDS
Expand All @@ -85,27 +71,29 @@ class TransactionRepositoryImpl(
.build()

val postTransactionWork = OneTimeWorkRequestBuilder<SyncProposalsWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(false)
.build()
)
.setConstraints(SyncProposalsWorker.CONSTRAINTS)
.setBackoffCriteria(
backoffPolicy = BackoffPolicy.LINEAR,
backoffDelay = SyncProposalsWorker.BACKOFF_DELAY_SEC,
timeUnit = TimeUnit.SECONDS
)
.build()

val refreshSelfBalanceWork = OneTimeWorkRequestBuilder<RefreshSelfBalanceWorker>()
.setConstraints(RefreshSelfBalanceWorker.CONSTRAINTS)
.build()

if (transactionType.isContractInteraction()) {
workManager
.beginWith(checkForReceiptWork)
.then(postTransactionWork)
.then(refreshSelfBalanceWork)
.enqueue()
} else {
workManager
.enqueue(checkForReceiptWork)
.beginWith(checkForReceiptWork)
.then(refreshSelfBalanceWork)
.enqueue()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package by.alexandr7035.votekt.data.workers

import android.content.Context
import android.util.Log
import androidx.work.Constraints
import androidx.work.CoroutineWorker
import androidx.work.NetworkType
import androidx.work.WorkerParameters
import by.alexandr7035.ethereum.core.EthereumClient
import by.alexandr7035.ethereum.errors.TransactionReceiptNotFound
Expand Down Expand Up @@ -39,5 +41,10 @@ class AwaitTransactionWorker(
const val TRANSACTION_HASH = "transactionHash"
const val INITIAL_DELAY = 5L
const val BACKOFF_DELAY_SEC = 10L

val CONSTRAINTS = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(false)
.build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package by.alexandr7035.votekt.data.workers

import android.content.Context
import android.util.Log
import androidx.work.Constraints
import androidx.work.CoroutineWorker
import androidx.work.NetworkType
import androidx.work.WorkerParameters
import by.alexandr7035.votekt.domain.core.OperationResult
import by.alexandr7035.votekt.domain.repository.AccountRepository

class RefreshSelfBalanceWorker(
appContext: Context,
params: WorkerParameters,
private val accountRepository: AccountRepository
) : CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
val result = OperationResult.runWrapped {
accountRepository.refreshBalance()
}
return when (result) {
is OperationResult.Failure -> {
Log.d(TAG, "balance sync error ${result.error.message}")
Result.failure()
}

is OperationResult.Success -> {
Log.d(TAG, "balance sync success")
Result.success()
}
}
}

companion object {
val TAG = this::class.java.simpleName

val CONSTRAINTS = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(false)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package by.alexandr7035.votekt.data.workers

import android.content.Context
import android.util.Log
import androidx.work.Constraints
import androidx.work.CoroutineWorker
import androidx.work.NetworkType
import androidx.work.WorkerParameters
import by.alexandr7035.votekt.domain.repository.VotingContractRepository

Expand All @@ -24,5 +26,10 @@ class SyncProposalsWorker(
companion object {
private val TAG = SyncProposalsWorker::class.simpleName
const val BACKOFF_DELAY_SEC = 10L

val CONSTRAINTS = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(false)
.build()
}
}
42 changes: 28 additions & 14 deletions app/src/main/java/by/alexandr7035/votekt/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import by.alexandr7035.votekt.data.cache.TransactionsDatabase
import by.alexandr7035.votekt.data.repository.AccountRepositoryImpl
import by.alexandr7035.votekt.data.repository.AppLockRepositoryImpl
import by.alexandr7035.votekt.data.repository.BlockchainExplorerRepositoryImpl
import by.alexandr7035.votekt.data.repository.DemoModeRepositoryImpl
import by.alexandr7035.votekt.data.repository.MnemonicRepositoryImpl
import by.alexandr7035.votekt.data.repository.SendTransactionRepositoryImpl
import by.alexandr7035.votekt.data.repository.TransactionRepositoryImpl
Expand All @@ -20,17 +21,17 @@ import by.alexandr7035.votekt.data.security.BiometricsManagerImpl
import by.alexandr7035.votekt.data.websockets.WebsocketActivityCallbacks
import by.alexandr7035.votekt.data.websockets.WebsocketManagerImpl
import by.alexandr7035.votekt.data.workers.AwaitTransactionWorker
import by.alexandr7035.votekt.data.workers.RefreshSelfBalanceWorker
import by.alexandr7035.votekt.data.workers.SyncProposalsWorker
import by.alexandr7035.votekt.domain.repository.AccountRepository
import by.alexandr7035.votekt.domain.repository.MnemonicRepository
import by.alexandr7035.votekt.domain.repository.AppLockRepository
import by.alexandr7035.votekt.domain.repository.BlockchainExplorerRepository
import by.alexandr7035.votekt.domain.repository.DemoModeRepository
import by.alexandr7035.votekt.data.repository.DemoModeRepositoryImpl
import by.alexandr7035.votekt.domain.repository.WebsocketManager
import by.alexandr7035.votekt.domain.repository.AppLockRepository
import by.alexandr7035.votekt.domain.repository.MnemonicRepository
import by.alexandr7035.votekt.domain.repository.SendTransactionRepository
import by.alexandr7035.votekt.domain.repository.TransactionRepository
import by.alexandr7035.votekt.domain.repository.VotingContractRepository
import by.alexandr7035.votekt.domain.repository.WebsocketManager
import by.alexandr7035.votekt.ui.core.AppViewModel
import by.alexandr7035.votekt.ui.feature.account.create.ConfirmPhraseViewModel
import by.alexandr7035.votekt.ui.feature.account.create.GeneratePhraseViewModel
Expand Down Expand Up @@ -102,17 +103,22 @@ val appModule = module {
)
}
viewModel { ProposalsViewModel(get(), get()) }
viewModel { TransactionsViewModel(
observeTransactionsUseCase = get(),
clearTransactionsUseCase = get(),
) }
viewModel {
TransactionsViewModel(
observeTransactionsUseCase = get(),
clearTransactionsUseCase = get(),
)
}
viewModel { CreateProposalViewModel(get(), get(), get(), get()) }
viewModel { WalletViewModel(
getSelfAccountUseCase = get(),
observeBalanceUseCase = get(),
contractStateUseCase = get(),
logoutUseCase = get(),
) }
viewModel {
WalletViewModel(
getSelfAccountUseCase = get(),
observeBalanceUseCase = get(),
refreshBalanceUseCase = get(),
contractStateUseCase = get(),
logoutUseCase = get(),
)
}

viewModel {
LockScreenViewModel(
Expand Down Expand Up @@ -203,6 +209,14 @@ val appModule = module {
)
}

worker {
RefreshSelfBalanceWorker(
appContext = get(),
params = get(),
accountRepository = get(),
)
}

single<MnemonicRepository> {
MnemonicRepositoryImpl()
}
Expand Down
22 changes: 12 additions & 10 deletions app/src/main/java/by/alexandr7035/votekt/di/DomainModule.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
package by.alexandr7035.votekt.di

import by.alexandr7035.votekt.domain.usecase.contract.SyncWithContractUseCase
import by.alexandr7035.votekt.domain.usecase.applock.AuthenticateWithPinUseCase
import by.alexandr7035.votekt.domain.usecase.applock.CheckAppLockUseCase
import by.alexandr7035.votekt.domain.usecase.applock.CheckAppLockedWithBiometricsUseCase
import by.alexandr7035.votekt.domain.usecase.applock.CheckIfBiometricsAvailableUseCase
import by.alexandr7035.votekt.domain.usecase.applock.DecryptPinWithBiometricsUseCase
import by.alexandr7035.votekt.domain.usecase.applock.GetBiometricDecryptionCipherUseCase
import by.alexandr7035.votekt.domain.usecase.applock.GetBiometricEncryptedPinUseCase
import by.alexandr7035.votekt.domain.usecase.applock.SetupAppLockUseCase
import by.alexandr7035.votekt.domain.usecase.applock.SetupAppLockedWithBiometricsUseCase
import by.alexandr7035.votekt.domain.usecase.account.AddAccountUseCase
import by.alexandr7035.votekt.domain.usecase.account.CheckAccountCreatedUseCase
import by.alexandr7035.votekt.domain.usecase.account.ConfirmNewAccountUseCase
Expand All @@ -18,10 +8,21 @@ import by.alexandr7035.votekt.domain.usecase.account.GetAccountConfirmationData
import by.alexandr7035.votekt.domain.usecase.account.GetSelfAccountUseCase
import by.alexandr7035.votekt.domain.usecase.account.LogoutUseCase
import by.alexandr7035.votekt.domain.usecase.account.ObserveBalanceUseCase
import by.alexandr7035.votekt.domain.usecase.account.RefreshBalanceUseCase
import by.alexandr7035.votekt.domain.usecase.account.VerifyMnemonicPhraseUseCase
import by.alexandr7035.votekt.domain.usecase.applock.AuthenticateWithPinUseCase
import by.alexandr7035.votekt.domain.usecase.applock.CheckAppLockUseCase
import by.alexandr7035.votekt.domain.usecase.applock.CheckAppLockedWithBiometricsUseCase
import by.alexandr7035.votekt.domain.usecase.applock.CheckIfBiometricsAvailableUseCase
import by.alexandr7035.votekt.domain.usecase.applock.DecryptPinWithBiometricsUseCase
import by.alexandr7035.votekt.domain.usecase.applock.GetBiometricDecryptionCipherUseCase
import by.alexandr7035.votekt.domain.usecase.applock.GetBiometricEncryptedPinUseCase
import by.alexandr7035.votekt.domain.usecase.applock.SetupAppLockUseCase
import by.alexandr7035.votekt.domain.usecase.applock.SetupAppLockedWithBiometricsUseCase
import by.alexandr7035.votekt.domain.usecase.contract.CreateDraftProposalUseCase
import by.alexandr7035.votekt.domain.usecase.contract.GetContractConfigurationUseCase
import by.alexandr7035.votekt.domain.usecase.contract.GetContractStateUseCase
import by.alexandr7035.votekt.domain.usecase.contract.SyncWithContractUseCase
import by.alexandr7035.votekt.domain.usecase.debug.GetTestMnemonicUseCase
import by.alexandr7035.votekt.domain.usecase.demo.GetDemoProposalUseCase
import by.alexandr7035.votekt.domain.usecase.demo.IsDemoModeEnabledUseCase
Expand Down Expand Up @@ -51,6 +52,7 @@ val domainModule = module {
single { LogoutUseCase(get(), get(), get(), get()) }

single { ObserveBalanceUseCase(get()) }
single { RefreshBalanceUseCase(get()) }

single { SyncWithContractUseCase(get()) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ interface AccountRepository {

fun observeAccountBalance(): Flow<Wei>

suspend fun refreshBalance()

suspend fun clearAccount()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ import by.alexandr7035.ethereum.model.Wei
import by.alexandr7035.votekt.domain.core.OperationResult
import by.alexandr7035.votekt.domain.model.transactions.TransactionDomain
import by.alexandr7035.votekt.domain.model.transactions.TransactionHash
import by.alexandr7035.votekt.domain.model.transactions.TransactionStatus
import by.alexandr7035.votekt.domain.model.transactions.TransactionType
import kotlinx.coroutines.flow.Flow

interface TransactionRepository {
fun observeTransactions(): Flow<List<TransactionDomain>>

suspend fun getTransactionStatus(transactionHash: TransactionHash): TransactionStatus?

suspend fun addNewTransaction(
transactionHash: TransactionHash,
transactionType: TransactionType,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package by.alexandr7035.votekt.domain.usecase.account

import by.alexandr7035.votekt.domain.repository.AccountRepository

class RefreshBalanceUseCase(
private val accountRepository: AccountRepository
) {
suspend fun invoke() {
accountRepository.refreshBalance()
}
}
Loading

0 comments on commit 08e2ca7

Please sign in to comment.