Skip to content

Commit 8c78a4f

Browse files
committed
Merge branch 'main' of github.com:gemwalletcom/wallet into 139-monad-claim-reward-issue
2 parents 24eac56 + 50c2ba7 commit 8c78a4f

50 files changed

Lines changed: 813 additions & 468 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

android/blockchain/src/main/kotlin/com/gemwallet/android/blockchain/services/BalancesService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class BalancesService(
3939
}
4040
}
4141

42-
suspend fun getDelegationBalances(account: Account): AssetBalance? {
42+
suspend fun getStakeBalances(account: Account): AssetBalance? {
4343
return try {
4444
val result = gateway.getBalanceStaking(account.chain.string, account.address)
4545
?: return null

android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/asset_select/GetRecentAssetsImpl.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ package com.gemwallet.android.data.coordinators.asset_select
22

33
import com.gemwallet.android.application.asset_select.coordinators.GetRecentAssets
44
import com.gemwallet.android.data.repositories.assets.AssetsRepository
5-
import com.gemwallet.android.model.AssetInfo
6-
import com.gemwallet.android.model.RecentType
5+
import com.gemwallet.android.model.RecentAssetsRequest
6+
import com.wallet.core.primitives.Asset
77
import kotlinx.coroutines.flow.Flow
88

99
class GetRecentAssetsImpl(
1010
private val assetsRepository: AssetsRepository,
1111
) : GetRecentAssets {
12-
override fun invoke(types: List<RecentType>): Flow<List<AssetInfo>> =
13-
assetsRepository.getRecentActivities(types)
12+
override fun invoke(request: RecentAssetsRequest): Flow<List<Asset>> =
13+
assetsRepository.getRecentAssets(request)
1414
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.gemwallet.android.data.coordinators.asset_select
2+
3+
import com.gemwallet.android.application.asset_select.coordinators.UpdateRecentAsset
4+
import com.gemwallet.android.data.repositories.assets.AssetsRepository
5+
import com.gemwallet.android.model.RecentType
6+
import com.wallet.core.primitives.AssetId
7+
8+
class UpdateRecentAssetImpl(
9+
private val assetsRepository: AssetsRepository,
10+
) : UpdateRecentAsset {
11+
override suspend fun invoke(assetId: AssetId, walletId: String, type: RecentType) =
12+
assetsRepository.addRecentActivity(assetId, walletId, type)
13+
}

android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/AssetSelectModule.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import com.gemwallet.android.application.asset_select.coordinators.GetSelectAsse
55
import com.gemwallet.android.application.asset_select.coordinators.SearchSelectAssets
66
import com.gemwallet.android.application.asset_select.coordinators.SwitchAssetVisibility
77
import com.gemwallet.android.application.asset_select.coordinators.ToggleAssetPin
8+
import com.gemwallet.android.application.asset_select.coordinators.UpdateRecentAsset
89
import com.gemwallet.android.data.coordinators.asset_select.GetRecentAssetsImpl
910
import com.gemwallet.android.data.coordinators.asset_select.GetSelectAssetsInfoImpl
1011
import com.gemwallet.android.data.coordinators.asset_select.SearchSelectAssetsImpl
1112
import com.gemwallet.android.data.coordinators.asset_select.SwitchAssetVisibilityImpl
1213
import com.gemwallet.android.data.coordinators.asset_select.ToggleAssetPinImpl
14+
import com.gemwallet.android.data.coordinators.asset_select.UpdateRecentAssetImpl
1315
import com.gemwallet.android.data.repositories.assets.AssetsRepository
1416
import dagger.Module
1517
import dagger.Provides
@@ -50,4 +52,10 @@ object AssetSelectModule {
5052
fun provideToggleAssetPin(
5153
assetsRepository: AssetsRepository,
5254
): ToggleAssetPin = ToggleAssetPinImpl(assetsRepository)
55+
56+
@Provides
57+
@Singleton
58+
fun provideUpdateRecentAsset(
59+
assetsRepository: AssetsRepository,
60+
): UpdateRecentAsset = UpdateRecentAssetImpl(assetsRepository)
5361
}

android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/FiatModule.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.gemwallet.android.data.coordinators.di
33
import android.content.Context
44
import com.gemwallet.android.application.assets.coordinators.PrefetchAssets
55
import com.gemwallet.android.application.config.coordinators.GetRemoteConfig
6-
import com.gemwallet.android.application.fiat.coordinators.AddBuyRecent
76
import com.gemwallet.android.application.fiat.coordinators.GetBuyAssetInfo
87
import com.gemwallet.android.application.fiat.coordinators.GetBuyQuoteUrl
98
import com.gemwallet.android.application.fiat.coordinators.GetBuyQuotes
@@ -13,7 +12,6 @@ import com.gemwallet.android.application.fiat.coordinators.GetSellableFiatAssets
1312
import com.gemwallet.android.application.fiat.coordinators.ObserveFiatTransactions
1413
import com.gemwallet.android.application.fiat.coordinators.SyncFiatAssets
1514
import com.gemwallet.android.application.fiat.coordinators.SyncFiatTransactions
16-
import com.gemwallet.android.data.coordinators.fiat.AddBuyRecentImpl
1715
import com.gemwallet.android.data.coordinators.fiat.GetBuyAssetInfoImpl
1816
import com.gemwallet.android.data.coordinators.fiat.GetBuyQuoteUrlImpl
1917
import com.gemwallet.android.data.coordinators.fiat.GetBuyQuotesImpl
@@ -157,11 +155,4 @@ object FiatModule {
157155
return GetBuyQuoteUrlImpl(gemDeviceApiClient)
158156
}
159157

160-
@Provides
161-
@Singleton
162-
fun provideAddBuyRecent(
163-
assetsRepository: AssetsRepository,
164-
): AddBuyRecent {
165-
return AddBuyRecentImpl(assetsRepository)
166-
}
167158
}

android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/fiat/AddBuyRecentImpl.kt

Lines changed: 0 additions & 15 deletions
This file was deleted.

android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/receive/GetReceiveAssetInfoImpl.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import kotlinx.coroutines.flow.Flow
1212
import kotlinx.coroutines.flow.filterNotNull
1313
import kotlinx.coroutines.flow.flatMapLatest
1414
import kotlinx.coroutines.flow.map
15-
import kotlinx.coroutines.flow.onEach
1615

1716
@OptIn(ExperimentalCoroutinesApi::class)
1817
class GetReceiveAssetInfoImpl(
@@ -23,9 +22,6 @@ class GetReceiveAssetInfoImpl(
2322
override fun invoke(assetId: AssetId): Flow<AssetInfo?> {
2423
return sessionRepository.session()
2524
.filterNotNull()
26-
.onEach { session ->
27-
assetsRepository.addRecentReceive(assetId, session.wallet.id)
28-
}
2925
.flatMapLatest { session ->
3026
assetsRepository.getTokenInfo(assetId).map { info ->
3127
if (info?.owner == null) {

android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/assets/AssetsRepository.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import com.gemwallet.android.ext.toIdentifier
3737
import com.gemwallet.android.model.AssetBalance
3838
import com.gemwallet.android.model.AssetInfo
3939
import com.gemwallet.android.model.AssetPriceInfo
40+
import com.gemwallet.android.model.RecentAssetsRequest
4041
import com.gemwallet.android.model.RecentType
4142
import com.gemwallet.android.model.TransactionExtended
4243
import com.wallet.core.primitives.Account
@@ -567,9 +568,8 @@ class AssetsRepository @Inject constructor(
567568
)
568569
}
569570

570-
override fun getRecentActivities(
571-
type: List<RecentType>
572-
): Flow<List<AssetInfo>> {
573-
return assetsDao.getRecentByType(type).toAssetInfoModel()
571+
override fun getRecentAssets(request: RecentAssetsRequest): Flow<List<Asset>> {
572+
return assetsDao.getRecentAssets(request.types, request.filters)
573+
.map { items -> items.mapNotNull { it.toDTO() } }
574574
}
575575
}

android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/assets/UpdateBalances.kt

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ package com.gemwallet.android.data.repositories.assets
33
import com.gemwallet.android.blockchain.services.BalancesService
44
import com.gemwallet.android.data.service.store.database.BalancesDao
55
import com.gemwallet.android.data.service.store.database.entities.DbBalance
6-
import com.gemwallet.android.data.service.store.database.entities.mergeDelegation
7-
import com.gemwallet.android.data.service.store.database.entities.mergeNative
86
import com.gemwallet.android.data.service.store.database.entities.toDTO
9-
import com.gemwallet.android.data.service.store.database.entities.toRecord
7+
import com.gemwallet.android.ext.toIdentifier
108
import com.gemwallet.android.model.AssetBalance
119
import com.wallet.core.primitives.Account
1210
import com.wallet.core.primitives.Asset
@@ -22,52 +20,106 @@ class UpdateBalances(
2220
suspend fun updateBalances(
2321
walletId: String,
2422
account: Account,
25-
tokens: List<Asset>
23+
tokens: List<Asset>,
2624
): List<AssetBalance> = withContext(Dispatchers.IO) {
2725
val updatedAt = System.currentTimeMillis()
2826

29-
val getNative = async { updateNativeBalance(walletId, account, updatedAt) }
30-
31-
val getDelegation = async { balancesService.getDelegationBalances(account) }
32-
27+
val getNative = async { balancesService.getNativeBalances(account) }
28+
val getStake = async { balancesService.getStakeBalances(account) }
3329
val getTokens = async { updateTokensBalance(walletId, account, tokens, updatedAt) }
3430

3531
val native = getNative.await()
36-
val delegation = getDelegation.await()
37-
val fullNative = mergeNativeBalances(native, delegation?.toRecord(walletId, account.address, updatedAt))
32+
val stake = getStake.await()
33+
val tokenResults = getTokens.await()
3834

39-
val tokens = getTokens.await()
35+
val nativeResult = updateNativeBalance(walletId, account, updatedAt, native, stake)
4036

41-
listOfNotNull(fullNative) + tokens
37+
listOfNotNull(nativeResult) + tokenResults
4238
}
4339

44-
private suspend fun updateNativeBalance(walletId: String, account: Account, updatedAt: Long): DbBalance? {
45-
val prevBalance =
46-
balancesDao.getByAccount(walletId, account.address, account.chain.string)
47-
val nativeBalance = balancesService.getNativeBalances(account)
48-
val dbNativeBalance = DbBalance.mergeNative(
49-
prevBalance,
50-
nativeBalance?.toRecord(walletId, account.address, updatedAt),
51-
)
52-
dbNativeBalance?.let { runCatching { balancesDao.insert(it) } }
53-
return dbNativeBalance
40+
private fun updateNativeBalance(
41+
walletId: String,
42+
account: Account,
43+
updatedAt: Long,
44+
native: AssetBalance?,
45+
stake: AssetBalance?,
46+
): AssetBalance? {
47+
val assetId = account.chain.string
48+
49+
if (native == null && stake == null) {
50+
return balancesDao.getByAccount(walletId, account.address, assetId)?.toDTO()
51+
}
52+
53+
ensureRowExists(walletId, account.address, assetId, updatedAt)
54+
55+
native?.let {
56+
balancesDao.updateCoinBalance(
57+
walletId = walletId,
58+
address = account.address,
59+
assetId = assetId,
60+
available = it.balance.available,
61+
availableAmount = it.balanceAmount.available,
62+
reserved = it.balance.reserved,
63+
reservedAmount = it.balanceAmount.reserved,
64+
isActive = it.isActive,
65+
updatedAt = updatedAt,
66+
)
67+
}
68+
69+
stake?.let {
70+
balancesDao.updateStakeBalance(
71+
walletId = walletId,
72+
address = account.address,
73+
assetId = assetId,
74+
staked = it.balance.staked,
75+
stakedAmount = it.balanceAmount.staked,
76+
frozen = it.balance.frozen,
77+
frozenAmount = it.balanceAmount.frozen,
78+
locked = it.balance.locked,
79+
lockedAmount = it.balanceAmount.locked,
80+
pending = it.balance.pending,
81+
pendingAmount = it.balanceAmount.pending,
82+
rewards = it.balance.rewards,
83+
rewardsAmount = it.balanceAmount.rewards,
84+
votes = it.metadata?.votes?.toLong() ?: 0L,
85+
energyAvailable = it.metadata?.energyAvailable?.toLong() ?: 0L,
86+
energyTotal = it.metadata?.energyTotal?.toLong() ?: 0L,
87+
bandwidthAvailable = it.metadata?.bandwidthAvailable?.toLong() ?: 0L,
88+
bandwidthTotal = it.metadata?.bandwidthTotal?.toLong() ?: 0L,
89+
updatedAt = updatedAt,
90+
)
91+
}
92+
93+
return balancesDao.getByAccount(walletId, account.address, assetId)?.toDTO()
5494
}
5595

56-
private suspend fun updateTokensBalance(walletId: String, account: Account, tokens: List<Asset>, updatedAt: Long): List<AssetBalance> {
96+
private suspend fun updateTokensBalance(
97+
walletId: String,
98+
account: Account,
99+
tokens: List<Asset>,
100+
updatedAt: Long,
101+
): List<AssetBalance> {
57102
if (tokens.none { it.id.tokenId != null }) return emptyList()
58103
val balances = balancesService.getTokensBalances(account, tokens)
59-
runCatching {
60-
val record = balances.map {
61-
it.toRecord(walletId, account.address, updatedAt)
62-
}
63-
balancesDao.insert(record)
104+
for (balance in balances) {
105+
val assetId = balance.asset.id.toIdentifier()
106+
ensureRowExists(walletId, account.address, assetId, updatedAt)
107+
balancesDao.updateTokenBalance(
108+
walletId = walletId,
109+
address = account.address,
110+
assetId = assetId,
111+
available = balance.balance.available,
112+
availableAmount = balance.balanceAmount.available,
113+
isActive = balance.isActive,
114+
updatedAt = updatedAt,
115+
)
64116
}
65117
return balances
66118
}
67119

68-
private suspend fun mergeNativeBalances(native: DbBalance?, delegation: DbBalance?): AssetBalance? = withContext(Dispatchers.IO) {
69-
val dbFullBalance = DbBalance.mergeDelegation(native, delegation)
70-
dbFullBalance?.let { runCatching { balancesDao.insert(it) } }
71-
dbFullBalance?.toDTO()
120+
private fun ensureRowExists(walletId: String, address: String, assetId: String, updatedAt: Long) {
121+
balancesDao.insertIgnore(
122+
DbBalance(assetId = assetId, walletId = walletId, accountAddress = address, updatedAt = updatedAt)
123+
)
72124
}
73-
}
125+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.gemwallet.android.data.repositories.assets
2+
3+
import com.gemwallet.android.blockchain.services.BalancesService
4+
import com.gemwallet.android.data.service.store.database.BalancesDao
5+
import com.gemwallet.android.data.service.store.database.entities.DbBalance
6+
import com.gemwallet.android.ext.asset
7+
import com.gemwallet.android.testkit.mockAccount
8+
import com.gemwallet.android.testkit.mockAssetEthereum
9+
import com.wallet.core.primitives.Chain
10+
import io.mockk.coEvery
11+
import io.mockk.every
12+
import io.mockk.mockk
13+
import io.mockk.mockkStatic
14+
import io.mockk.unmockkAll
15+
import io.mockk.verify
16+
import kotlinx.coroutines.test.runTest
17+
import org.junit.After
18+
import org.junit.Assert.assertEquals
19+
import org.junit.Assert.assertTrue
20+
import org.junit.Test
21+
22+
class UpdateBalancesTest {
23+
24+
private val balancesDao = mockk<BalancesDao>(relaxed = true)
25+
private val balancesService = mockk<BalancesService>(relaxed = true)
26+
27+
private val subject = UpdateBalances(
28+
balancesDao = balancesDao,
29+
balancesService = balancesService,
30+
)
31+
32+
@After
33+
fun tearDown() {
34+
unmockkAll()
35+
}
36+
37+
@Test
38+
fun `failed native refresh does not create empty balance row`() = runTest {
39+
val walletId = "wallet-1"
40+
val account = mockAccount(chain = Chain.Ethereum)
41+
42+
every { balancesDao.getByAccount(walletId, account.address, account.chain.string) } returns null
43+
coEvery { balancesService.getNativeBalances(account) } returns null
44+
coEvery { balancesService.getStakeBalances(account) } returns null
45+
46+
val result = subject.updateBalances(walletId, account, emptyList())
47+
48+
assertTrue(result.isEmpty())
49+
verify(exactly = 0) { balancesDao.insertIgnore(any()) }
50+
verify(exactly = 0) {
51+
balancesDao.updateCoinBalance(any(), any(), any(), any(), any(), any(), any(), any(), any())
52+
}
53+
}
54+
55+
@Test
56+
fun `failed native refresh keeps previous balance row`() = runTest {
57+
val walletId = "wallet-1"
58+
val account = mockAccount(chain = Chain.Ethereum)
59+
val existing = DbBalance(
60+
assetId = account.chain.string,
61+
walletId = walletId,
62+
accountAddress = account.address,
63+
available = "1000000000000000000",
64+
availableAmount = 1.0,
65+
updatedAt = 1L,
66+
)
67+
68+
mockkStatic("com.gemwallet.android.ext.ChainKt")
69+
every { Chain.Ethereum.asset() } returns mockAssetEthereum()
70+
every { balancesDao.getByAccount(walletId, account.address, account.chain.string) } returns existing
71+
coEvery { balancesService.getNativeBalances(account) } returns null
72+
coEvery { balancesService.getStakeBalances(account) } returns null
73+
74+
val result = subject.updateBalances(walletId, account, emptyList())
75+
76+
assertEquals(1, result.size)
77+
assertEquals("1000000000000000000", result.single().balance.available)
78+
verify(exactly = 0) { balancesDao.insertIgnore(any()) }
79+
verify(exactly = 0) {
80+
balancesDao.updateCoinBalance(any(), any(), any(), any(), any(), any(), any(), any(), any())
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)