Skip to content

Commit

Permalink
Merge pull request #1022 from radixdlt/feature/all-metadata-retake
Browse files Browse the repository at this point in the history
All metadata
  • Loading branch information
micbakos-rdx authored Jul 3, 2024
2 parents d350d0c + 9916dd8 commit 10a0e02
Show file tree
Hide file tree
Showing 42 changed files with 1,274 additions and 522 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.babylon.wallet.android.data.gateway.extensions

import com.babylon.wallet.android.data.gateway.apis.StateApi
import com.babylon.wallet.android.data.gateway.generated.models.EntityMetadataItem
import com.babylon.wallet.android.data.gateway.generated.models.FungibleResourcesCollection
import com.babylon.wallet.android.data.gateway.generated.models.FungibleResourcesCollectionItem
import com.babylon.wallet.android.data.gateway.generated.models.LedgerState
Expand All @@ -15,6 +16,7 @@ import com.babylon.wallet.android.data.gateway.generated.models.StateEntityDetai
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityDetailsResponseItem
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityFungiblesPageRequest
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityFungiblesPageRequestOptIns
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityMetadataPageRequest
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityNonFungibleIdsPageRequest
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityNonFungiblesPageRequest
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityNonFungiblesPageRequestOptIns
Expand Down Expand Up @@ -386,3 +388,28 @@ suspend fun StateApi.paginateNonFungibles(
onPage(response)
}
}

suspend fun StateApi.getAllMetadata(
resourceAddress: ResourceAddress,
stateVersion: Long,
initialCursor: String
): List<EntityMetadataItem> {
val items = mutableListOf<EntityMetadataItem>()

var cursor: String? = initialCursor
while (cursor != null) {
val page = entityMetadataPage(
stateEntityMetadataPageRequest = StateEntityMetadataPageRequest(
address = resourceAddress.string,
cursor = initialCursor,
atLedgerState = LedgerStateSelector(
stateVersion = stateVersion
)
)
).toResult().getOrThrow()
cursor = page.nextCursor
items.addAll(page.items)
}

return items
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.babylon.wallet.android.data.repository.cache.database
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.babylon.wallet.android.data.gateway.extensions.toMetadata
import com.babylon.wallet.android.data.gateway.generated.models.StateEntityDetailsResponseItem
import com.radixdlt.sargon.AccountAddress
import com.radixdlt.sargon.extensions.init
Expand All @@ -27,7 +26,10 @@ data class DAppEntity(
companion object {
fun from(item: StateEntityDetailsResponseItem, syncedAt: Instant) = DAppEntity(
definitionAddress = AccountAddress.init(item.address),
metadata = item.explicitMetadata?.toMetadata()?.let { MetadataColumn(it) },
metadata = MetadataColumn.from(
explicitMetadata = item.explicitMetadata,
implicitMetadata = item.metadata
),
synced = syncedAt
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ data class NFTEntity(
metadata = toMetadata().takeIf {
it.isNotEmpty()
}?.let {
MetadataColumn(it)
MetadataColumn(metadata = it, implicitState = MetadataColumn.ImplicitMetadataState.Complete)
},
synced = synced
)
Expand All @@ -49,7 +49,7 @@ data class NFTEntity(
metadata = metadata.takeIf {
it.isNotEmpty()
}?.let {
MetadataColumn(it)
MetadataColumn(metadata = it, implicitState = MetadataColumn.ImplicitMetadataState.Complete)
},
synced = synced
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
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
Expand Down Expand Up @@ -60,11 +59,14 @@ data class PoolEntity(
}

fun StateEntityDetailsResponseItem.asPoolEntity(): PoolEntity? {
val metadata = this.metadata.toMetadata()
val poolUnitResourceAddress = metadata.poolUnit() ?: return null
val metadataColumn = MetadataColumn.from(
explicitMetadata = explicitMetadata,
implicitMetadata = metadata
)
val poolUnitResourceAddress = metadataColumn.metadata.poolUnit() ?: return null
return PoolEntity(
address = PoolAddress.init(address),
metadata = MetadataColumn(metadata),
metadata = metadataColumn,
resourceAddress = poolUnitResourceAddress
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package com.babylon.wallet.android.data.repository.cache.database

import androidx.room.ProvidedTypeConverter
import androidx.room.TypeConverter
import com.babylon.wallet.android.data.gateway.extensions.toMetadata
import com.babylon.wallet.android.data.gateway.generated.models.EntityMetadataCollection
import com.babylon.wallet.android.data.repository.cache.database.MetadataColumn.ImplicitMetadataState
import com.radixdlt.sargon.AccountAddress
import com.radixdlt.sargon.Decimal192
import com.radixdlt.sargon.NonFungibleLocalId
Expand All @@ -12,6 +15,7 @@ import com.radixdlt.sargon.VaultAddress
import com.radixdlt.sargon.extensions.init
import com.radixdlt.sargon.extensions.string
import com.radixdlt.sargon.extensions.toDecimal192OrNull
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
Expand All @@ -24,7 +28,75 @@ import java.time.Instant
data class BehavioursColumn(val behaviours: Set<AssetBehaviour>)

@Serializable
data class MetadataColumn(val metadata: List<Metadata>)
data class MetadataColumn(
/**
* A union of explicit and **currently known** implicit metadata
* As a client we don't need to expose the difference between explicit
* and implicit metadata.
*/
val metadata: List<Metadata>,

/**
* The state of the next page of the implicit metadata. See [ImplicitMetadataState]
*/
@SerialName("implicit_state")
val implicitState: ImplicitMetadataState
) {

val nextCursor: String?
get() = (implicitState as? ImplicitMetadataState.Incomplete)?.nextCursor

@Serializable
sealed interface ImplicitMetadataState {
/**
* When we have no information yet regarding the existence of implicit metadata
* An example is when we query account information. In this request we receive
* resource data but with no information about implicit metadata. In order to make
* sure we received all metadata available we need to fetch details of this specific
* resource
*/
@Serializable
@SerialName("unknown")
data object Unknown : ImplicitMetadataState

/**
* We have received an answer from a details request and we know that the [MetadataColumn.metadata]
* are complete.
*/
@Serializable
@SerialName("complete")
data object Complete : ImplicitMetadataState

/**
* We have received an answer from a details request and we know that the [MetadataColumn.metadata]
* are incomplete. We need to query [nextCursor] to receive more.
*/
@Serializable
@SerialName("incomplete")
data class Incomplete(
@SerialName("next_cursor")
val nextCursor: String
) : ImplicitMetadataState
}

companion object {
fun from(
explicitMetadata: EntityMetadataCollection?,
implicitMetadata: EntityMetadataCollection
): MetadataColumn {
val explicit = explicitMetadata?.toMetadata().orEmpty().toSet()
val implicit = implicitMetadata.toMetadata().toSet()

val all = explicit union implicit
return MetadataColumn(
metadata = all.toList(),
implicitState = implicitMetadata.nextCursor?.let {
ImplicitMetadataState.Incomplete(nextCursor = it)
} ?: ImplicitMetadataState.Complete
)
}
}
}

@Suppress("TooManyFunctions")
@ProvidedTypeConverter
Expand All @@ -37,23 +109,23 @@ class StateDatabaseConverters {
// Behaviours
@TypeConverter
fun stringToBehaviours(string: String?): BehavioursColumn? {
return string?.let { BehavioursColumn(behaviours = json.decodeFromString(string)) }
return string?.let { json.decodeFromString(string) }
}

@TypeConverter
fun behavioursToString(column: BehavioursColumn?): String? {
return column?.let { json.encodeToString(it.behaviours) }
return column?.let { json.encodeToString(it) }
}

// Metadata
@TypeConverter
fun stringToMetadata(string: String?): MetadataColumn? {
return string?.let { MetadataColumn(metadata = json.decodeFromString(string)) }
return string?.let { json.decodeFromString(string) }
}

@TypeConverter
fun metadataToString(column: MetadataColumn?): String? {
return column?.let { json.encodeToString(it.metadata) }
return column?.let { json.encodeToString(it) }
}

// Decimal192
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ import com.radixdlt.sargon.extensions.init
import com.radixdlt.sargon.extensions.string
import com.radixdlt.sargon.extensions.toDecimal192
import rdx.works.core.domain.resources.Divisibility
import rdx.works.core.domain.resources.ExplicitMetadataKey
import rdx.works.core.domain.resources.Resource
import rdx.works.core.domain.resources.metadata.Metadata
import rdx.works.core.domain.resources.metadata.MetadataType
import rdx.works.core.domain.resources.metadata.poolAddress
import rdx.works.core.domain.resources.metadata.validatorAddress
import java.time.Instant
Expand All @@ -50,17 +47,14 @@ data class ResourceEntity(
val synced: Instant
) {

val isDetailsAvailable: Boolean
get() = when (type) {
ResourceEntityType.FUNGIBLE -> supply != null && divisibility != null && behaviours != null
ResourceEntityType.NON_FUNGIBLE -> supply != null && behaviours != null
}

@Suppress("CyclomaticComplexMethod")
fun toResource(amount: Decimal192?): Resource {
val validatorAndPoolMetadata = listOf(
validatorAddress?.let {
Metadata.Primitive(ExplicitMetadataKey.VALIDATOR.key, it.string, MetadataType.Address)
},
poolAddress?.let {
Metadata.Primitive(ExplicitMetadataKey.POOL.key, it.string, MetadataType.Address)
}
).mapNotNull { it }

return when (type) {
ResourceEntityType.FUNGIBLE -> {
Resource.FungibleResource(
Expand All @@ -69,7 +63,7 @@ data class ResourceEntity(
assetBehaviours = behaviours?.behaviours?.toSet(),
currentSupply = supply,
divisibility = divisibility,
metadata = metadata?.metadata.orEmpty() + validatorAndPoolMetadata
metadata = metadata?.metadata.orEmpty()
)
}

Expand All @@ -80,7 +74,7 @@ data class ResourceEntity(
assetBehaviours = behaviours?.behaviours?.toSet(),
items = emptyList(),
currentSupply = supply?.string?.toIntOrNull(),
metadata = metadata?.metadata.orEmpty() + validatorAndPoolMetadata
metadata = metadata?.metadata.orEmpty()
)
}
}
Expand All @@ -97,9 +91,8 @@ data class ResourceEntity(
validatorAddress = metadata.validatorAddress(),
poolAddress = metadata.poolAddress(),
metadata = metadata
.filterNot { it.key in setOf(ExplicitMetadataKey.POOL.key, ExplicitMetadataKey.VALIDATOR.key) }
.takeIf { it.isNotEmpty() }
?.let { MetadataColumn(it) },
?.let { MetadataColumn(it, MetadataColumn.ImplicitMetadataState.Unknown) },
synced = synced
)

Expand All @@ -112,9 +105,8 @@ data class ResourceEntity(
validatorAddress = metadata.validatorAddress(),
poolAddress = metadata.poolAddress(),
metadata = metadata
.filterNot { it.key in setOf(ExplicitMetadataKey.POOL.key, ExplicitMetadataKey.VALIDATOR.key) }
.takeIf { it.isNotEmpty() }
?.let { MetadataColumn(it) },
?.let { MetadataColumn(it, MetadataColumn.ImplicitMetadataState.Unknown) },
synced = synced
)
}
Expand All @@ -126,7 +118,8 @@ data class ResourceEntity(
details: StateEntityDetailsResponseItemDetails? = null
): ResourceEntity = from(
address = ResourceAddress.init(resourceAddress),
metadataCollection = explicitMetadata,
explicitMetadata = explicitMetadata,
implicitMetadata = null,
details = details,
type = ResourceEntityType.FUNGIBLE,
synced = synced
Expand All @@ -139,7 +132,8 @@ data class ResourceEntity(
details: StateEntityDetailsResponseItemDetails? = null
): ResourceEntity = from(
address = ResourceAddress.init(resourceAddress),
metadataCollection = explicitMetadata,
explicitMetadata = explicitMetadata,
implicitMetadata = null,
details = details,
type = ResourceEntityType.NON_FUNGIBLE,
synced = synced
Expand All @@ -156,33 +150,44 @@ data class ResourceEntity(
}
return from(
address = ResourceAddress.init(address),
metadataCollection = metadata,
explicitMetadata = explicitMetadata,
implicitMetadata = metadata,
details = details,
type = type,
synced = synced
)
}

@Suppress("LongParameterList")
private fun from(
address: ResourceAddress,
metadataCollection: EntityMetadataCollection?,
explicitMetadata: EntityMetadataCollection?,
implicitMetadata: EntityMetadataCollection?,
details: StateEntityDetailsResponseItemDetails?,
type: ResourceEntityType,
synced: Instant
): ResourceEntity {
val metadata = metadataCollection?.toMetadata().orEmpty()
val metadataColumn = if (implicitMetadata != null) {
MetadataColumn.from(
explicitMetadata = explicitMetadata,
implicitMetadata = implicitMetadata
)
} else {
MetadataColumn(
metadata = explicitMetadata?.toMetadata().orEmpty(),
implicitState = MetadataColumn.ImplicitMetadataState.Unknown
)
}.takeIf { it.metadata.isNotEmpty() }

return ResourceEntity(
address = address,
type = type,
divisibility = details?.divisibility(),
behaviours = details?.let { BehavioursColumn(it.extractBehaviours()) },
supply = details?.totalSupply(),
validatorAddress = metadata.validatorAddress(),
poolAddress = metadata.poolAddress(),
metadata = metadata
.filterNot { it.key in setOf(ExplicitMetadataKey.VALIDATOR.key, ExplicitMetadataKey.POOL.key) }
.takeIf { it.isNotEmpty() }
?.let { MetadataColumn(it) },
validatorAddress = metadataColumn?.metadata?.validatorAddress(),
poolAddress = metadataColumn?.metadata?.poolAddress(),
metadata = metadataColumn,
synced = synced
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,15 @@ interface StateDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertDApps(dApps: List<DAppEntity>)

@Query(
"""
UPDATE ResourceEntity SET
metadata = :metadataColumn
WHERE address = :resourceAddress
"""
)
fun updateMetadata(resourceAddress: ResourceAddress, metadataColumn: MetadataColumn)

companion object {
val deleteDuration = 1.toDuration(DurationUnit.SECONDS)
private val accountsCacheDuration = 2.toDuration(DurationUnit.HOURS)
Expand Down
Loading

0 comments on commit 10a0e02

Please sign in to comment.