Skip to content

Commit

Permalink
Fix/nomination pools (#1587)
Browse files Browse the repository at this point in the history
* Show holds

* Show holds on balance details

* Reduce shown reserved amount by sum of all holds

* Fix conflicts

* Code style
  • Loading branch information
valentunn authored Jul 19, 2024
1 parent 7b3912a commit 5454d77
Show file tree
Hide file tree
Showing 80 changed files with 1,068 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ fun RuntimeMetadata.preImage() = module(Modules.PREIMAGE)

fun RuntimeMetadata.nominationPools() = module(Modules.NOMINATION_POOLS)

fun RuntimeMetadata.delegatedStakingOrNull() = moduleOrNull(Modules.DELEGATED_STAKING)

fun RuntimeMetadata.delegatedStaking() = module(Modules.DELEGATED_STAKING)

fun RuntimeMetadata.nominationPoolsOrNull() = moduleOrNull(Modules.NOMINATION_POOLS)

fun RuntimeMetadata.assetConversionOrNull() = moduleOrNull(Modules.ASSET_CONVERSION)
Expand Down Expand Up @@ -437,6 +441,8 @@ object Modules {

const val NOMINATION_POOLS = "NominationPools"

const val DELEGATED_STAKING = "DelegatedStaking"

const val ASSET_CONVERSION = "AssetConversion"

const val TRANSACTION_PAYMENT = "TransactionPayment"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ fun <T : Identifiable, R> Flow<List<T>>.transformLatestDiffed(transform: suspend
private class SendingCollector<T>(
private val channel: SendChannel<T>
) : FlowCollector<T> {

override suspend fun emit(value: T): Unit = channel.send(value)
}

Expand Down Expand Up @@ -554,6 +555,20 @@ fun <A, B, C, R> unite(flowA: Flow<A>, flowB: Flow<B>, flowC: Flow<C>, transform
).map { transform(aResult, bResult, cResult) }
}

fun <A, B, C, D, R> unite(flowA: Flow<A>, flowB: Flow<B>, flowC: Flow<C>, flowD: Flow<D>, transform: (A?, B?, C?, D?) -> R): Flow<R> {
var aResult: A? = null
var bResult: B? = null
var cResult: C? = null
var dResult: D? = null

return merge(
flowA.onEach { aResult = it },
flowB.onEach { bResult = it },
flowC.onEach { cResult = it },
flowD.onEach { dResult = it }
).map { transform(aResult, bResult, cResult, dResult) }
}

fun <T> firstNonEmpty(
vararg sources: Flow<List<T>>
): Flow<List<T>> = accumulate(*sources)
Expand Down
7 changes: 7 additions & 0 deletions common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="TypographyEllipsis">
<string name="setup_staking_conflict_title">Already staking</string>
<string name="setup_staking_conflict_message">You cannot stake with Direct Staking and Nomination Pools at the same time</string>


<string name="pool_staking_conflict_title">Pool operations are not available</string>
<string name="pool_staking_conflict_message">You can no longer use both Direct Staking and Pool Staking from the same account. To manage your Pool Staking you first need to unstake your tokens from Direct Staking.</string>

<string name="chain_network_management_auto_balance">Auto-balance nodes</string>
<string name="chain_network_management_enabling">Enable connection</string>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
import io.novafoundation.nova.core_db.dao.ExternalBalanceDao
import io.novafoundation.nova.core_db.dao.FavouriteDAppsDao
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
import io.novafoundation.nova.core_db.dao.HoldsDao
import io.novafoundation.nova.core_db.dao.LockDao
import io.novafoundation.nova.core_db.dao.MetaAccountDao
import io.novafoundation.nova.core_db.dao.NftDao
Expand All @@ -44,6 +45,7 @@ import io.novafoundation.nova.core_db.dao.StorageDao
import io.novafoundation.nova.core_db.dao.TokenDao
import io.novafoundation.nova.core_db.dao.WalletConnectSessionsDao
import io.novafoundation.nova.core_db.migrations.AddAdditionalFieldToChains_12_13
import io.novafoundation.nova.core_db.migrations.AddBalanceHolds_60_61
import io.novafoundation.nova.core_db.migrations.AddBalanceModesToAssets_51_52
import io.novafoundation.nova.core_db.migrations.AddBrowserHostSettings_34_35
import io.novafoundation.nova.core_db.migrations.AddBuyProviders_7_8
Expand All @@ -59,7 +61,6 @@ import io.novafoundation.nova.core_db.migrations.AddExtrinsicContentField_37_38
import io.novafoundation.nova.core_db.migrations.AddFavouriteDApps_9_10
import io.novafoundation.nova.core_db.migrations.AddFungibleNfts_55_56
import io.novafoundation.nova.core_db.migrations.AddGloballyUniqueIdToMetaAccounts_58_59
import io.novafoundation.nova.core_db.migrations.ChainNetworkManagement_59_60
import io.novafoundation.nova.core_db.migrations.AddGovernanceDapps_25_26
import io.novafoundation.nova.core_db.migrations.AddGovernanceExternalApiToChain_27_28
import io.novafoundation.nova.core_db.migrations.AddGovernanceFlagToChains_24_25
Expand All @@ -84,6 +85,7 @@ import io.novafoundation.nova.core_db.migrations.AddVersioningToGovernanceDapps_
import io.novafoundation.nova.core_db.migrations.AddWalletConnectSessions_39_40
import io.novafoundation.nova.core_db.migrations.AssetTypes_2_3
import io.novafoundation.nova.core_db.migrations.BetterChainDiffing_8_9
import io.novafoundation.nova.core_db.migrations.ChainNetworkManagement_59_60
import io.novafoundation.nova.core_db.migrations.ChainPushSupport_56_57
import io.novafoundation.nova.core_db.migrations.ChangeAsset_3_4
import io.novafoundation.nova.core_db.migrations.ChangeChainNodes_20_21
Expand All @@ -105,6 +107,7 @@ import io.novafoundation.nova.core_db.migrations.WatchOnlyChainAccounts_16_17
import io.novafoundation.nova.core_db.model.AccountLocal
import io.novafoundation.nova.core_db.model.AccountStakingLocal
import io.novafoundation.nova.core_db.model.AssetLocal
import io.novafoundation.nova.core_db.model.BalanceHoldLocal
import io.novafoundation.nova.core_db.model.BalanceLockLocal
import io.novafoundation.nova.core_db.model.BrowserHostSettingsLocal
import io.novafoundation.nova.core_db.model.CoinPriceLocal
Expand Down Expand Up @@ -142,7 +145,7 @@ import io.novafoundation.nova.core_db.model.operation.SwapTypeLocal
import io.novafoundation.nova.core_db.model.operation.TransferTypeLocal

@Database(
version = 60,
version = 61,
entities = [
AccountLocal::class,
NodeLocal::class,
Expand Down Expand Up @@ -181,6 +184,7 @@ import io.novafoundation.nova.core_db.model.operation.TransferTypeLocal
StakingRewardPeriodLocal::class,
ExternalBalanceLocal::class,
ProxyAccountLocal::class,
BalanceHoldLocal::class,
NodeSelectionPreferencesLocal::class
],
)
Expand Down Expand Up @@ -236,7 +240,7 @@ abstract class AppDatabase : RoomDatabase() {
.addMigrations(ChangeSessionTopicToParing_52_53, AddConnectionStateToChains_53_54, AddProxyAccount_54_55)
.addMigrations(AddFungibleNfts_55_56, ChainPushSupport_56_57)
.addMigrations(AddLocalMigratorVersionToChainRuntimes_57_58, AddGloballyUniqueIdToMetaAccounts_58_59)
.addMigrations(ChainNetworkManagement_59_60)
.addMigrations(ChainNetworkManagement_59_60, AddBalanceHolds_60_61)
.build()
}
return instance!!
Expand Down Expand Up @@ -294,4 +298,6 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun stakingRewardPeriodDao(): StakingRewardPeriodDao

abstract fun externalBalanceDao(): ExternalBalanceDao

abstract fun holdsDao(): HoldsDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.novafoundation.nova.core_db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import io.novafoundation.nova.core_db.model.BalanceHoldLocal
import kotlinx.coroutines.flow.Flow

@Dao
abstract class HoldsDao {

@Transaction
open suspend fun updateHolds(
holds: List<BalanceHoldLocal>,
metaId: Long,
chainId: String,
chainAssetId: Int
) {
deleteHolds(metaId, chainId, chainAssetId)

insert(holds)
}

@Insert(onConflict = OnConflictStrategy.REPLACE)
protected abstract fun insert(holds: List<BalanceHoldLocal>)

@Query("DELETE FROM holds WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId")
protected abstract fun deleteHolds(metaId: Long, chainId: String, chainAssetId: Int)

@Query("SELECT * FROM holds WHERE metaId = :metaId")
abstract fun observeHoldsForMetaAccount(metaId: Long): Flow<List<BalanceHoldLocal>>

@Query("SELECT * FROM holds WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId")
abstract fun observeBalanceHolds(metaId: Long, chainId: String, chainAssetId: Int): Flow<List<BalanceHoldLocal>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
import io.novafoundation.nova.core_db.dao.ExternalBalanceDao
import io.novafoundation.nova.core_db.dao.FavouriteDAppsDao
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
import io.novafoundation.nova.core_db.dao.HoldsDao
import io.novafoundation.nova.core_db.dao.LockDao
import io.novafoundation.nova.core_db.dao.MetaAccountDao
import io.novafoundation.nova.core_db.dao.NftDao
Expand Down Expand Up @@ -83,4 +84,6 @@ interface DbApi {
val stakingDashboardDao: StakingDashboardDao

val externalBalanceDao: ExternalBalanceDao

val holdsDao: HoldsDao
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
import io.novafoundation.nova.core_db.dao.ExternalBalanceDao
import io.novafoundation.nova.core_db.dao.FavouriteDAppsDao
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
import io.novafoundation.nova.core_db.dao.HoldsDao
import io.novafoundation.nova.core_db.dao.LockDao
import io.novafoundation.nova.core_db.dao.MetaAccountDao
import io.novafoundation.nova.core_db.dao.NftDao
Expand Down Expand Up @@ -198,4 +199,10 @@ class DbModule {
fun provideExternalBalanceDao(appDatabase: AppDatabase): ExternalBalanceDao {
return appDatabase.externalBalanceDao()
}

@Provides
@ApplicationScope
fun provideHoldsDao(appDatabase: AppDatabase): HoldsDao {
return appDatabase.holdsDao()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.novafoundation.nova.core_db.migrations

import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

val AddBalanceHolds_60_61 = object : Migration(60, 61) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS `holds` (
`metaId` INTEGER NOT NULL,
`chainId` TEXT NOT NULL,
`assetId` INTEGER NOT NULL,
`amount` TEXT NOT NULL,
`id_module` TEXT NOT NULL,
`id_reason` TEXT NOT NULL,
PRIMARY KEY(`metaId`, `chainId`, `assetId`, `id_module`, `id_reason`),
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE ,
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE ,
FOREIGN KEY(`assetId`, `chainId`) REFERENCES `chain_assets`(`id`, `chainId`) ON UPDATE NO ACTION ON DELETE CASCADE
)
""".trimIndent()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.novafoundation.nova.core_db.model

import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.ForeignKey
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
import io.novafoundation.nova.core_db.model.chain.ChainLocal
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
import java.math.BigInteger

@Entity(
tableName = "holds",
primaryKeys = ["metaId", "chainId", "assetId", "id_module", "id_reason"],
foreignKeys = [
ForeignKey(
entity = MetaAccountLocal::class,
parentColumns = ["id"],
childColumns = ["metaId"],
onDelete = ForeignKey.CASCADE
),
ForeignKey(
entity = ChainLocal::class,
parentColumns = ["id"],
childColumns = ["chainId"],
onDelete = ForeignKey.CASCADE
),
ForeignKey(
entity = ChainAssetLocal::class,
parentColumns = ["id", "chainId"],
childColumns = ["assetId", "chainId"],
onDelete = ForeignKey.CASCADE
)
],
)
class BalanceHoldLocal(
val metaId: Long,
val chainId: String,
val assetId: Int,
@Embedded(prefix = "id_") val id: HoldIdLocal,
val amount: BigInteger
) {

class HoldIdLocal(val module: String, val reason: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.novafoundation.nova.common.resources.ResourceManager
import io.novafoundation.nova.common.utils.QrCodeGenerator
import io.novafoundation.nova.common.validation.ValidationExecutor
import io.novafoundation.nova.common.view.bottomSheet.description.DescriptionBottomSheetLauncher
import io.novafoundation.nova.core_db.dao.HoldsDao
import io.novafoundation.nova.core_db.dao.LockDao
import io.novafoundation.nova.core_db.dao.OperationDao
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
Expand Down Expand Up @@ -56,6 +57,7 @@ import io.novafoundation.nova.feature_wallet_api.data.network.coingecko.Coingeck
import io.novafoundation.nova.feature_wallet_api.data.network.crosschain.CrossChainTransactor
import io.novafoundation.nova.feature_wallet_api.data.network.crosschain.CrossChainTransfersRepository
import io.novafoundation.nova.feature_wallet_api.data.network.crosschain.CrossChainWeigher
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceHoldsRepository
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository
import io.novafoundation.nova.feature_wallet_api.data.repository.ExternalBalanceRepository
import io.novafoundation.nova.feature_wallet_api.domain.ArbitraryTokenUseCase
Expand Down Expand Up @@ -243,5 +245,9 @@ interface AssetsFeatureDependencies {

val chainStateRepository: ChainStateRepository

val holdsRepository: BalanceHoldsRepository

val holdsDao: HoldsDao

val coinGeckoLinkParser: CoinGeckoLinkParser
}
Loading

0 comments on commit 5454d77

Please sign in to comment.