Skip to content

Commit

Permalink
Merge pull request #745 from radixdlt/feature/ABW-2674-pool-redeem-co…
Browse files Browse the repository at this point in the history
…ntrobute-tx-types

[ABW-2674] Pool redemption/contribution tx preview types
  • Loading branch information
micbakos-rdx authored Jan 17, 2024
2 parents 2846fff + 9a8bf7d commit 4bc4dee
Show file tree
Hide file tree
Showing 43 changed files with 1,282 additions and 314 deletions.
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,
@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

0 comments on commit 4bc4dee

Please sign in to comment.