Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ABW-2674] Pool redemption/contribution tx preview types #745

Merged
merged 5 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ suspend fun StateApi.fetchAccountGatewayDetails(
suspend fun StateApi.fetchPools(
poolAddresses: Set<String>,
stateVersion: Long
): Map<StateEntityDetailsResponseItem, List<FungibleResourcesCollectionItem>> {
if (poolAddresses.isEmpty()) return emptyMap()
): List<PoolsResponse> {
if (poolAddresses.isEmpty()) return emptyList()

val poolDetails = mutableMapOf<String, StateEntityDetailsResponseItem>()
val poolWithResources = mutableMapOf<String, List<FungibleResourcesCollectionItem>>()
val resourceToPoolComponentAssociation = mutableMapOf<String, String>()

Expand All @@ -98,28 +99,37 @@ suspend fun StateApi.fetchPools(
stateVersion = stateVersion,
) { poolComponents ->
poolComponents.items.forEach { pool ->
poolDetails[pool.address] = pool
val metadata = pool.explicitMetadata?.toMetadata().orEmpty()
val associatedResource = metadata.poolUnit().orEmpty()
resourceToPoolComponentAssociation[associatedResource] = pool.address
poolWithResources[pool.address] = pool.fungibleResources?.items.orEmpty()
}
}

val result = mutableMapOf<StateEntityDetailsResponseItem, List<FungibleResourcesCollectionItem>>()
val result = mutableListOf<PoolsResponse>()
paginateDetails(
addresses = resourceToPoolComponentAssociation.keys, // Request details for resources
metadataKeys = ExplicitMetadataKey.forAssets,
stateVersion = stateVersion
) { resourcesDetails ->
resourcesDetails.items.forEach { resourceDetails ->
val poolAddress = resourceToPoolComponentAssociation[resourceDetails.address]
result[resourceDetails] = poolWithResources[poolAddress].orEmpty()
poolDetails[poolAddress]?.let { poolDetails ->
result.add(PoolsResponse(poolDetails, resourceDetails, poolWithResources[poolAddress].orEmpty()))
}
}
}

return result
}

data class PoolsResponse(
val poolDetails: StateEntityDetailsResponseItem,
val poolUnitDetails: StateEntityDetailsResponseItem,
val poolResourcesDetails: List<FungibleResourcesCollectionItem>
)

suspend fun StateApi.fetchValidators(
validatorsAddresses: Set<String>,
stateVersion: Long
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import com.babylon.wallet.android.data.gateway.generated.models.FungibleResourcesCollectionItem
import com.babylon.wallet.android.data.gateway.extensions.PoolsResponse
import com.babylon.wallet.android.data.gateway.extensions.toMetadata
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityDetailsResponseItem
import com.babylon.wallet.android.data.repository.cache.database.PoolResourceJoin.Companion.asPoolResourceJoin
import com.babylon.wallet.android.data.repository.cache.database.ResourceEntity.Companion.asEntity
import com.babylon.wallet.android.domain.model.resources.metadata.poolUnit

@Entity(
foreignKeys = [
Expand All @@ -25,23 +27,42 @@ import com.babylon.wallet.android.data.repository.cache.database.ResourceEntity.
data class PoolEntity(
@PrimaryKey
val address: String,
val metadata: MetadataColumn?,
@ColumnInfo("resource_address")
val resourceAddress: String
) {

companion object {
@Suppress("UnsafeCallOnNullableType")
fun Map<StateEntityDetailsResponseItem, List<FungibleResourcesCollectionItem>>.asPoolsResourcesJoin(
fun List<PoolsResponse>.asPoolsResourcesJoin(
syncInfo: SyncInfo
): Map<ResourceEntity, List<Pair<PoolResourceJoin, ResourceEntity>>> =
map { (poolResource, itemsInPool) ->
val poolResourceEntity = poolResource.asEntity(syncInfo.synced)
): List<PoolWithResourcesJoinResult> =
mapNotNull { fetchedPoolDetails ->
val poolResourceEntity = fetchedPoolDetails.poolUnitDetails.asEntity(syncInfo.synced)

val resourcesInPool = itemsInPool.map { fungibleItem ->
val resourcesInPool = fetchedPoolDetails.poolResourcesDetails.map { fungibleItem ->
fungibleItem.asPoolResourceJoin(poolAddress = poolResourceEntity.poolAddress!!, syncInfo)
}

poolResourceEntity to resourcesInPool
}.toMap()
val poolEntity = fetchedPoolDetails.poolDetails.asPoolEntity()
poolEntity?.let {
PoolWithResourcesJoinResult(poolEntity, poolResourceEntity, resourcesInPool)
}
}
}
}

fun StateEntityDetailsResponseItem.asPoolEntity(): PoolEntity? {
val metadata = this.metadata.toMetadata()
val poolUnitResourceAddress = metadata.poolUnit() ?: return null
return PoolEntity(
address = address,
metadata = MetadataColumn(metadata),
resourceAddress = poolUnitResourceAddress
)
}

data class PoolWithResourcesJoinResult(
val pool: PoolEntity,
val poolUnitResource: ResourceEntity,
val resources: List<Pair<PoolResourceJoin, ResourceEntity>>
)
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,14 @@ interface StateDao {

@Suppress("UnsafeCallOnNullableType")
@Transaction
fun updatePools(pools: Map<ResourceEntity, List<Pair<PoolResourceJoin, ResourceEntity>>>) {
val poolEntities = pools.keys.map {
PoolEntity(
address = it.poolAddress!!,
resourceAddress = it.address
)
}
insertPoolDetails(poolEntities)
fun updatePools(pools: List<PoolWithResourcesJoinResult>) {
insertPoolDetails(pools.map { it.pool })

val resourcesInvolved = pools.map { entry -> listOf(entry.key) + entry.value.map { it.second } }.flatten()
val resourcesInvolved = pools.map { pool ->
listOf(pool.poolUnitResource) + pool.resources.map { it.second }
}.flatten()
insertOrReplaceResources(resourcesInvolved)
val join = pools.values.map { poolResource -> poolResource.map { it.first } }.flatten()
val join = pools.map { poolResource -> poolResource.resources.map { it.first } }.flatten()
insertPoolResources(join)
}

Expand Down Expand Up @@ -128,7 +124,8 @@ interface StateDao {
"""
SELECT
PoolEntity.address AS pool_entity_address,
PoolEntity.resource_address AS pool_unit_address,
PoolEntity.resource_address AS pool_unit_address,
PoolEntity.metadata AS pool_metadata,
PoolResourceJoin.state_version AS account_state_version,
PoolResourceJoin.amount AS amount,
ResourceEntity.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ fun StateDao.getCachedPools(poolAddresses: Set<String>, atStateVersion: Long): M
val pool = pools[poolResource.poolAddress]
pools[poolResource.poolAddress!!] = pool?.copy(
resources = pool.resources.toMutableList().apply { add(resource) }
) ?: Pool(address = join.address, poolUnitAddress = join.poolUnitAddress, resources = listOf(resource))
) ?: Pool(
address = join.address,
resources = listOf(resource),
metadata = join.poolMetadata?.metadata.orEmpty(),
)
}
return pools
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import androidx.room.TypeConverters
PoolResourceJoin::class,
DAppEntity::class
],
version = StateDatabase.VERSION_3
version = StateDatabase.VERSION_4
)
@TypeConverters(StateDatabaseConverters::class)
abstract class StateDatabase : RoomDatabase() {
Expand All @@ -32,9 +32,12 @@ abstract class StateDatabase : RoomDatabase() {
@Deprecated("Updated metadata schema")
const val VERSION_2 = 2

// Add DAppEntity to schema
@Deprecated("Add DAppEntity to schema")
const val VERSION_3 = 3

// Add PoolEntity.metadata to schema
const val VERSION_4 = 4

private const val NAME = "STATE_DATABASE"

fun factory(applicationContext: Context): StateDatabase = Room
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ data class PoolWithResourceResponse(
val poolUnitAddress: String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this can be deleted now, since the same info exists in the poolMetadata.

@ColumnInfo("account_state_version")
val accountStateVersion: Long?,
@ColumnInfo("pool_metadata")
val poolMetadata: MetadataColumn?,
val amount: BigDecimal?,

// From ResourceEntity (@Embed does not work here since making ResourceEntity nullable does not work)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.babylon.wallet.android.domain.model.resources.Pool
import com.babylon.wallet.android.domain.model.resources.Resource
import com.babylon.wallet.android.domain.model.resources.XrdResource
import com.babylon.wallet.android.domain.model.resources.metadata.AccountType
import com.babylon.wallet.android.domain.model.resources.metadata.poolUnit
import com.babylon.wallet.android.utils.truncatedHash
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -328,7 +329,7 @@ class AccountsStateCache @Inject constructor(
val pool = pools[fungible.poolAddress]?.takeIf { pool ->
// The fungible claims that it is part of the poolAddress.
// We need to check if pool points back to this resource
pool.poolUnitAddress == fungible.resourceAddress
pool.metadata.poolUnit() == fungible.resourceAddress
}
if (pool != null) {
resultingPoolUnits.add(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.babylon.wallet.android.data.repository.state

import com.babylon.wallet.android.data.gateway.apis.StateApi
import com.babylon.wallet.android.data.gateway.extensions.fetchPools
import com.babylon.wallet.android.data.gateway.extensions.fetchValidators
import com.babylon.wallet.android.data.gateway.extensions.getNextNftItems
import com.babylon.wallet.android.data.gateway.extensions.paginateDetails
Expand All @@ -10,6 +11,7 @@ import com.babylon.wallet.android.data.gateway.model.ExplicitMetadataKey
import com.babylon.wallet.android.data.repository.cache.database.DAppEntity
import com.babylon.wallet.android.data.repository.cache.database.MetadataColumn
import com.babylon.wallet.android.data.repository.cache.database.NFTEntity.Companion.asEntity
import com.babylon.wallet.android.data.repository.cache.database.PoolEntity.Companion.asPoolsResourcesJoin
import com.babylon.wallet.android.data.repository.cache.database.ResourceEntity
import com.babylon.wallet.android.data.repository.cache.database.ResourceEntity.Companion.asEntity
import com.babylon.wallet.android.data.repository.cache.database.StateDao
Expand Down Expand Up @@ -52,7 +54,7 @@ interface StateRepository {

suspend fun getResources(addresses: Set<String>, underAccountAddress: String?, withDetails: Boolean): Result<List<Resource>>

suspend fun getPool(poolAddress: String): Result<Pool>
suspend fun getPools(poolAddresses: Set<String>): Result<List<Pool>>

suspend fun getValidator(validatorAddress: String): Result<ValidatorDetail>

Expand Down Expand Up @@ -285,13 +287,26 @@ class StateRepositoryImpl @Inject constructor(
}
}

override suspend fun getPool(poolAddress: String): Result<Pool> = withContext(dispatcher) {
override suspend fun getPools(poolAddresses: Set<String>): Result<List<Pool>> = withContext(dispatcher) {
runCatching {
val stateVersion = stateDao.getLatestStateVersion() ?: error("No cached state version found")
stateDao.getCachedPools(
poolAddresses = setOf(poolAddress),
var cachedPools = stateDao.getCachedPools(
poolAddresses = poolAddresses,
atStateVersion = stateVersion
)[poolAddress] ?: error("Pool $poolAddress does not exist")
).values.toList()
val unknownPools = poolAddresses - cachedPools.map { it.address }.toSet()
if (unknownPools.isNotEmpty()) {
val newPools = stateApi.fetchPools(unknownPools, stateVersion)
if (newPools.isNotEmpty()) {
val join = newPools.asPoolsResourcesJoin(SyncInfo(InstantGenerator(), stateVersion))
stateDao.updatePools(pools = join)
cachedPools = stateDao.getCachedPools(
poolAddresses = poolAddresses,
atStateVersion = stateVersion
).values.toList()
}
}
cachedPools
}
}

Expand Down
Loading