mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-22 02:07:58 +00:00
Initial commit: Pezkuwi Wallet Android
Security hardened release: - Code obfuscation enabled (minifyEnabled=true, shrinkResources=true) - Sensitive files excluded (google-services.json, keystores) - Branch.io key moved to BuildConfig placeholder - Updated dependencies: OkHttp 4.12.0, Gson 2.10.1, BouncyCastle 1.77 - Comprehensive ProGuard rules for crypto wallet - Navigation 2.7.7, Lifecycle 2.7.0, ConstraintLayout 2.1.4
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,68 @@
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply from: '../scripts/secrets.gradle'
|
||||
|
||||
android {
|
||||
namespace 'io.novafoundation.nova.feature_governance_impl'
|
||||
|
||||
|
||||
defaultConfig {
|
||||
buildConfigField "String", "GOVERNANCE_DAPPS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/governance/v2/dapps_dev.json\""
|
||||
|
||||
buildConfigField "String", "DELEGATION_TUTORIAL_URL", "\"https://docs.pezkuwichain.io/pezkuwi-wallet-wiki/governance/add-delegate-information\""
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
||||
buildConfigField "String", "GOVERNANCE_DAPPS_URL", "\"https://raw.githubusercontent.com/pezkuwichain/pezkuwi-wallet-utils/master/governance/v2/dapps.json\""
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':feature-account-api')
|
||||
implementation project(':feature-wallet-api')
|
||||
implementation project(':feature-governance-api')
|
||||
implementation project(':feature-dapp-api')
|
||||
implementation project(':feature-xcm:api')
|
||||
implementation project(':feature-deep-linking')
|
||||
|
||||
implementation project(":common")
|
||||
implementation project(":runtime")
|
||||
|
||||
implementation markwonDep
|
||||
|
||||
implementation materialDep
|
||||
|
||||
implementation substrateSdkDep
|
||||
|
||||
implementation kotlinDep
|
||||
|
||||
|
||||
implementation androidDep
|
||||
|
||||
implementation coroutinesDep
|
||||
implementation coroutinesAndroidDep
|
||||
implementation lifeCycleKtxDep
|
||||
implementation flexBoxDep
|
||||
|
||||
implementation project(":core-db")
|
||||
|
||||
implementation viewModelKtxDep
|
||||
|
||||
implementation shimmerDep
|
||||
|
||||
implementation cardStackView
|
||||
|
||||
implementation daggerDep
|
||||
ksp daggerCompiler
|
||||
|
||||
testImplementation jUnitDep
|
||||
testImplementation mockitoDep
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data
|
||||
|
||||
import io.novafoundation.nova.common.data.storage.Preferences
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.feature_governance_api.data.MutableGovernanceState
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceAdditionalState
|
||||
import io.novafoundation.nova.feature_governance_impl.R
|
||||
import io.novafoundation.nova.runtime.ext.isUtilityAsset
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.state.SelectableSingleAssetSharedState
|
||||
|
||||
private const val GOVERNANCE_SHARED_STATE = "GOVERNANCE_SHARED_STATE"
|
||||
|
||||
class GovernanceSharedState(
|
||||
chainRegistry: ChainRegistry,
|
||||
preferences: Preferences,
|
||||
) : SelectableSingleAssetSharedState<GovernanceAdditionalState>(
|
||||
preferences = preferences,
|
||||
chainRegistry = chainRegistry,
|
||||
supportedOptions = { chain, asset ->
|
||||
if (asset.isUtilityAsset) {
|
||||
val multipleGovernanceTypesPresent = chain.governance.size > 1
|
||||
chain.governance.map { RealGovernanceAdditionalState(it, multipleGovernanceTypesPresent) }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
},
|
||||
preferencesKey = GOVERNANCE_SHARED_STATE
|
||||
),
|
||||
MutableGovernanceState {
|
||||
|
||||
override fun update(chainId: ChainId, assetId: Int, governanceType: Chain.Governance) {
|
||||
update(chainId, assetId, governanceType.name)
|
||||
}
|
||||
}
|
||||
|
||||
class RealGovernanceAdditionalState(
|
||||
override val governanceType: Chain.Governance,
|
||||
private val multipleGovernanceTypesPresent: Boolean
|
||||
) : GovernanceAdditionalState {
|
||||
|
||||
override val identifier: String = governanceType.name
|
||||
|
||||
override fun format(resourceManager: ResourceManager): String? {
|
||||
val shouldShowSuffix = multipleGovernanceTypesPresent || governanceType == Chain.Governance.V2
|
||||
if (!shouldShowSuffix) return null
|
||||
|
||||
return when (governanceType) {
|
||||
Chain.Governance.V1 -> resourceManager.getString(R.string.assets_balance_details_locks_democrac_v1)
|
||||
Chain.Governance.V2 -> resourceManager.getString(R.string.assets_balance_details_locks_democrac_v2)
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.dapps
|
||||
|
||||
import io.novafoundation.nova.common.utils.retryUntilDone
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.core_db.model.GovernanceDAppLocal
|
||||
import io.novafoundation.nova.feature_governance_impl.data.dapps.remote.GovernanceDappsFetcher
|
||||
import io.novafoundation.nova.feature_governance_impl.data.dapps.remote.model.GovernanceChainDappsRemote
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GovernanceDAppsSyncService(
|
||||
private val dao: GovernanceDAppsDao,
|
||||
private val dappsFetcher: GovernanceDappsFetcher
|
||||
) {
|
||||
|
||||
suspend fun syncDapps() = withContext(Dispatchers.Default) {
|
||||
val newDapps = retryUntilDone {
|
||||
mapRemoteDappsToLocal(dappsFetcher.getDapps())
|
||||
}
|
||||
dao.update(newDapps)
|
||||
}
|
||||
|
||||
private fun mapRemoteDappsToLocal(
|
||||
chainDapps: List<GovernanceChainDappsRemote>
|
||||
): List<GovernanceDAppLocal> {
|
||||
return chainDapps.flatMap { chainWithDapp ->
|
||||
chainWithDapp.dapps.map {
|
||||
GovernanceDAppLocal(
|
||||
chainWithDapp.chainId,
|
||||
it.title,
|
||||
it.urlV1,
|
||||
it.urlV2,
|
||||
it.icon,
|
||||
it.details
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.dapps.remote
|
||||
|
||||
import io.novafoundation.nova.feature_governance_impl.BuildConfig
|
||||
import io.novafoundation.nova.feature_governance_impl.data.dapps.remote.model.GovernanceChainDappsRemote
|
||||
import retrofit2.http.GET
|
||||
|
||||
interface GovernanceDappsFetcher {
|
||||
|
||||
@GET(BuildConfig.GOVERNANCE_DAPPS_URL)
|
||||
suspend fun getDapps(): List<GovernanceChainDappsRemote>
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.dapps.remote.model
|
||||
|
||||
class GovernanceChainDappsRemote(
|
||||
val chainId: String,
|
||||
val dapps: List<GovernanceDappRemote>
|
||||
)
|
||||
|
||||
class GovernanceDappRemote(
|
||||
val title: String,
|
||||
val urlV1: String?,
|
||||
val urlV2: String?,
|
||||
val icon: String,
|
||||
val details: String
|
||||
)
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic
|
||||
|
||||
import io.novafoundation.nova.common.utils.Modules
|
||||
import io.novafoundation.nova.common.utils.argumentType
|
||||
import io.novafoundation.nova.common.utils.democracy
|
||||
import io.novafoundation.nova.common.utils.structOf
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.AccountVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.runtime.extrinsic.multi.CallBuilder
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Conviction
|
||||
import io.novafoundation.nova.runtime.util.constructAccountLookupInstance
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.DictEnum
|
||||
import io.novafoundation.nova.common.utils.PezkuwiAddressConstructor
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.builder.ExtrinsicBuilder
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.call
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.call
|
||||
|
||||
fun ExtrinsicBuilder.convictionVotingVote(
|
||||
referendumId: ReferendumId,
|
||||
vote: AccountVote
|
||||
): ExtrinsicBuilder {
|
||||
return call(
|
||||
moduleName = Modules.CONVICTION_VOTING,
|
||||
callName = "vote",
|
||||
arguments = mapOf(
|
||||
"poll_index" to referendumId.value,
|
||||
"vote" to vote.prepareForEncoding()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun CallBuilder.convictionVotingVote(
|
||||
referendumId: ReferendumId,
|
||||
vote: AccountVote
|
||||
): CallBuilder {
|
||||
return addCall(
|
||||
moduleName = Modules.CONVICTION_VOTING,
|
||||
callName = "vote",
|
||||
arguments = mapOf(
|
||||
"poll_index" to referendumId.value,
|
||||
"vote" to vote.prepareForEncoding()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ExtrinsicBuilder.convictionVotingUnlock(
|
||||
trackId: TrackId,
|
||||
accountId: AccountId
|
||||
): ExtrinsicBuilder {
|
||||
return call(
|
||||
moduleName = Modules.CONVICTION_VOTING,
|
||||
callName = "unlock",
|
||||
arguments = mapOf(
|
||||
"class" to trackId.value,
|
||||
"target" to PezkuwiAddressConstructor.constructInstance(runtime.typeRegistry, accountId)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ExtrinsicBuilder.convictionVotingRemoveVote(
|
||||
trackId: TrackId,
|
||||
referendumId: ReferendumId,
|
||||
): ExtrinsicBuilder {
|
||||
return call(
|
||||
moduleName = Modules.CONVICTION_VOTING,
|
||||
callName = "remove_vote",
|
||||
arguments = mapOf(
|
||||
"class" to trackId.value,
|
||||
"index" to referendumId.value
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ExtrinsicBuilder.democracyVote(
|
||||
referendumId: ReferendumId,
|
||||
vote: AccountVote
|
||||
): ExtrinsicBuilder {
|
||||
return call(
|
||||
moduleName = Modules.DEMOCRACY,
|
||||
callName = "vote",
|
||||
arguments = mapOf(
|
||||
"ref_index" to referendumId.value,
|
||||
"vote" to vote.prepareForEncoding()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun CallBuilder.democracyVote(
|
||||
referendumId: ReferendumId,
|
||||
vote: AccountVote
|
||||
): CallBuilder {
|
||||
return addCall(
|
||||
moduleName = Modules.DEMOCRACY,
|
||||
callName = "vote",
|
||||
arguments = mapOf(
|
||||
"ref_index" to referendumId.value,
|
||||
"vote" to vote.prepareForEncoding()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ExtrinsicBuilder.democracyUnlock(accountId: AccountId): ExtrinsicBuilder {
|
||||
val accountLookupType = runtime.metadata.democracy().call("unlock").argumentType("target")
|
||||
|
||||
return call(
|
||||
moduleName = Modules.DEMOCRACY,
|
||||
callName = "unlock",
|
||||
arguments = mapOf(
|
||||
"target" to accountLookupType.constructAccountLookupInstance(accountId)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ExtrinsicBuilder.democracyRemoveVote(
|
||||
referendumId: ReferendumId,
|
||||
): ExtrinsicBuilder {
|
||||
return call(
|
||||
moduleName = Modules.DEMOCRACY,
|
||||
callName = "remove_vote",
|
||||
arguments = mapOf(
|
||||
"index" to referendumId.value
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun CallBuilder.convictionVotingDelegate(
|
||||
delegate: AccountId,
|
||||
trackId: TrackId,
|
||||
amount: Balance,
|
||||
conviction: Conviction
|
||||
): CallBuilder {
|
||||
return addCall(
|
||||
moduleName = Modules.CONVICTION_VOTING,
|
||||
callName = "delegate",
|
||||
arguments = mapOf(
|
||||
"class" to trackId.value,
|
||||
"to" to PezkuwiAddressConstructor.constructInstance(runtime.typeRegistry, delegate),
|
||||
"conviction" to conviction.prepareForEncoding(),
|
||||
"balance" to amount
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun CallBuilder.convictionVotingUndelegate(trackId: TrackId): CallBuilder {
|
||||
return addCall(
|
||||
moduleName = Modules.CONVICTION_VOTING,
|
||||
callName = "undelegate",
|
||||
arguments = mapOf(
|
||||
"class" to trackId.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun Conviction.prepareForEncoding(): Any {
|
||||
return DictEnum.Entry(name, null)
|
||||
}
|
||||
|
||||
private fun AccountVote.prepareForEncoding(): Any {
|
||||
return when (this) {
|
||||
AccountVote.Unsupported -> error("Not yet supported")
|
||||
|
||||
is AccountVote.Standard -> DictEnum.Entry(
|
||||
name = "Standard",
|
||||
value = structOf(
|
||||
"vote" to vote,
|
||||
"balance" to balance
|
||||
)
|
||||
)
|
||||
|
||||
is AccountVote.SplitAbstain -> DictEnum.Entry(
|
||||
name = "SplitAbstain",
|
||||
value = structOf(
|
||||
"aye" to this.aye,
|
||||
"nay" to this.nay,
|
||||
"abstain" to this.abstain
|
||||
)
|
||||
)
|
||||
|
||||
else -> error("Not supported yet")
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumPreview
|
||||
|
||||
interface OffChainReferendaDataSource<O> {
|
||||
|
||||
suspend fun referendumPreviews(baseUrl: String, options: O): List<OffChainReferendumPreview>
|
||||
|
||||
suspend fun referendumDetails(referendumId: ReferendumId, baseUrl: String, options: O): OffChainReferendumDetails?
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.metadata
|
||||
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.metadata.response.DelegateMetadataRemote
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
|
||||
interface DelegateMetadataApi {
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "https://raw.githubusercontent.com/pezkuwichain/opengov-delegate-registry/master/registry/"
|
||||
}
|
||||
|
||||
@GET("{fileName}")
|
||||
suspend fun getDelegatesMetadata(
|
||||
@Path("fileName") fileName: String,
|
||||
): List<DelegateMetadataRemote>
|
||||
}
|
||||
|
||||
suspend fun DelegateMetadataApi.getDelegatesMetadata(chain: Chain): List<DelegateMetadataRemote> {
|
||||
return getDelegatesMetadata(fileNameFor(chain))
|
||||
}
|
||||
|
||||
private fun fileNameFor(chain: Chain): String {
|
||||
val withoutExtension = chain.name.lowercase()
|
||||
|
||||
return "$withoutExtension.json"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.metadata.response
|
||||
|
||||
class DelegateMetadataRemote(
|
||||
val address: String,
|
||||
val name: String,
|
||||
val image: String,
|
||||
val shortDescription: String,
|
||||
val longDescription: String?,
|
||||
val isOrganization: Boolean
|
||||
)
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats
|
||||
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.AllHistoricalVotesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.ReferendumVotersRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateDelegatorsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateDetailedStatsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateStatsByAddressesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateStatsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DirectHistoricalVotesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.ReferendumSplitAbstainVotersRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.ReferendumVotesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.AllVotesResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DelegateDelegatorsResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DelegateDetailedStatsResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DelegateStatsResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DirectVotesResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.ReferendumSplitAbstainVotersResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.ReferendumVotersResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.ReferendumVotesResponse
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface DelegationsSubqueryApi {
|
||||
|
||||
@POST
|
||||
suspend fun getDelegateStats(
|
||||
@Url url: String,
|
||||
@Body body: DelegateStatsRequest
|
||||
): SubQueryResponse<DelegateStatsResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getDelegateStats(
|
||||
@Url url: String,
|
||||
@Body body: DelegateStatsByAddressesRequest
|
||||
): SubQueryResponse<DelegateStatsResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getDetailedDelegateStats(
|
||||
@Url url: String,
|
||||
@Body body: DelegateDetailedStatsRequest
|
||||
): SubQueryResponse<DelegateDetailedStatsResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getDelegateDelegators(
|
||||
@Url url: String,
|
||||
@Body body: DelegateDelegatorsRequest
|
||||
): SubQueryResponse<DelegateDelegatorsResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getAllHistoricalVotes(
|
||||
@Url url: String,
|
||||
@Body body: AllHistoricalVotesRequest
|
||||
): SubQueryResponse<AllVotesResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getDirectHistoricalVotes(
|
||||
@Url url: String,
|
||||
@Body body: DirectHistoricalVotesRequest
|
||||
): SubQueryResponse<DirectVotesResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumVoters(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumVotersRequest
|
||||
): SubQueryResponse<ReferendumVotersResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumVotes(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumVotesRequest
|
||||
): SubQueryResponse<ReferendumVotesResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumAbstainVoters(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumSplitAbstainVotersRequest
|
||||
): SubQueryResponse<ReferendumSplitAbstainVotersResponse>
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.RecentVotesDateThreshold
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.common.createSubqueryFilter
|
||||
|
||||
class AllHistoricalVotesRequest(address: String) {
|
||||
|
||||
val query = """
|
||||
query {
|
||||
castingVotings(filter: { voter: {equalTo: "$address"}}) {
|
||||
nodes {
|
||||
referendumId
|
||||
standardVote
|
||||
splitVote
|
||||
splitAbstainVote
|
||||
}
|
||||
}
|
||||
|
||||
delegatorVotings(filter: {delegator: {equalTo: "$address"}}) {
|
||||
nodes {
|
||||
vote
|
||||
parent {
|
||||
referendumId
|
||||
delegateId
|
||||
standardVote
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
class DirectHistoricalVotesRequest(address: String, recentVotesDateThreshold: RecentVotesDateThreshold) {
|
||||
|
||||
val query = """
|
||||
query {
|
||||
castingVotings(filter: { and: { voter: {equalTo: "$address"}, ${recentVotesDateThreshold.createSubqueryFilter()}}}) {
|
||||
nodes {
|
||||
referendumId
|
||||
standardVote
|
||||
splitVote
|
||||
splitAbstainVote
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
class DelegateDelegatorsRequest(delegateAddress: String) {
|
||||
val query = """
|
||||
query {
|
||||
delegations(filter: {delegateId: {equalTo: "$delegateAddress" }}) {
|
||||
nodes {
|
||||
delegator
|
||||
delegation
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.RecentVotesDateThreshold
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.common.createSubqueryFilter
|
||||
|
||||
class DelegateDetailedStatsRequest(delegateAddress: String, recentVotesDateThreshold: RecentVotesDateThreshold) {
|
||||
val query = """
|
||||
query {
|
||||
delegates(filter: {accountId: {equalTo: "$delegateAddress"}}) {
|
||||
nodes {
|
||||
accountId
|
||||
delegators
|
||||
delegatorVotes
|
||||
allVotes: delegateVotes {
|
||||
totalCount
|
||||
}
|
||||
recentVotes: delegateVotes(filter: {${recentVotesDateThreshold.createSubqueryFilter()}}) {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.RecentVotesDateThreshold
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.common.createSubqueryFilter
|
||||
|
||||
class DelegateStatsByAddressesRequest(recentVotesDateThreshold: RecentVotesDateThreshold, val addresses: List<String>) {
|
||||
val query = """
|
||||
query {
|
||||
delegates(filter:{accountId:{in:[${getAddresses()}]}}) {
|
||||
totalCount
|
||||
nodes {
|
||||
accountId
|
||||
delegators
|
||||
delegatorVotes
|
||||
delegateVotes(filter: {${recentVotesDateThreshold.createSubqueryFilter()}}) {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
private fun getAddresses(): String {
|
||||
return addresses.joinToString { "\"$it\"" }
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.RecentVotesDateThreshold
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.common.createSubqueryFilter
|
||||
|
||||
class DelegateStatsRequest(recentVotesDateThreshold: RecentVotesDateThreshold) {
|
||||
val query = """
|
||||
query {
|
||||
delegates {
|
||||
totalCount
|
||||
nodes {
|
||||
accountId
|
||||
delegators
|
||||
delegatorVotes
|
||||
delegateVotes(filter: {${recentVotesDateThreshold.createSubqueryFilter()}}) {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumSplitAbstainVotersRequest(referendumId: BigInteger) {
|
||||
val query = """
|
||||
query {
|
||||
referendum(id:"$referendumId") {
|
||||
trackId
|
||||
castingVotings(filter: {splitAbstainVote: {isNull: false}}) {
|
||||
nodes {
|
||||
splitAbstainVote
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubqueryExpressions.anyOf
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumVotersRequest(referendumId: BigInteger, isAye: Boolean) {
|
||||
val query = """
|
||||
query {
|
||||
castingVotings(filter:{referendumId:{equalTo:"$referendumId"}, ${voteTypeFilter(isAye)}}) {
|
||||
nodes {
|
||||
voter
|
||||
standardVote
|
||||
splitVote
|
||||
splitAbstainVote
|
||||
delegateId
|
||||
delegatorVotes {
|
||||
nodes {
|
||||
delegator
|
||||
vote
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
private fun voteTypeFilter(isAye: Boolean): String {
|
||||
return anyOf(standardVoteFilter(isAye), splitVoteFilter(), splitAbstainVote())
|
||||
}
|
||||
|
||||
// we cannot filter JSON field by checking splitVote.ayeAmount > 0 so it should be done after request
|
||||
private fun splitVoteFilter(): String {
|
||||
return "splitVote: {isNull: false}"
|
||||
}
|
||||
|
||||
private fun splitAbstainVote(): String {
|
||||
return "splitAbstainVote: {isNull: false}"
|
||||
}
|
||||
|
||||
private fun standardVoteFilter(isAye: Boolean): String {
|
||||
return "standardVote: {contains: {aye: $isAye}}"
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumVotesRequest(referendumId: BigInteger) {
|
||||
val query = """
|
||||
query {
|
||||
referendum(id:"$referendumId") {
|
||||
trackId
|
||||
castingVotings {
|
||||
nodes {
|
||||
splitVote
|
||||
splitAbstainVote
|
||||
standardVote
|
||||
delegatorVotes {
|
||||
nodes {
|
||||
vote
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.common
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.RecentVotesDateThreshold
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
fun RecentVotesDateThreshold.createSubqueryFilter(): String {
|
||||
return when (this) {
|
||||
is RecentVotesDateThreshold.BlockNumber -> "at: {greaterThanOrEqualTo: ${number.toLong()}}"
|
||||
is RecentVotesDateThreshold.Timestamp -> "timestamp: {greaterThanOrEqualTo: ${timestampMs.milliseconds.inWholeSeconds}}"
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
import java.math.BigInteger
|
||||
|
||||
class AllVotesResponse(
|
||||
@SerializedName("castingVotings") val direct: SubQueryNodes<DirectVoteRemote>,
|
||||
@SerializedName("delegatorVotings") val delegated: SubQueryNodes<DelegatedVoteRemote>
|
||||
)
|
||||
|
||||
class DirectVotesResponse(
|
||||
@SerializedName("castingVotings") val direct: SubQueryNodes<DirectVoteRemote>,
|
||||
)
|
||||
|
||||
class DirectVoteRemote(
|
||||
val referendumId: BigInteger,
|
||||
override val standardVote: StandardVoteRemote?,
|
||||
override val splitVote: SplitVoteRemote?,
|
||||
override val splitAbstainVote: SplitAbstainVoteRemote?
|
||||
) : MultiVoteRemote
|
||||
|
||||
class DelegatedVoteRemote(
|
||||
val vote: VoteRemote,
|
||||
val parent: Parent
|
||||
) {
|
||||
|
||||
class Parent(
|
||||
val referendumId: BigInteger,
|
||||
val delegateId: String,
|
||||
val standardVote: StandardVoteRemote?
|
||||
)
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
|
||||
class DelegateDelegatorsResponse(
|
||||
val delegations: SubQueryNodes<DelegatorRemote>
|
||||
) {
|
||||
|
||||
class DelegatorRemote(
|
||||
@SerializedName("delegator") val address: String,
|
||||
val delegation: VoteRemote
|
||||
)
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryTotalCount
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
|
||||
class DelegateDetailedStatsResponse(
|
||||
val delegates: SubQueryNodes<Delegate>
|
||||
) {
|
||||
|
||||
class Delegate(
|
||||
val delegators: Int,
|
||||
val delegatorVotes: Balance,
|
||||
val recentVotes: SubQueryTotalCount,
|
||||
val allVotes: SubQueryTotalCount
|
||||
)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryTotalCount
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
|
||||
class DelegateStatsResponse(
|
||||
val delegates: SubQueryNodes<Delegate>
|
||||
) {
|
||||
|
||||
class Delegate(
|
||||
@SerializedName("accountId") val address: String,
|
||||
val delegators: Int,
|
||||
val delegatorVotes: Balance,
|
||||
val delegateVotes: SubQueryTotalCount
|
||||
)
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumSplitAbstainVotersResponse(
|
||||
val referendum: Referendum
|
||||
) {
|
||||
|
||||
class Referendum(val trackId: BigInteger, val castingVotings: SubQueryNodes<Voter>)
|
||||
|
||||
class Voter(
|
||||
val splitAbstainVote: SplitAbstainVoteRemote?
|
||||
)
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
|
||||
class ReferendumVotersResponse(
|
||||
@SerializedName("castingVotings") val voters: SubQueryNodes<ReferendumVoterRemote>
|
||||
)
|
||||
|
||||
class ReferendumVoterRemote(
|
||||
@SerializedName("voter") val voterId: String,
|
||||
val delegateId: String,
|
||||
override val standardVote: StandardVoteRemote?,
|
||||
override val splitVote: SplitVoteRemote?,
|
||||
override val splitAbstainVote: SplitAbstainVoteRemote?,
|
||||
val delegatorVotes: SubQueryNodes<ReferendumDelegatorVoteRemote>
|
||||
) : MultiVoteRemote
|
||||
|
||||
class ReferendumDelegatorVoteRemote(
|
||||
@SerializedName("delegator") val delegatorId: String,
|
||||
val vote: VoteRemote
|
||||
)
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumVotesResponse(
|
||||
val referendum: Referendum
|
||||
) {
|
||||
|
||||
class Referendum(val trackId: BigInteger, val castingVotings: SubQueryNodes<Vote>)
|
||||
|
||||
class Vote(
|
||||
override val standardVote: StandardVoteRemote?,
|
||||
override val splitVote: SplitVoteRemote?,
|
||||
override val splitAbstainVote: SplitAbstainVoteRemote?,
|
||||
val delegatorVotes: SubQueryNodes<DelegatorVote>
|
||||
) : MultiVoteRemote
|
||||
|
||||
class DelegatorVote(
|
||||
val vote: VoteRemote
|
||||
)
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.AccountVote
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Vote
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.mapConvictionFromString
|
||||
import java.math.BigInteger
|
||||
|
||||
class StandardVoteRemote(val aye: Boolean, val vote: VoteRemote)
|
||||
|
||||
class SplitVoteRemote(val ayeAmount: Balance, val nayAmount: Balance)
|
||||
|
||||
class SplitAbstainVoteRemote(val ayeAmount: Balance, val nayAmount: Balance, val abstainAmount: Balance)
|
||||
|
||||
interface MultiVoteRemote {
|
||||
|
||||
val standardVote: StandardVoteRemote?
|
||||
|
||||
val splitVote: SplitVoteRemote?
|
||||
|
||||
val splitAbstainVote: SplitAbstainVoteRemote?
|
||||
}
|
||||
|
||||
fun mapMultiVoteRemoteToAccountVote(vote: MultiVoteRemote): AccountVote {
|
||||
val standard = vote.standardVote
|
||||
val split = vote.splitVote
|
||||
val splitAbstain = vote.splitAbstainVote
|
||||
|
||||
return when {
|
||||
standard != null -> AccountVote.Standard(
|
||||
balance = standard.vote.amount,
|
||||
vote = Vote(
|
||||
aye = standard.aye,
|
||||
conviction = mapConvictionFromString(standard.vote.conviction)
|
||||
)
|
||||
)
|
||||
split != null -> AccountVote.Split(
|
||||
aye = split.ayeAmount,
|
||||
nay = split.nayAmount
|
||||
)
|
||||
splitAbstain != null -> AccountVote.SplitAbstain(
|
||||
aye = splitAbstain.ayeAmount,
|
||||
nay = splitAbstain.nayAmount,
|
||||
abstain = splitAbstain.abstainAmount
|
||||
)
|
||||
else -> AccountVote.Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
class VoteRemote(val amount: BigInteger, val conviction: String)
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1
|
||||
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ParachainReferendumDetailsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ReferendumDetailsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ParachainReferendumPreviewRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ReferendumPreviewRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response.ParachainReferendaPreviewResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response.ReferendaPreviewResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response.ReferendumDetailsResponse
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface PolkassemblyV1Api {
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumPreviews(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumPreviewRequest
|
||||
): SubQueryResponse<ReferendaPreviewResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getParachainReferendumPreviews(
|
||||
@Url url: String,
|
||||
@Body body: ParachainReferendumPreviewRequest
|
||||
): SubQueryResponse<ParachainReferendaPreviewResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumDetails(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumDetailsRequest
|
||||
): SubQueryResponse<ReferendumDetailsResponse>
|
||||
|
||||
@POST
|
||||
suspend fun getParachainReferendumDetails(
|
||||
@Url url: String,
|
||||
@Body body: ParachainReferendumDetailsRequest
|
||||
): SubQueryResponse<ReferendumDetailsResponse>
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1
|
||||
|
||||
import io.novafoundation.nova.common.utils.formatting.parseDateISO_8601
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumPreview
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.details.ReferendumTimeline
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.OffChainReferendaDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ParachainReferendumDetailsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ParachainReferendumPreviewRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ReferendumDetailsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request.ReferendumPreviewRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response.ParachainReferendaPreviewResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response.ReferendaPreviewResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response.ReferendumDetailsResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response.getId
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.ExternalApi.GovernanceReferenda.Source
|
||||
|
||||
class PolkassemblyV1ReferendaDataSource(
|
||||
private val polkassemblyApi: PolkassemblyV1Api,
|
||||
) : OffChainReferendaDataSource<Source.Polkassembly> {
|
||||
|
||||
override suspend fun referendumPreviews(baseUrl: String, options: Source.Polkassembly): List<OffChainReferendumPreview> {
|
||||
val polkassemblyNetwork = options.network
|
||||
|
||||
return if (polkassemblyNetwork == null) {
|
||||
referendaRelaychainRequest(baseUrl)
|
||||
} else {
|
||||
referendaParachainRequest(baseUrl, polkassemblyNetwork)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun referendumDetails(referendumId: ReferendumId, baseUrl: String, options: Source.Polkassembly): OffChainReferendumDetails? {
|
||||
val polkassemblyNetwork = options.network
|
||||
|
||||
val referendumDetails = if (polkassemblyNetwork == null) {
|
||||
detailsRelaychain(baseUrl, referendumId)
|
||||
} else {
|
||||
detailsParachain(baseUrl, polkassemblyNetwork, referendumId)
|
||||
}
|
||||
|
||||
return referendumDetails?.let(::mapPolkassemblyPostToDetails)
|
||||
}
|
||||
|
||||
private suspend fun referendaRelaychainRequest(url: String): List<OffChainReferendumPreview> {
|
||||
val request = ReferendumPreviewRequest()
|
||||
val response = polkassemblyApi.getReferendumPreviews(url, request)
|
||||
return response.data.posts.map {
|
||||
mapPolkassemblyPostToPreview(it)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun referendaParachainRequest(url: String, network: String): List<OffChainReferendumPreview> {
|
||||
val request = ParachainReferendumPreviewRequest(network)
|
||||
val response = polkassemblyApi.getParachainReferendumPreviews(url, request)
|
||||
return response.data.posts.map {
|
||||
mapParachainPolkassemblyPostToPreview(it)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun detailsRelaychain(url: String, referendumId: ReferendumId): ReferendumDetailsResponse.Post? {
|
||||
val request = ReferendumDetailsRequest(referendumId.value)
|
||||
val response = polkassemblyApi.getReferendumDetails(url, request)
|
||||
return response.data.posts.firstOrNull()
|
||||
}
|
||||
|
||||
private suspend fun detailsParachain(url: String, network: String, referendumId: ReferendumId): ReferendumDetailsResponse.Post? {
|
||||
val request = ParachainReferendumDetailsRequest(network, referendumId.value)
|
||||
val response = polkassemblyApi.getParachainReferendumDetails(url, request)
|
||||
return response.data.posts.firstOrNull()
|
||||
}
|
||||
|
||||
private fun mapPolkassemblyPostToPreview(post: ReferendaPreviewResponse.Post): OffChainReferendumPreview {
|
||||
return OffChainReferendumPreview(
|
||||
post.title,
|
||||
ReferendumId(post.getId()),
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapParachainPolkassemblyPostToPreview(post: ParachainReferendaPreviewResponse.Post): OffChainReferendumPreview {
|
||||
return OffChainReferendumPreview(
|
||||
post.title,
|
||||
ReferendumId(post.getId()),
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapPolkassemblyPostToDetails(post: ReferendumDetailsResponse.Post): OffChainReferendumDetails {
|
||||
val timeline = post.onchainLink
|
||||
?.onchainReferendum
|
||||
?.getOrNull(0)
|
||||
?.referendumStatus
|
||||
?.map {
|
||||
mapReferendumStatusToTimelineEntry(it)
|
||||
}
|
||||
|
||||
return OffChainReferendumDetails(
|
||||
title = post.title,
|
||||
description = post.content,
|
||||
proposerName = null, // author of the post on PA might not be equal to on-chain submitter so we want to be safe here
|
||||
proposerAddress = post.onchainLink?.proposerAddress,
|
||||
timeLine = timeline
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapReferendumStatusToTimelineEntry(status: ReferendumDetailsResponse.Status): ReferendumTimeline.Entry {
|
||||
val timelineState = when (status.status) {
|
||||
"Started" -> ReferendumTimeline.State.CREATED
|
||||
"Passed" -> ReferendumTimeline.State.APPROVED
|
||||
"NotPassed" -> ReferendumTimeline.State.REJECTED
|
||||
"Executed" -> ReferendumTimeline.State.EXECUTED
|
||||
else -> error("Unkonown referendum status")
|
||||
}
|
||||
|
||||
val statusDate = parseDateISO_8601(status.blockNumber.startDateTime)
|
||||
|
||||
return ReferendumTimeline.Entry(timelineState, statusDate?.time)
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ParachainReferendumDetailsRequest(network: String, id: BigInteger) {
|
||||
val query = """
|
||||
query {
|
||||
posts(
|
||||
where: {onchain_link: {onchain_network_referendum_id: {_eq: "${network}_$id"}}}
|
||||
) {
|
||||
title
|
||||
content
|
||||
author {
|
||||
username
|
||||
}
|
||||
onchain_link {
|
||||
onchain_referendum {
|
||||
referendumStatus {
|
||||
blockNumber {
|
||||
startDateTime
|
||||
number
|
||||
}
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request
|
||||
|
||||
class ParachainReferendumPreviewRequest(networkName: String?) {
|
||||
val query = """
|
||||
query {
|
||||
posts(
|
||||
where: {type: {id: {_eq: 2}}, network: {_eq: $networkName}, onchain_link: {onchain_network_referendum_id: {_is_null: false}}}
|
||||
) {
|
||||
title
|
||||
onchain_link {
|
||||
onchain_referendum {
|
||||
referendumId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumDetailsRequest(id: BigInteger) {
|
||||
val query = """
|
||||
query {
|
||||
posts(
|
||||
where: {onchain_link: {onchain_referendum_id: {_eq: $id}}}
|
||||
) {
|
||||
title
|
||||
content
|
||||
author {
|
||||
username
|
||||
}
|
||||
onchain_link {
|
||||
onchain_referendum {
|
||||
referendumStatus {
|
||||
blockNumber {
|
||||
startDateTime
|
||||
number
|
||||
}
|
||||
status
|
||||
}
|
||||
}
|
||||
proposer_address
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.request
|
||||
|
||||
class ReferendumPreviewRequest {
|
||||
val query = """
|
||||
query {
|
||||
posts(
|
||||
where: {type: {id: {_eq: 2}}, onchain_link: {onchain_referendum_id: {_is_null: false}}}
|
||||
) {
|
||||
title
|
||||
onchain_link {
|
||||
onchain_referendum_id
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.math.BigInteger
|
||||
|
||||
class ParachainReferendaPreviewResponse(
|
||||
val posts: List<Post>
|
||||
) {
|
||||
|
||||
class Post(
|
||||
val title: String?,
|
||||
@SerializedName("onchain_link") val onChainLink: OnChainLink
|
||||
)
|
||||
|
||||
class OnChainLink(
|
||||
@SerializedName("onchain_referendum") val onChainReferendum: List<OnChainReferendum>
|
||||
)
|
||||
|
||||
class OnChainReferendum(
|
||||
val referendumId: BigInteger
|
||||
)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendaPreviewResponse(
|
||||
val posts: List<Post>
|
||||
) {
|
||||
|
||||
class Post(
|
||||
val title: String?,
|
||||
@SerializedName("onchain_link") val onChainLink: OnChainLink
|
||||
)
|
||||
|
||||
class OnChainLink(
|
||||
@SerializedName("onchain_referendum_id") val onChainReferendumId: BigInteger,
|
||||
)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
fun ParachainReferendaPreviewResponse.Post.getId(): BigInteger {
|
||||
return onChainLink.onChainReferendum[0].referendumId
|
||||
}
|
||||
|
||||
fun ReferendaPreviewResponse.Post.getId(): BigInteger {
|
||||
return onChainLink.onChainReferendumId
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumDetailsResponse(
|
||||
val posts: List<Post>
|
||||
) {
|
||||
|
||||
class Post(
|
||||
val title: String?,
|
||||
val content: String,
|
||||
val author: Author,
|
||||
@SerializedName("onchain_link") val onchainLink: OnChainLink?
|
||||
)
|
||||
|
||||
class Author(val username: String)
|
||||
|
||||
class OnChainLink(
|
||||
@SerializedName("onchain_referendum") val onchainReferendum: List<OnChainReferendum>?,
|
||||
@SerializedName("proposer_address") val proposerAddress: String,
|
||||
)
|
||||
|
||||
class OnChainReferendum(
|
||||
val referendumStatus: List<Status>
|
||||
)
|
||||
|
||||
class Status(
|
||||
val blockNumber: BlockNumber,
|
||||
val status: String
|
||||
)
|
||||
|
||||
class BlockNumber(
|
||||
val startDateTime: String,
|
||||
val number: BigInteger
|
||||
)
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2
|
||||
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.request.ReferendumDetailsV2Request
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.request.ReferendumPreviewV2Request
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.response.ReferendaPreviewV2Response
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.response.ReferendumDetailsV2Response
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface PolkassemblyV2Api {
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumPreviews(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumPreviewV2Request
|
||||
): SubQueryResponse<ReferendaPreviewV2Response>
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumDetails(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumDetailsV2Request
|
||||
): SubQueryResponse<ReferendumDetailsV2Response>
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2
|
||||
|
||||
import io.novafoundation.nova.common.utils.formatting.parseDateISO_8601
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumPreview
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.details.ReferendumTimeline
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.OffChainReferendaDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.request.ReferendumDetailsV2Request
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.request.ReferendumPreviewV2Request
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.response.ReferendaPreviewV2Response
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.response.ReferendumDetailsV2Response
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.ExternalApi.GovernanceReferenda.Source
|
||||
|
||||
class PolkassemblyV2ReferendaDataSource(
|
||||
private val polkassemblyApi: PolkassemblyV2Api
|
||||
) : OffChainReferendaDataSource<Source.Polkassembly> {
|
||||
|
||||
override suspend fun referendumPreviews(baseUrl: String, options: Source.Polkassembly): List<OffChainReferendumPreview> {
|
||||
val request = ReferendumPreviewV2Request()
|
||||
val response = polkassemblyApi.getReferendumPreviews(baseUrl, request)
|
||||
|
||||
return response.data.posts.map(::mapPolkassemblyPostToPreview)
|
||||
}
|
||||
|
||||
override suspend fun referendumDetails(referendumId: ReferendumId, baseUrl: String, options: Source.Polkassembly): OffChainReferendumDetails? {
|
||||
val request = ReferendumDetailsV2Request(referendumId.value)
|
||||
val response = polkassemblyApi.getReferendumDetails(baseUrl, request)
|
||||
val referendumDetails = response.data.posts.firstOrNull()
|
||||
|
||||
return referendumDetails?.let(::mapPolkassemblyPostToDetails)
|
||||
}
|
||||
|
||||
private fun mapPolkassemblyPostToPreview(post: ReferendaPreviewV2Response.Post): OffChainReferendumPreview {
|
||||
return OffChainReferendumPreview(
|
||||
title = post.title,
|
||||
referendumId = ReferendumId(post.onChainLink.onChainReferendumId),
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapPolkassemblyPostToDetails(post: ReferendumDetailsV2Response.Post): OffChainReferendumDetails {
|
||||
val timeline = post.onchainLink.onchainReferendum
|
||||
.firstOrNull()
|
||||
?.referendumStatus
|
||||
?.mapNotNull {
|
||||
mapReferendumStatusToTimelineEntry(it)
|
||||
}
|
||||
|
||||
return OffChainReferendumDetails(
|
||||
title = post.title,
|
||||
description = post.content,
|
||||
proposerAddress = null,
|
||||
proposerName = post.author.username,
|
||||
timeLine = timeline
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapReferendumStatusToTimelineEntry(status: ReferendumDetailsV2Response.Status): ReferendumTimeline.Entry? {
|
||||
val timelineState = when (status.status) {
|
||||
"Submitted" -> ReferendumTimeline.State.CREATED
|
||||
"Ongoing" -> ReferendumTimeline.State.CREATED
|
||||
"Approved" -> ReferendumTimeline.State.APPROVED
|
||||
"Rejected" -> ReferendumTimeline.State.REJECTED
|
||||
"Cancelled" -> ReferendumTimeline.State.CANCELLED
|
||||
"TimedOut" -> ReferendumTimeline.State.TIMED_OUT
|
||||
"Killed" -> ReferendumTimeline.State.KILLED
|
||||
"Executed" -> ReferendumTimeline.State.EXECUTED
|
||||
else -> null
|
||||
}
|
||||
|
||||
val statusDate = parseDateISO_8601(status.blockNumber.startDateTime)
|
||||
|
||||
return timelineState?.let {
|
||||
ReferendumTimeline.Entry(timelineState, statusDate?.time)
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.request
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumDetailsV2Request(id: BigInteger) {
|
||||
val query = """
|
||||
query {
|
||||
posts(
|
||||
where: {onchain_link: {onchain_referendumv2_id: {_eq: $id}}}
|
||||
) {
|
||||
title
|
||||
content
|
||||
author {
|
||||
username
|
||||
}
|
||||
onchain_link {
|
||||
onchain_referendumv2 {
|
||||
referendumStatus {
|
||||
blockNumber {
|
||||
startDateTime
|
||||
number
|
||||
}
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.request
|
||||
|
||||
class ReferendumPreviewV2Request {
|
||||
val query = """
|
||||
query {
|
||||
posts(
|
||||
where: {onchain_link: {onchain_referendumv2_id: {_is_null: false}}}
|
||||
) {
|
||||
title
|
||||
onchain_link {
|
||||
onchain_referendumv2_id
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendaPreviewV2Response(
|
||||
val posts: List<Post>
|
||||
) {
|
||||
|
||||
class Post(
|
||||
val title: String?,
|
||||
@SerializedName("onchain_link") val onChainLink: OnChainLink
|
||||
)
|
||||
|
||||
class OnChainLink(@SerializedName("onchain_referendumv2_id") val onChainReferendumId: BigInteger)
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v2.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumDetailsV2Response(
|
||||
val posts: List<Post>
|
||||
) {
|
||||
|
||||
class Post(
|
||||
val title: String?,
|
||||
val content: String,
|
||||
val author: Author,
|
||||
@SerializedName("onchain_link") val onchainLink: OnChainLink
|
||||
)
|
||||
|
||||
class Author(val username: String)
|
||||
|
||||
class OnChainLink(
|
||||
@SerializedName("onchain_referendumv2") val onchainReferendum: List<OnChainReferendum>
|
||||
)
|
||||
|
||||
class OnChainReferendum(
|
||||
val referendumStatus: List<Status>
|
||||
)
|
||||
|
||||
class Status(
|
||||
val blockNumber: BlockNumber,
|
||||
val status: String
|
||||
)
|
||||
|
||||
class BlockNumber(
|
||||
val startDateTime: String,
|
||||
val number: BigInteger
|
||||
)
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1
|
||||
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1.response.ReferendaPreviewV1Response
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1.response.ReferendumDetailsV1Response
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface SubSquareV1Api {
|
||||
|
||||
@GET
|
||||
suspend fun getReferendumPreviews(
|
||||
@Url url: String,
|
||||
@Query("page_size") pageSize: Int = 1000
|
||||
): ReferendaPreviewV1Response
|
||||
|
||||
@GET
|
||||
suspend fun getReferendumDetails(@Url url: String): ReferendumDetailsV1Response
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1
|
||||
|
||||
import io.novafoundation.nova.common.utils.ensureSuffix
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumPreview
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.details.ReferendumTimeline
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.OffChainReferendaDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1.response.ReferendaPreviewV1Response
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1.response.ReferendumDetailsV1Response
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.ExternalApi.GovernanceReferenda.Source
|
||||
|
||||
class SubSquareV1ReferendaDataSource(
|
||||
private val subSquareApi: SubSquareV1Api,
|
||||
) : OffChainReferendaDataSource<Source.SubSquare> {
|
||||
|
||||
override suspend fun referendumPreviews(baseUrl: String, options: Source.SubSquare): List<OffChainReferendumPreview> {
|
||||
val fullUrl = previewsUrlOf(baseUrl)
|
||||
|
||||
val response = subSquareApi.getReferendumPreviews(fullUrl)
|
||||
|
||||
return response.items.map(::mapReferendumPreviewResponseToPreview)
|
||||
}
|
||||
|
||||
override suspend fun referendumDetails(referendumId: ReferendumId, baseUrl: String, options: Source.SubSquare): OffChainReferendumDetails? {
|
||||
val fullUrl = detailsUrlOf(baseUrl, referendumId)
|
||||
|
||||
val response = subSquareApi.getReferendumDetails(fullUrl)
|
||||
|
||||
return mapReferendumDetailsResponseToDetails(response)
|
||||
}
|
||||
|
||||
private fun mapReferendumPreviewResponseToPreview(post: ReferendaPreviewV1Response.Referendum): OffChainReferendumPreview {
|
||||
return OffChainReferendumPreview(
|
||||
title = post.title,
|
||||
referendumId = ReferendumId(post.referendumIndex),
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapReferendumDetailsResponseToDetails(referendum: ReferendumDetailsV1Response): OffChainReferendumDetails {
|
||||
val timeline = referendum.onchainData.timeline.mapNotNull(::mapReferendumStatusToTimelineEntry)
|
||||
|
||||
return OffChainReferendumDetails(
|
||||
title = referendum.title,
|
||||
description = referendum.content,
|
||||
proposerAddress = referendum.author?.address,
|
||||
proposerName = referendum.author?.username,
|
||||
timeLine = timeline
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapReferendumStatusToTimelineEntry(status: ReferendumDetailsV1Response.Status): ReferendumTimeline.Entry? {
|
||||
val timelineState = when (status.method) {
|
||||
"Started" -> ReferendumTimeline.State.CREATED
|
||||
"Passed" -> ReferendumTimeline.State.APPROVED
|
||||
"NotPassed" -> ReferendumTimeline.State.REJECTED
|
||||
"Executed" -> ReferendumTimeline.State.EXECUTED
|
||||
else -> null
|
||||
}
|
||||
|
||||
return timelineState?.let {
|
||||
ReferendumTimeline.Entry(timelineState, status.indexer.blockTime)
|
||||
}
|
||||
}
|
||||
|
||||
private fun previewsUrlOf(baseUrl: String) = baseUrl.ensureSuffix("/") + "democracy/referendums"
|
||||
|
||||
private fun detailsUrlOf(baseUrl: String, referendumId: ReferendumId) = baseUrl.ensureSuffix("/") + "democracy/referendums/${referendumId.value}"
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1.response
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendaPreviewV1Response(
|
||||
val items: List<Referendum>
|
||||
) {
|
||||
|
||||
class Referendum(
|
||||
val title: String?,
|
||||
val referendumIndex: BigInteger
|
||||
)
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1.response
|
||||
|
||||
class ReferendumDetailsV1Response(
|
||||
val title: String?,
|
||||
val content: String?,
|
||||
val author: Author?,
|
||||
val onchainData: OnChainData
|
||||
) {
|
||||
|
||||
class Author(val username: String?, val address: String?)
|
||||
|
||||
class OnChainData(val timeline: List<Status>)
|
||||
|
||||
class Status(
|
||||
val indexer: IndexerState,
|
||||
val method: String
|
||||
)
|
||||
|
||||
class IndexerState(
|
||||
val blockTime: Long
|
||||
)
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2
|
||||
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2.response.ReferendaPreviewV2Response
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2.response.ReferendumDetailsV2Response
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface SubSquareV2Api {
|
||||
|
||||
@GET
|
||||
suspend fun getReferendumPreviews(
|
||||
@Url url: String,
|
||||
@Query("page_size") pageSize: Int = 100
|
||||
): ReferendaPreviewV2Response
|
||||
|
||||
@GET
|
||||
suspend fun getReferendumDetails(@Url url: String): ReferendumDetailsV2Response
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2
|
||||
|
||||
import io.novafoundation.nova.common.utils.ensureSuffix
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumPreview
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.details.ReferendumTimeline
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.OffChainReferendaDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2.response.ReferendaPreviewV2Response
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2.response.ReferendumDetailsV2Response
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.ExternalApi.GovernanceReferenda.Source
|
||||
|
||||
class SubSquareV2ReferendaDataSource(
|
||||
private val subSquareApi: SubSquareV2Api
|
||||
) : OffChainReferendaDataSource<Source.SubSquare> {
|
||||
|
||||
override suspend fun referendumPreviews(baseUrl: String, options: Source.SubSquare): List<OffChainReferendumPreview> {
|
||||
val fullUrl = previewsUrlOf(baseUrl)
|
||||
|
||||
val response = subSquareApi.getReferendumPreviews(fullUrl)
|
||||
|
||||
return response.items.map(::mapPolkassemblyPostToPreview)
|
||||
}
|
||||
|
||||
override suspend fun referendumDetails(referendumId: ReferendumId, baseUrl: String, options: Source.SubSquare): OffChainReferendumDetails {
|
||||
val detailsUrl = detailsUrlOf(baseUrl, referendumId)
|
||||
val referendaDetails = subSquareApi.getReferendumDetails(detailsUrl)
|
||||
|
||||
return mapPolkassemblyPostToDetails(referendaDetails)
|
||||
}
|
||||
|
||||
private fun mapPolkassemblyPostToPreview(post: ReferendaPreviewV2Response.Referendum): OffChainReferendumPreview {
|
||||
return OffChainReferendumPreview(
|
||||
title = post.title,
|
||||
referendumId = ReferendumId(post.referendumIndex),
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapPolkassemblyPostToDetails(
|
||||
referendum: ReferendumDetailsV2Response
|
||||
): OffChainReferendumDetails {
|
||||
val timeline = referendum.onchainData.timeline.mapNotNull(::mapReferendumStatusToTimelineEntry)
|
||||
|
||||
return OffChainReferendumDetails(
|
||||
title = referendum.title,
|
||||
description = referendum.content,
|
||||
proposerAddress = referendum.author?.address,
|
||||
proposerName = referendum.author?.username,
|
||||
timeLine = timeline
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapReferendumStatusToTimelineEntry(status: ReferendumDetailsV2Response.Status): ReferendumTimeline.Entry? {
|
||||
val timelineState = when (status.name) {
|
||||
"Submitted" -> ReferendumTimeline.State.CREATED
|
||||
"Confirmed" -> ReferendumTimeline.State.APPROVED
|
||||
"Rejected" -> ReferendumTimeline.State.REJECTED
|
||||
"Cancelled" -> ReferendumTimeline.State.CANCELLED
|
||||
"TimedOut" -> ReferendumTimeline.State.TIMED_OUT
|
||||
"Killed" -> ReferendumTimeline.State.KILLED
|
||||
else -> null
|
||||
}
|
||||
|
||||
return timelineState?.let {
|
||||
ReferendumTimeline.Entry(timelineState, status.indexer.blockTime)
|
||||
}
|
||||
}
|
||||
|
||||
private fun previewsUrlOf(baseUrl: String) = baseUrl.ensureSuffix("/") + "gov2/referendums"
|
||||
|
||||
private fun detailsUrlOf(baseUrl: String, referendumId: ReferendumId) = baseUrl.ensureSuffix("/") + "gov2/referendums/${referendumId.value}"
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2.response
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendaPreviewV2Response(
|
||||
val items: List<Referendum>
|
||||
) {
|
||||
|
||||
class Referendum(
|
||||
val title: String?,
|
||||
val referendumIndex: BigInteger
|
||||
)
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2.response
|
||||
|
||||
class ReferendumDetailsV2Response(
|
||||
val title: String?,
|
||||
val content: String?,
|
||||
val author: Author?,
|
||||
val onchainData: OnChainData
|
||||
) {
|
||||
|
||||
class Author(val username: String?, val address: String?)
|
||||
|
||||
class OnChainData(val timeline: List<Status>)
|
||||
|
||||
class Status(
|
||||
val indexer: IndexerState,
|
||||
val name: String
|
||||
)
|
||||
|
||||
class IndexerState(
|
||||
val blockTime: Long
|
||||
)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v2.response
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
class ReferendumVoteV2Response(
|
||||
val isSplitAbstain: Boolean,
|
||||
val abstainVotes: BigInteger?
|
||||
)
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2
|
||||
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.request.ReferendumSummariesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.response.ReferendumSummaryResponse
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface ReferendumSummaryApi {
|
||||
|
||||
@POST
|
||||
suspend fun getReferendumSummaries(
|
||||
@Url url: String,
|
||||
@Body body: ReferendumSummariesRequest
|
||||
): List<ReferendumSummaryResponse>
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.request.ReferendumSummariesRequest
|
||||
import io.novafoundation.nova.runtime.ext.summaryApiOrNull
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
|
||||
interface ReferendumSummaryDataSource {
|
||||
|
||||
suspend fun loadSummaries(chain: Chain, ids: List<ReferendumId>, languageCode: String): Map<ReferendumId, String>?
|
||||
}
|
||||
|
||||
class RealReferendumSummaryDataSource(
|
||||
val api: ReferendumSummaryApi
|
||||
) : ReferendumSummaryDataSource {
|
||||
|
||||
override suspend fun loadSummaries(chain: Chain, ids: List<ReferendumId>, languageCode: String): Map<ReferendumId, String>? {
|
||||
val summaryApi = chain.summaryApiOrNull() ?: return null
|
||||
|
||||
val response = api.getReferendumSummaries(
|
||||
summaryApi.url,
|
||||
ReferendumSummariesRequest(
|
||||
chainId = chain.id,
|
||||
languageIsoCode = languageCode,
|
||||
referendumIds = ids.map { it.value.toString() }
|
||||
)
|
||||
)
|
||||
|
||||
return response.associateBy { ReferendumId(it.referendumId.toBigInteger()) }
|
||||
.mapValues { it.value.summary }
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.request
|
||||
|
||||
class ReferendumSummariesRequest(
|
||||
val chainId: String,
|
||||
val languageIsoCode: String,
|
||||
val referendumIds: List<String>
|
||||
)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.response
|
||||
|
||||
class ReferendumSummaryResponse(val referendumId: Int, val summary: String)
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.preimage
|
||||
|
||||
import io.novafoundation.nova.common.utils.kilobytes
|
||||
import java.math.BigInteger
|
||||
|
||||
interface PreImageSizer {
|
||||
|
||||
enum class SizeConstraint {
|
||||
SMALL
|
||||
}
|
||||
|
||||
fun satisfiesSizeConstraint(preImageSize: BigInteger, constraint: SizeConstraint): Boolean
|
||||
}
|
||||
|
||||
class RealPreImageSizer : PreImageSizer {
|
||||
|
||||
override fun satisfiesSizeConstraint(preImageSize: BigInteger, constraint: PreImageSizer.SizeConstraint): Boolean {
|
||||
return preImageSize < constraint.threshold
|
||||
}
|
||||
|
||||
private val PreImageSizer.SizeConstraint.threshold: BigInteger
|
||||
get() = when (this) {
|
||||
PreImageSizer.SizeConstraint.SMALL -> 1.kilobytes
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumPreview
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.OffChainReferendaInfoRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.OffChainReferendaDataSource
|
||||
import io.novafoundation.nova.runtime.ext.externalApi
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.ExternalApi.GovernanceReferenda.Source
|
||||
|
||||
class MultiSourceOffChainReferendaInfoRepository(
|
||||
private val subSquareReferendaDataSource: OffChainReferendaDataSource<Source.SubSquare>,
|
||||
private val polkassemblyReferendaDataSource: OffChainReferendaDataSource<Source.Polkassembly>
|
||||
) : OffChainReferendaInfoRepository {
|
||||
|
||||
override suspend fun referendumPreviews(chain: Chain): List<OffChainReferendumPreview> {
|
||||
return runCatching {
|
||||
val dataSource = chain.carriedGovernanceDataSource() ?: return emptyList()
|
||||
|
||||
dataSource.referendumPreviews()
|
||||
}.getOrDefault(emptyList())
|
||||
}
|
||||
|
||||
override suspend fun referendumDetails(referendumId: ReferendumId, chain: Chain): OffChainReferendumDetails? {
|
||||
return runCatching {
|
||||
val dataSource = chain.carriedGovernanceDataSource() ?: return null
|
||||
|
||||
dataSource.referendumDetails(referendumId)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private fun Chain.carriedGovernanceDataSource(): OffChainReferendaDataSourceCarried<*>? {
|
||||
val governanceApi = externalApi<Chain.ExternalApi.GovernanceReferenda>() ?: return null
|
||||
val baseUrl = governanceApi.url
|
||||
|
||||
return when (val source = governanceApi.source) {
|
||||
is Source.Polkassembly -> OffChainReferendaDataSourceCarried(polkassemblyReferendaDataSource, baseUrl, source)
|
||||
is Source.SubSquare -> OffChainReferendaDataSourceCarried(subSquareReferendaDataSource, baseUrl, source)
|
||||
}
|
||||
}
|
||||
|
||||
private class OffChainReferendaDataSourceCarried<O>(
|
||||
private val dataSource: OffChainReferendaDataSource<O>,
|
||||
private val baseUrl: String,
|
||||
private val options: O
|
||||
) {
|
||||
suspend fun referendumPreviews(): List<OffChainReferendumPreview> = dataSource.referendumPreviews(baseUrl, options)
|
||||
|
||||
suspend fun referendumDetails(referendumId: ReferendumId): OffChainReferendumDetails? = dataSource.referendumDetails(referendumId, baseUrl, options)
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository
|
||||
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindAccountId
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToStructOrNull
|
||||
import io.novafoundation.nova.common.utils.treasury
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TreasuryProposal
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.TreasuryRepository
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.storage
|
||||
|
||||
class RealTreasuryRepository(
|
||||
private val remoteSource: StorageDataSource
|
||||
) : TreasuryRepository {
|
||||
|
||||
override suspend fun getTreasuryProposal(chainId: ChainId, id: TreasuryProposal.Id): TreasuryProposal? {
|
||||
return remoteSource.query(chainId) {
|
||||
runtime.metadata.treasury().storage("Proposals").query(
|
||||
id.value,
|
||||
binding = { bindProposal(id, it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindProposal(id: TreasuryProposal.Id, decoded: Any?): TreasuryProposal? {
|
||||
val asStruct = decoded.castToStructOrNull() ?: return null
|
||||
|
||||
return TreasuryProposal(
|
||||
id = id,
|
||||
proposer = bindAccountId(asStruct["proposer"]),
|
||||
amount = bindNumber(asStruct["value"]),
|
||||
beneficiary = bindAccountId(asStruct["beneficiary"]),
|
||||
bond = bindNumber(asStruct["bond"])
|
||||
)
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository
|
||||
|
||||
import io.novafoundation.nova.common.data.storage.Preferences
|
||||
|
||||
interface RemoveVotesSuggestionRepository {
|
||||
|
||||
fun isAllowedToShowRemoveVotesSuggestion(): Boolean
|
||||
|
||||
suspend fun disallowShowRemoveVotesSuggestion()
|
||||
}
|
||||
|
||||
class RealRemoveVotesSuggestionRepository(
|
||||
private val preferences: Preferences
|
||||
) : RemoveVotesSuggestionRepository {
|
||||
|
||||
companion object {
|
||||
private const val PREFS_KEY = "RemoveVotesSuggestionRepository.ShouldShowSuggestion"
|
||||
|
||||
private const val ALLOWED_DEFAULT = true
|
||||
}
|
||||
|
||||
override fun isAllowedToShowRemoveVotesSuggestion(): Boolean {
|
||||
return preferences.getBoolean(PREFS_KEY, ALLOWED_DEFAULT)
|
||||
}
|
||||
|
||||
override suspend fun disallowShowRemoveVotesSuggestion() {
|
||||
preferences.putBoolean(PREFS_KEY, value = false)
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Delegation
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.delegation.DelegateDetailedStats
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.delegation.DelegateMetadata
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.delegation.DelegateStats
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.vote.UserVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.DelegationsRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.RecentVotesDateThreshold
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.runtime.extrinsic.multi.CallBuilder
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Conviction
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
|
||||
class UnsupportedDelegationsRepository : DelegationsRepository {
|
||||
|
||||
override suspend fun isDelegationSupported(chain: Chain): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override suspend fun getDelegatesStats(recentVotesBlockThreshold: RecentVotesDateThreshold, chain: Chain): List<DelegateStats> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun getDelegatesStatsByAccountIds(
|
||||
recentVotesBlockThreshold: RecentVotesDateThreshold,
|
||||
accountIds: List<AccountId>,
|
||||
chain: Chain
|
||||
): List<DelegateStats> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun getDetailedDelegateStats(
|
||||
delegateAddress: String,
|
||||
recentVotesDateThreshold: RecentVotesDateThreshold,
|
||||
chain: Chain
|
||||
): DelegateDetailedStats? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun getDelegatesMetadata(chain: Chain): List<DelegateMetadata> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun getDelegateMetadata(chain: Chain, delegate: AccountId): DelegateMetadata? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun getDelegationsTo(delegate: AccountId, chain: Chain): List<Delegation> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun allHistoricalVotesOf(user: AccountId, chain: Chain): Map<ReferendumId, UserVote>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun historicalVoteOf(user: AccountId, referendumId: ReferendumId, chain: Chain): UserVote? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun directHistoricalVotesOf(
|
||||
user: AccountId,
|
||||
chain: Chain,
|
||||
recentVotesDateThreshold: RecentVotesDateThreshold?
|
||||
): Map<ReferendumId, UserVote.Direct>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun CallBuilder.delegate(delegate: AccountId, trackId: TrackId, amount: Balance, conviction: Conviction) {
|
||||
error("Unsupported")
|
||||
}
|
||||
|
||||
override suspend fun CallBuilder.undelegate(trackId: TrackId) {
|
||||
error("Unsupported")
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.common
|
||||
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindAccountId
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindBlockNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindByteArray
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindCollectionEnum
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindList
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.cast
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToDictEnum
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToList
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.incompatible
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.AccountVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.PriorLock
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Proposal
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Tally
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Voting
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Conviction
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Vote
|
||||
import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.DictEnum
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.Struct
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.fromByteArray
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.GenericCall
|
||||
|
||||
fun bindProposal(decoded: Any?, runtimeSnapshot: RuntimeSnapshot): Proposal {
|
||||
return when (decoded) {
|
||||
is ByteArray -> bindProposalLegacy(decoded)
|
||||
is DictEnum.Entry<*> -> bindProposalBound(decoded, runtimeSnapshot)
|
||||
else -> incompatible()
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindProposalLegacy(decoded: ByteArray): Proposal {
|
||||
return Proposal.Legacy(decoded)
|
||||
}
|
||||
|
||||
private fun bindProposalBound(decoded: DictEnum.Entry<*>, runtime: RuntimeSnapshot): Proposal {
|
||||
return when (decoded.name) {
|
||||
"Legacy" -> {
|
||||
val valueAsStruct = decoded.value.castToStruct()
|
||||
Proposal.Legacy(bindByteArray(valueAsStruct["hash"]))
|
||||
}
|
||||
|
||||
"Inline" -> {
|
||||
val bytes = bindByteArray(decoded.value)
|
||||
val call = GenericCall.fromByteArray(runtime, bytes)
|
||||
|
||||
Proposal.Inline(bytes, call)
|
||||
}
|
||||
|
||||
"Lookup" -> {
|
||||
val valueAsStruct = decoded.value.castToStruct()
|
||||
|
||||
Proposal.Lookup(
|
||||
hash = bindByteArray(valueAsStruct["hash"]),
|
||||
callLength = bindNumber(valueAsStruct["len"])
|
||||
)
|
||||
}
|
||||
|
||||
else -> incompatible()
|
||||
}
|
||||
}
|
||||
|
||||
fun bindTally(decoded: Struct.Instance): Tally {
|
||||
return Tally(
|
||||
ayes = bindNumber(decoded["ayes"]),
|
||||
nays = bindNumber(decoded["nays"]),
|
||||
support = bindNumber(decoded["support"] ?: decoded["turnout"])
|
||||
)
|
||||
}
|
||||
|
||||
fun bindVoting(decoded: Any): Voting {
|
||||
decoded.castToDictEnum()
|
||||
|
||||
return when (decoded.name) {
|
||||
"Casting", "Direct" -> {
|
||||
val casting = decoded.value.castToStruct()
|
||||
|
||||
val votes = bindVotes(casting["votes"])
|
||||
val prior = bindPriorLock(casting["prior"])
|
||||
|
||||
Voting.Casting(votes, prior)
|
||||
}
|
||||
|
||||
"Delegating" -> {
|
||||
val delegating = decoded.value.castToStruct()
|
||||
|
||||
val balance = bindNumber(delegating["balance"])
|
||||
val target = bindAccountId(delegating["target"])
|
||||
val conviction = bindConvictionEnum(delegating["conviction"])
|
||||
val prior = bindPriorLock(delegating["prior"])
|
||||
|
||||
Voting.Delegating(balance, target, conviction, prior)
|
||||
}
|
||||
|
||||
else -> incompatible()
|
||||
}
|
||||
}
|
||||
|
||||
fun bindConvictionEnum(decoded: Any?): Conviction {
|
||||
return bindCollectionEnum(decoded) { name ->
|
||||
when (name) {
|
||||
"None" -> Conviction.None
|
||||
"Locked1x" -> Conviction.Locked1x
|
||||
"Locked2x" -> Conviction.Locked2x
|
||||
"Locked3x" -> Conviction.Locked3x
|
||||
"Locked4x" -> Conviction.Locked4x
|
||||
"Locked5x" -> Conviction.Locked5x
|
||||
"Locked6x" -> Conviction.Locked6x
|
||||
else -> incompatible()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindVotes(decoded: Any?): Map<ReferendumId, AccountVote> {
|
||||
return bindList(decoded) { item ->
|
||||
val (referendumId, accountVote) = item.castToList()
|
||||
|
||||
ReferendumId(bindNumber(referendumId)) to bindAccountVote(accountVote)
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun bindAccountVote(decoded: Any?): AccountVote {
|
||||
decoded.castToDictEnum()
|
||||
|
||||
return when (decoded.name) {
|
||||
"Standard" -> {
|
||||
val standardVote = decoded.value.castToStruct()
|
||||
|
||||
AccountVote.Standard(
|
||||
vote = bindVote(standardVote["vote"]),
|
||||
balance = bindNumber(standardVote["balance"])
|
||||
)
|
||||
}
|
||||
|
||||
"Split" -> {
|
||||
val splitVote = decoded.value.castToStruct()
|
||||
|
||||
AccountVote.Split(
|
||||
aye = bindNumber(splitVote["aye"]),
|
||||
nay = bindNumber(splitVote["nay"])
|
||||
)
|
||||
}
|
||||
|
||||
"SplitAbstain" -> {
|
||||
val splitVote = decoded.value.castToStruct()
|
||||
|
||||
AccountVote.SplitAbstain(
|
||||
aye = bindNumber(splitVote["aye"]),
|
||||
nay = bindNumber(splitVote["nay"]),
|
||||
abstain = bindNumber(splitVote["abstain"])
|
||||
)
|
||||
}
|
||||
|
||||
else -> AccountVote.Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindPriorLock(decoded: Any?): PriorLock {
|
||||
// 2-tuple
|
||||
val (unlockAt, amount) = decoded.castToList()
|
||||
|
||||
return PriorLock(
|
||||
unlockAt = bindBlockNumber(unlockAt),
|
||||
amount = bindNumber(amount)
|
||||
)
|
||||
}
|
||||
|
||||
private fun bindVote(decoded: Any?): Vote {
|
||||
return decoded.cast()
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.common
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.amountMultiplier
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumVotingDetails.VotingInfo
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.empty
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.plus
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.ReferendumVotesResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.SplitAbstainVoteRemote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.SplitVoteRemote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.StandardVoteRemote
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Conviction
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.mapConvictionFromString
|
||||
import java.math.BigDecimal
|
||||
|
||||
fun StandardVoteRemote?.toOffChainVotes(): VotingInfo.Full {
|
||||
if (this == null) return VotingInfo.Full.empty()
|
||||
|
||||
val conviction = mapConvictionFromString(this.vote.conviction)
|
||||
val amount = this.vote.amount.toBigDecimal() * conviction.amountMultiplier()
|
||||
return VotingInfo.Full(
|
||||
aye = if (this.aye) amount else BigDecimal.ZERO,
|
||||
nay = if (!this.aye) amount else BigDecimal.ZERO,
|
||||
abstain = BigDecimal.ZERO,
|
||||
support = this.vote.amount
|
||||
)
|
||||
}
|
||||
|
||||
fun SplitVoteRemote?.toOffChainVotes(): VotingInfo.Full {
|
||||
if (this == null) return VotingInfo.Full.empty()
|
||||
|
||||
val amountMultiplier = Conviction.None.amountMultiplier()
|
||||
|
||||
return VotingInfo.Full(
|
||||
aye = this.ayeAmount.toBigDecimal() * amountMultiplier,
|
||||
nay = this.nayAmount.toBigDecimal() * amountMultiplier,
|
||||
abstain = BigDecimal.ZERO,
|
||||
support = this.ayeAmount + this.nayAmount
|
||||
)
|
||||
}
|
||||
|
||||
fun SplitAbstainVoteRemote?.toOffChainVotes(): VotingInfo.Full {
|
||||
if (this == null) return VotingInfo.Full.empty()
|
||||
|
||||
val amountMultiplier = Conviction.None.amountMultiplier()
|
||||
|
||||
return VotingInfo.Full(
|
||||
aye = this.ayeAmount.toBigDecimal() * amountMultiplier,
|
||||
nay = this.nayAmount.toBigDecimal() * amountMultiplier,
|
||||
abstain = this.abstainAmount.toBigDecimal() * amountMultiplier,
|
||||
support = this.ayeAmount + this.nayAmount + this.abstainAmount
|
||||
)
|
||||
}
|
||||
|
||||
fun ReferendumVotesResponse.Vote.toOffChainVotes(): VotingInfo.Full {
|
||||
var delegatorsVoteSum = BigDecimal.ZERO
|
||||
var delegatorSupportSum = Balance.ZERO
|
||||
|
||||
this.delegatorVotes.nodes.forEach { delegatorVote ->
|
||||
val conviction = mapConvictionFromString(delegatorVote.vote.conviction)
|
||||
delegatorsVoteSum += delegatorVote.vote.amount.toBigDecimal() * conviction.amountMultiplier()
|
||||
delegatorSupportSum += delegatorVote.vote.amount
|
||||
}
|
||||
|
||||
return standardVote.toOffChainVotes() + splitVote.toOffChainVotes() + splitAbstainVote.toOffChainVotes() + getDelegationVotes()
|
||||
}
|
||||
|
||||
private fun ReferendumVotesResponse.Vote.getDelegationVotes(): VotingInfo.Full {
|
||||
return if (standardVote != null) {
|
||||
var delegatorsVoteSum = BigDecimal.ZERO
|
||||
var delegatorSupportSum = Balance.ZERO
|
||||
|
||||
this.delegatorVotes.nodes.forEach { delegatorVote ->
|
||||
val conviction = mapConvictionFromString(delegatorVote.vote.conviction)
|
||||
delegatorsVoteSum += delegatorVote.vote.amount.toBigDecimal() * conviction.amountMultiplier()
|
||||
delegatorSupportSum += delegatorVote.vote.amount
|
||||
}
|
||||
|
||||
return VotingInfo.Full(
|
||||
aye = if (standardVote.aye) delegatorsVoteSum else BigDecimal.ZERO,
|
||||
nay = if (!standardVote.aye) delegatorsVoteSum else BigDecimal.ZERO,
|
||||
abstain = BigDecimal.ZERO,
|
||||
support = delegatorSupportSum
|
||||
)
|
||||
} else {
|
||||
VotingInfo.Full.empty()
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.common
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumVoter
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Voting
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.votes
|
||||
import io.novafoundation.nova.runtime.storage.source.query.StorageKeyComponents
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
|
||||
fun Map<StorageKeyComponents, Voting?>.votersFor(referendumId: ReferendumId): List<ReferendumVoter> {
|
||||
return mapNotNull { (keyComponents, voting) ->
|
||||
val voterId = keyComponents.component1<AccountId>()
|
||||
val votes = voting?.votes()
|
||||
|
||||
votes?.get(referendumId)?.let { accountVote ->
|
||||
ReferendumVoter(
|
||||
accountId = voterId,
|
||||
vote = accountVote,
|
||||
delegators = emptyList()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.filters
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.filters.ReferendumType
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.filters.ReferendumTypeFilter
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
private const val PREF_REFERENDUM_TYPE_FILTER = "PREF_REFERENDUM_TYPE_FILTER"
|
||||
|
||||
interface ReferendaFiltersRepository {
|
||||
|
||||
fun getReferendumTypeFilter(): ReferendumTypeFilter
|
||||
|
||||
fun observeReferendumTypeFilter(): Flow<ReferendumTypeFilter>
|
||||
|
||||
fun updateReferendumTypeFilter(filter: ReferendumTypeFilter)
|
||||
}
|
||||
|
||||
class PreferencesReferendaFiltersRepository : ReferendaFiltersRepository {
|
||||
|
||||
private var referendumTypeFilter = MutableStateFlow(getDefaultReferendaTypeFilter())
|
||||
|
||||
override fun getReferendumTypeFilter(): ReferendumTypeFilter {
|
||||
return referendumTypeFilter.value
|
||||
}
|
||||
|
||||
override fun observeReferendumTypeFilter(): Flow<ReferendumTypeFilter> {
|
||||
return referendumTypeFilter
|
||||
}
|
||||
|
||||
override fun updateReferendumTypeFilter(filter: ReferendumTypeFilter) {
|
||||
referendumTypeFilter.value = filter
|
||||
}
|
||||
|
||||
private fun getDefaultReferendaTypeFilter(): ReferendumTypeFilter {
|
||||
return ReferendumTypeFilter(ReferendumType.ALL)
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.tindergov
|
||||
|
||||
import io.novafoundation.nova.core_db.model.common.ConvictionLocal
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Conviction
|
||||
|
||||
fun Conviction.toLocal() = when (this) {
|
||||
Conviction.None -> ConvictionLocal.NONE
|
||||
Conviction.Locked1x -> ConvictionLocal.LOCKED_1X
|
||||
Conviction.Locked2x -> ConvictionLocal.LOCKED_2X
|
||||
Conviction.Locked3x -> ConvictionLocal.LOCKED_3X
|
||||
Conviction.Locked4x -> ConvictionLocal.LOCKED_4X
|
||||
Conviction.Locked5x -> ConvictionLocal.LOCKED_5X
|
||||
Conviction.Locked6x -> ConvictionLocal.LOCKED_6X
|
||||
}
|
||||
|
||||
fun ConvictionLocal.toDomain() = when (this) {
|
||||
ConvictionLocal.NONE -> Conviction.None
|
||||
ConvictionLocal.LOCKED_1X -> Conviction.Locked1x
|
||||
ConvictionLocal.LOCKED_2X -> Conviction.Locked2x
|
||||
ConvictionLocal.LOCKED_3X -> Conviction.Locked3x
|
||||
ConvictionLocal.LOCKED_4X -> Conviction.Locked4x
|
||||
ConvictionLocal.LOCKED_5X -> Conviction.Locked5x
|
||||
ConvictionLocal.LOCKED_6X -> Conviction.Locked6x
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.tindergov
|
||||
|
||||
import io.novafoundation.nova.common.utils.mapList
|
||||
import io.novafoundation.nova.core_db.dao.TinderGovDao
|
||||
import io.novafoundation.nova.core_db.model.TinderGovBasketItemLocal
|
||||
import io.novafoundation.nova.feature_governance_api.data.model.TinderGovBasketItem
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.core_db.model.TinderGovBasketItemLocal.VoteType as LocalVoteType
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.VoteType
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
interface TinderGovBasketRepository {
|
||||
|
||||
suspend fun add(item: TinderGovBasketItem)
|
||||
|
||||
suspend fun remove(item: TinderGovBasketItem)
|
||||
|
||||
suspend fun remove(items: Collection<TinderGovBasketItem>)
|
||||
|
||||
suspend fun isBasketEmpty(metaId: Long, chainId: ChainId): Boolean
|
||||
|
||||
suspend fun clearBasket(metaId: Long, chainId: ChainId)
|
||||
|
||||
suspend fun getBasket(metaId: Long, chainId: ChainId): List<TinderGovBasketItem>
|
||||
|
||||
fun observeBasket(metaId: Long, chainId: String): Flow<List<TinderGovBasketItem>>
|
||||
}
|
||||
|
||||
class RealTinderGovBasketRepository(private val dao: TinderGovDao) : TinderGovBasketRepository {
|
||||
|
||||
override suspend fun add(item: TinderGovBasketItem) {
|
||||
dao.addToBasket(item.toLocal())
|
||||
}
|
||||
|
||||
override suspend fun remove(item: TinderGovBasketItem) {
|
||||
withContext(Dispatchers.Default) { dao.removeFromBasket(item.toLocal()) }
|
||||
}
|
||||
|
||||
override suspend fun remove(items: Collection<TinderGovBasketItem>) {
|
||||
withContext(Dispatchers.Default) { dao.removeFromBasket(items.map { it.toLocal() }) }
|
||||
}
|
||||
|
||||
override fun observeBasket(metaId: Long, chainId: String): Flow<List<TinderGovBasketItem>> {
|
||||
return dao.observeBasket(metaId, chainId)
|
||||
.mapList { it.toDomain() }
|
||||
}
|
||||
|
||||
override suspend fun getBasket(metaId: Long, chainId: ChainId): List<TinderGovBasketItem> {
|
||||
return withContext(Dispatchers.Default) { dao.getBasket(metaId, chainId).map { it.toDomain() } }
|
||||
}
|
||||
|
||||
override suspend fun isBasketEmpty(metaId: Long, chainId: ChainId): Boolean {
|
||||
return withContext(Dispatchers.Default) { dao.basketSize(metaId, chainId) == 0 }
|
||||
}
|
||||
|
||||
override suspend fun clearBasket(metaId: Long, chainId: ChainId) {
|
||||
withContext(Dispatchers.Default) { dao.clearBasket(metaId, chainId) }
|
||||
}
|
||||
|
||||
private fun TinderGovBasketItem.toLocal(): TinderGovBasketItemLocal {
|
||||
return TinderGovBasketItemLocal(
|
||||
metaId = this.metaId,
|
||||
chainId = this.chainId,
|
||||
referendumId = this.referendumId.value,
|
||||
voteType = this.voteTypeToLocal(),
|
||||
conviction = this.conviction.toLocal(),
|
||||
amount = this.amount
|
||||
)
|
||||
}
|
||||
|
||||
private fun TinderGovBasketItem.voteTypeToLocal() = when (this.voteType) {
|
||||
VoteType.AYE -> LocalVoteType.AYE
|
||||
VoteType.NAY -> LocalVoteType.NAY
|
||||
VoteType.ABSTAIN -> LocalVoteType.ABSTAIN
|
||||
}
|
||||
|
||||
private fun TinderGovBasketItemLocal.toDomain(): TinderGovBasketItem {
|
||||
return TinderGovBasketItem(
|
||||
metaId = this.metaId,
|
||||
chainId = this.chainId,
|
||||
referendumId = ReferendumId(this.referendumId),
|
||||
voteType = this.voteTypeToDomain(),
|
||||
conviction = this.conviction.toDomain(),
|
||||
amount = this.amount
|
||||
)
|
||||
}
|
||||
|
||||
private fun TinderGovBasketItemLocal.voteTypeToDomain() = when (this.voteType) {
|
||||
LocalVoteType.AYE -> VoteType.AYE
|
||||
LocalVoteType.NAY -> VoteType.NAY
|
||||
LocalVoteType.ABSTAIN -> VoteType.ABSTAIN
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.tindergov
|
||||
|
||||
import io.novafoundation.nova.core_db.dao.TinderGovDao
|
||||
import io.novafoundation.nova.core_db.model.TinderGovVotingPowerLocal
|
||||
import io.novafoundation.nova.feature_governance_api.data.model.VotingPower
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
|
||||
interface TinderGovVotingPowerRepository {
|
||||
|
||||
suspend fun setVotingPower(votingPower: VotingPower)
|
||||
|
||||
suspend fun getVotingPower(metaId: Long, chainId: ChainId): VotingPower?
|
||||
}
|
||||
|
||||
class RealTinderGovVotingPowerRepository(
|
||||
private val tinderGovDao: TinderGovDao
|
||||
) : TinderGovVotingPowerRepository {
|
||||
|
||||
override suspend fun setVotingPower(votingPower: VotingPower) {
|
||||
val local = TinderGovVotingPowerLocal(
|
||||
metaId = votingPower.metaId,
|
||||
chainId = votingPower.chainId,
|
||||
amount = votingPower.amount,
|
||||
conviction = votingPower.conviction.toLocal()
|
||||
)
|
||||
|
||||
tinderGovDao.setVotingPower(local)
|
||||
}
|
||||
|
||||
override suspend fun getVotingPower(metaId: Long, chainId: ChainId): VotingPower? {
|
||||
val local = tinderGovDao.getVotingPower(metaId, chainId) ?: return null
|
||||
return VotingPower(
|
||||
metaId = local.metaId,
|
||||
chainId = local.chainId,
|
||||
amount = local.amount,
|
||||
conviction = local.conviction.toDomain()
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v1
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_wallet_api.domain.model.BalanceLockId
|
||||
import java.math.BigInteger
|
||||
|
||||
val DemocracyTrackId = TrackId(BigInteger.ZERO)
|
||||
val DEMOCRACY_ID = BalanceLockId.fromFullId("democrac")
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v1
|
||||
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.BlockNumber
|
||||
import io.novafoundation.nova.common.utils.democracy
|
||||
import io.novafoundation.nova.common.utils.flowOfAll
|
||||
import io.novafoundation.nova.common.utils.numberConstant
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.AccountVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumVoter
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.VoteType
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Voting
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.votedFor
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumVotingDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.ConvictionVotingRepository
|
||||
import io.novafoundation.nova.feature_governance_api.domain.locks.ClaimSchedule
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.democracyRemoveVote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.democracyUnlock
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.democracyVote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.bindVoting
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.votersFor
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository
|
||||
import io.novafoundation.nova.feature_wallet_api.domain.model.Asset
|
||||
import io.novafoundation.nova.runtime.extrinsic.multi.CallBuilder
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.multiNetwork.asset
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId
|
||||
import io.novafoundation.nova.runtime.multiNetwork.getRuntime
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.builder.ExtrinsicBuilder
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.storage
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.math.BigInteger
|
||||
|
||||
class GovV1ConvictionVotingRepository(
|
||||
private val remoteStorageSource: StorageDataSource,
|
||||
private val chainRegistry: ChainRegistry,
|
||||
private val balanceLocksRepository: BalanceLocksRepository,
|
||||
) : ConvictionVotingRepository {
|
||||
|
||||
override val voteLockId = DEMOCRACY_ID
|
||||
|
||||
override suspend fun maxAvailableForVote(asset: Asset): Balance {
|
||||
return asset.freeInPlanks
|
||||
}
|
||||
|
||||
override suspend fun voteLockingPeriod(chainId: ChainId): BlockNumber {
|
||||
val runtime = chainRegistry.getRuntime(chainId)
|
||||
|
||||
return runtime.metadata.democracy().numberConstant("VoteLockingPeriod", runtime)
|
||||
}
|
||||
|
||||
override suspend fun maxTrackVotes(chainId: ChainId): BigInteger {
|
||||
val runtime = chainRegistry.getRuntime(chainId)
|
||||
|
||||
return runtime.metadata.democracy().numberConstant("MaxVotes", runtime)
|
||||
}
|
||||
|
||||
override fun trackLocksFlow(accountId: AccountId, chainAssetId: FullChainAssetId): Flow<Map<TrackId, Balance>> {
|
||||
return flowOfAll {
|
||||
val chainAsset = chainRegistry.asset(chainAssetId)
|
||||
|
||||
balanceLocksRepository.observeBalanceLock(chainAsset, voteLockId)
|
||||
.map { lock -> lock?.amountInPlanks.associatedWithTrack() }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun votingFor(accountId: AccountId, chainId: ChainId): Map<TrackId, Voting> {
|
||||
return votingFor(accountId, chainId, DemocracyTrackId).associatedWithTrack()
|
||||
}
|
||||
|
||||
override suspend fun votingFor(accountId: AccountId, chainId: ChainId, trackId: TrackId): Voting? {
|
||||
if (trackId != DemocracyTrackId) return null
|
||||
|
||||
return remoteStorageSource.query(chainId) {
|
||||
runtime.metadata.democracy().storage("VotingOf").query(
|
||||
accountId,
|
||||
binding = { decoded -> decoded?.let(::bindVoting) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun votingFor(accountId: AccountId, chainId: ChainId, trackIds: Collection<TrackId>): Map<TrackId, Voting> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
override suspend fun votersOf(referendumId: ReferendumId, chain: Chain, type: VoteType): List<ReferendumVoter> {
|
||||
val allVotings = remoteStorageSource.query(chain.id) {
|
||||
runtime.metadata.democracy().storage("VotingOf").entries(
|
||||
keyExtractor = { it },
|
||||
binding = { decoded, _ -> bindVoting(decoded!!) }
|
||||
)
|
||||
}
|
||||
|
||||
return allVotings.votersFor(referendumId)
|
||||
.filter { it.vote.votedFor(type) }
|
||||
}
|
||||
|
||||
override suspend fun abstainVotingDetails(referendumId: ReferendumId, chain: Chain): OffChainReferendumVotingDetails? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun ExtrinsicBuilder.unlock(accountId: AccountId, claimable: ClaimSchedule.UnlockChunk.Claimable) {
|
||||
claimable.actions.forEach { claimAction ->
|
||||
when (claimAction) {
|
||||
is ClaimSchedule.ClaimAction.RemoveVote -> {
|
||||
removeVote(claimAction.trackId, claimAction.referendumId)
|
||||
}
|
||||
|
||||
is ClaimSchedule.ClaimAction.Unlock -> {
|
||||
democracyUnlock(accountId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun ExtrinsicBuilder.vote(referendumId: ReferendumId, vote: AccountVote) {
|
||||
democracyVote(referendumId, vote)
|
||||
}
|
||||
|
||||
override fun CallBuilder.vote(referendumId: ReferendumId, vote: AccountVote) {
|
||||
democracyVote(referendumId, vote)
|
||||
}
|
||||
|
||||
override fun ExtrinsicBuilder.removeVote(trackId: TrackId, referendumId: ReferendumId) {
|
||||
democracyRemoveVote(referendumId)
|
||||
}
|
||||
|
||||
override fun isAbstainVotingAvailable(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override suspend fun fullVotingDetails(referendumId: ReferendumId, chain: Chain): OffChainReferendumVotingDetails? {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun <T> T?.associatedWithTrack(): Map<TrackId, T> {
|
||||
return if (this != null) {
|
||||
mapOf(DemocracyTrackId to this)
|
||||
} else {
|
||||
emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsupported(): Nothing {
|
||||
error("Unsupported operation for Governance 1 voting")
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v1
|
||||
|
||||
import io.novafoundation.nova.common.utils.formatNamed
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.core_db.model.GovernanceDAppLocal
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.GovernanceDAppsRepository
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.details.ReferendumDApp
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GovV1DAppsRepository(
|
||||
private val governanceDAppsDao: GovernanceDAppsDao
|
||||
) : GovernanceDAppsRepository {
|
||||
|
||||
override fun observeReferendumDApps(chainId: ChainId, referendumId: ReferendumId): Flow<List<ReferendumDApp>> {
|
||||
return governanceDAppsDao.observeChainDapps(chainId)
|
||||
.map { dapps ->
|
||||
val v1Dapps = dapps.filter { it.referendumUrlV1 != null }
|
||||
mapV1DappsLocalToDomain(referendumId, v1Dapps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapV1DappsLocalToDomain(referendumId: ReferendumId, dapps: List<GovernanceDAppLocal>): List<ReferendumDApp> {
|
||||
return dapps.map {
|
||||
ReferendumDApp(
|
||||
it.chainId,
|
||||
it.name,
|
||||
it.referendumUrlV1?.formatNamed("referendumId" to referendumId.value.toString())!!,
|
||||
it.iconUrl,
|
||||
it.details
|
||||
)
|
||||
}
|
||||
}
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v1
|
||||
|
||||
import android.util.Log
|
||||
import io.novafoundation.nova.common.address.intoKey
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.BlockNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindBlockNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindBoolean
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindCollectionEnum
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToDictEnum
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToList
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.getTyped
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.incompatible
|
||||
import io.novafoundation.nova.common.utils.LOG_TAG
|
||||
import io.novafoundation.nova.common.utils.democracy
|
||||
import io.novafoundation.nova.common.utils.filterNotNull
|
||||
import io.novafoundation.nova.common.utils.numberConstant
|
||||
import io.novafoundation.nova.common.utils.padEnd
|
||||
import io.novafoundation.nova.common.utils.scheduler
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ConfirmingSource
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.DecidingStatus
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.OnChainReferendum
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.OnChainReferendumStatus
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackInfo
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackQueue
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.OnChainReferendaRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.thresold.gov1.Gov1VotingThreshold
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.bindProposal
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.bindTally
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.multiNetwork.getRuntime
|
||||
import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novasama.substrate_sdk_android.extensions.pad
|
||||
import io.novasama.substrate_sdk_android.hash.Hasher.blake2b256
|
||||
import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.primitives.FixedByteArray
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.primitives.u32
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.toByteArray
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.RuntimeMetadata
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.keys
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.storage
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.math.BigInteger
|
||||
|
||||
private const val SCHEDULER_KEY_BOUND = 32
|
||||
|
||||
private enum class SchedulerVersion {
|
||||
V3, V4
|
||||
}
|
||||
|
||||
class GovV1OnChainReferendaRepository(
|
||||
private val remoteStorageSource: StorageDataSource,
|
||||
private val chainRegistry: ChainRegistry,
|
||||
private val totalIssuanceRepository: TotalIssuanceRepository,
|
||||
) : OnChainReferendaRepository {
|
||||
|
||||
override suspend fun electorate(chainId: ChainId): Balance {
|
||||
return totalIssuanceRepository.getTotalIssuance(chainId)
|
||||
}
|
||||
|
||||
override suspend fun undecidingTimeout(chainId: ChainId): BlockNumber {
|
||||
// we do not support `in queue` status for gov v1 yet
|
||||
return Balance.ZERO
|
||||
}
|
||||
|
||||
override suspend fun getTracks(chainId: ChainId): Collection<TrackInfo> {
|
||||
val runtime = chainRegistry.getRuntime(chainId)
|
||||
|
||||
val track = TrackInfo(
|
||||
id = DemocracyTrackId,
|
||||
name = "root",
|
||||
preparePeriod = Balance.ZERO,
|
||||
decisionPeriod = runtime.votingPeriod(),
|
||||
confirmPeriod = Balance.ZERO,
|
||||
minSupport = null,
|
||||
minApproval = null
|
||||
)
|
||||
|
||||
return listOf(track)
|
||||
}
|
||||
|
||||
override suspend fun getTrackQueues(trackIds: Set<TrackId>, chainId: ChainId): Map<TrackId, TrackQueue> {
|
||||
// we do not support `in queue` status for gov v1 yet
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
override suspend fun getAllOnChainReferenda(chainId: ChainId): Collection<OnChainReferendum> {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
val votingPeriod = runtime.votingPeriod()
|
||||
|
||||
runtime.metadata.democracy().storage("ReferendumInfoOf").entries(
|
||||
keyExtractor = { (id: BigInteger) -> ReferendumId(id) },
|
||||
binding = { decoded, id -> bindReferendum(decoded, id, votingPeriod, runtime) }
|
||||
)
|
||||
}.values.filterNotNull()
|
||||
}
|
||||
|
||||
override suspend fun getOnChainReferenda(chainId: ChainId, referendaIds: Collection<ReferendumId>): Map<ReferendumId, OnChainReferendum> {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
val votingPeriod = runtime.votingPeriod()
|
||||
|
||||
runtime.metadata.democracy().storage("ReferendumInfoOf").entries(
|
||||
keysArguments = referendaIds.map { listOf(it.value) },
|
||||
keyExtractor = { (id: BigInteger) -> ReferendumId(id) },
|
||||
binding = { decoded, id -> bindReferendum(decoded, id, votingPeriod, runtime) }
|
||||
)
|
||||
}.filterNotNull()
|
||||
}
|
||||
|
||||
override suspend fun onChainReferendumFlow(chainId: ChainId, referendumId: ReferendumId): Flow<OnChainReferendum?> {
|
||||
return remoteStorageSource.subscribe(chainId) {
|
||||
val votingPeriod = runtime.votingPeriod()
|
||||
|
||||
runtime.metadata.democracy().storage("ReferendumInfoOf").observe(
|
||||
referendumId.value,
|
||||
binding = { bindReferendum(it, referendumId, votingPeriod, runtime) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getReferendaExecutionBlocks(
|
||||
chainId: ChainId,
|
||||
approvedReferendaIds: Collection<ReferendumId>
|
||||
): Map<ReferendumId, BlockNumber> {
|
||||
if (approvedReferendaIds.isEmpty()) return emptyMap()
|
||||
|
||||
return remoteStorageSource.query(chainId) {
|
||||
val schedulerVersion = runtime.metadata.schedulerVersion()
|
||||
|
||||
val referendaIdBySchedulerId = approvedReferendaIds.flatMap { referendumId ->
|
||||
referendumId.versionedEnactmentSchedulerIdVariants(runtime, schedulerVersion).map { enactmentKeyVariant ->
|
||||
enactmentKeyVariant.intoKey() to referendumId
|
||||
}
|
||||
}.toMap()
|
||||
|
||||
// We do not extract referendumId as a key here since we request multiple keys per each referendumId (pre- and post- v4 migration)
|
||||
// Thus, we should firstly filter out null values from map.
|
||||
// Otherwise key candidate that resulted in null value may shadow another which resulted in value and we will loose that value
|
||||
val schedulerKeysBySchedulerKey = runtime.metadata.scheduler().storage("Lookup").entries(
|
||||
keysArguments = referendaIdBySchedulerId.keys.map { schedulerIdKey -> listOf(schedulerIdKey.value) },
|
||||
keyExtractor = { (schedulerId: ByteArray) -> schedulerId.intoKey() },
|
||||
binding = { decoded, _ ->
|
||||
decoded?.let {
|
||||
val (blockNumber, _) = decoded.castToList()
|
||||
|
||||
bindBlockNumber(blockNumber)
|
||||
}
|
||||
}
|
||||
).filterNotNull()
|
||||
|
||||
schedulerKeysBySchedulerKey.mapKeys { (schedulerKey, _) -> referendaIdBySchedulerId.getValue(schedulerKey) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindReferendum(
|
||||
decoded: Any?,
|
||||
id: ReferendumId,
|
||||
votingPeriod: BlockNumber,
|
||||
runtime: RuntimeSnapshot,
|
||||
): OnChainReferendum? = runCatching {
|
||||
val asDictEnum = decoded.castToDictEnum()
|
||||
|
||||
val referendumStatus = when (asDictEnum.name) {
|
||||
"Ongoing" -> {
|
||||
val status = asDictEnum.value.castToStruct()
|
||||
val end = bindBlockNumber(status["end"])
|
||||
val submittedIn = end - votingPeriod
|
||||
|
||||
val threshold = bindThreshold(status["threshold"])
|
||||
|
||||
OnChainReferendumStatus.Ongoing(
|
||||
track = DemocracyTrackId,
|
||||
proposal = bindProposal(status["proposalHash"] ?: status["proposal"], runtime),
|
||||
submitted = submittedIn,
|
||||
submissionDeposit = null,
|
||||
decisionDeposit = null,
|
||||
deciding = DecidingStatus(
|
||||
since = submittedIn,
|
||||
confirming = ConfirmingSource.FromThreshold(end = end)
|
||||
),
|
||||
tally = bindTally(status.getTyped("tally")),
|
||||
inQueue = false,
|
||||
threshold = threshold
|
||||
)
|
||||
}
|
||||
|
||||
"Finished" -> {
|
||||
val status = asDictEnum.value.castToStruct()
|
||||
val approved = bindBoolean(status["approved"])
|
||||
val end = bindBlockNumber(status["end"])
|
||||
|
||||
if (approved) {
|
||||
OnChainReferendumStatus.Approved(end)
|
||||
} else {
|
||||
OnChainReferendumStatus.Rejected(end)
|
||||
}
|
||||
}
|
||||
|
||||
else -> throw IllegalArgumentException("Unsupported referendum status")
|
||||
}
|
||||
|
||||
OnChainReferendum(
|
||||
id = id,
|
||||
status = referendumStatus
|
||||
)
|
||||
}
|
||||
.onFailure { Log.e(this.LOG_TAG, "Failed to decode on-chain referendum", it) }
|
||||
.getOrNull()
|
||||
|
||||
private fun bindThreshold(decoded: Any?) = bindCollectionEnum(decoded) { name ->
|
||||
when (name) {
|
||||
"SimpleMajority" -> Gov1VotingThreshold.SIMPLE_MAJORITY
|
||||
"SuperMajorityApprove" -> Gov1VotingThreshold.SUPER_MAJORITY_APPROVE
|
||||
"SuperMajorityAgainst" -> Gov1VotingThreshold.SUPER_MAJORITY_AGAINST
|
||||
else -> incompatible()
|
||||
}
|
||||
}
|
||||
|
||||
private fun RuntimeSnapshot.votingPeriod(): BlockNumber {
|
||||
return metadata.democracy().numberConstant("VotingPeriod", this)
|
||||
}
|
||||
|
||||
private fun ReferendumId.versionedEnactmentSchedulerIdVariants(runtime: RuntimeSnapshot, schedulerVersion: SchedulerVersion): List<ByteArray> {
|
||||
return when (schedulerVersion) {
|
||||
SchedulerVersion.V3 -> listOf(v3EnactmentSchedulerId(runtime))
|
||||
SchedulerVersion.V4 -> listOf(v4EnactmentSchedulerId(runtime), v4MigratedEnactmentSchedulerId(runtime))
|
||||
}
|
||||
}
|
||||
|
||||
// https:github.com/paritytech/substrate/blob/0d64ba4268106fffe430d41b541c1aeedd4f8da5/frame/democracy/src/lib.rs#L1476
|
||||
private fun ReferendumId.v3EnactmentSchedulerId(runtime: RuntimeSnapshot): ByteArray {
|
||||
val encodedAssemblyId = DEMOCRACY_ID.value.encodeToByteArray() // 'const bytes' in rust
|
||||
val encodedIndex = u32.toByteArray(runtime, value)
|
||||
|
||||
return encodedAssemblyId + encodedIndex
|
||||
}
|
||||
|
||||
private fun ReferendumId.v4EnactmentSchedulerId(runtime: RuntimeSnapshot): ByteArray {
|
||||
val oldId = v3EnactmentSchedulerId(runtime)
|
||||
|
||||
return if (oldId.size > SCHEDULER_KEY_BOUND) {
|
||||
oldId.blake2b256().pad(SCHEDULER_KEY_BOUND, padding = 0)
|
||||
} else {
|
||||
oldId.padEnd(SCHEDULER_KEY_BOUND, padding = 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ReferendumId.v4MigratedEnactmentSchedulerId(runtime: RuntimeSnapshot): ByteArray {
|
||||
return v3EnactmentSchedulerId(runtime).blake2b256()
|
||||
}
|
||||
|
||||
private fun RuntimeMetadata.schedulerVersion(): SchedulerVersion {
|
||||
val lookupStorage = scheduler().storage("Lookup")
|
||||
val lookupArgumentType = lookupStorage.keys.first()
|
||||
|
||||
return if (lookupArgumentType is FixedByteArray) {
|
||||
// bounded type is used
|
||||
SchedulerVersion.V4
|
||||
} else {
|
||||
SchedulerVersion.V3
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v1
|
||||
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindByteArray
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToDictEnum
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct
|
||||
import io.novafoundation.nova.common.utils.democracy
|
||||
import io.novafoundation.nova.common.utils.hasStorage
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.PreImage
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.HexHash
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.PreImageRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.PreImageRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.v2.Gov2PreImageRepository
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.fromByteArray
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.GenericCall
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.storage
|
||||
|
||||
class GovV1PreImageRepository(
|
||||
private val remoteStorageSource: StorageDataSource,
|
||||
private val v2Delegate: Gov2PreImageRepository,
|
||||
) : PreImageRepository {
|
||||
|
||||
override suspend fun getPreimageFor(request: PreImageRequest, chainId: ChainId): PreImage? {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
// The most recent democracy pallet version stores preimages the same way as gov v2 does
|
||||
// However, those changes are not yet live on Kusama & Polkadot
|
||||
if (runtime.metadata.democracy().hasStorage("Preimages")) {
|
||||
runtime.metadata.democracy().storage("Preimages").query(
|
||||
request.hash,
|
||||
binding = { bindPreimage(it, runtime) }
|
||||
)
|
||||
} else {
|
||||
// just in case something will fail during v2 delegate execution
|
||||
runCatching { v2Delegate.getPreimageFor(request, chainId) }.getOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPreimagesFor(requests: Collection<PreImageRequest>, chainId: ChainId): Map<HexHash, PreImage?> {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
if (runtime.metadata.democracy().hasStorage("Preimages")) {
|
||||
// Since it democracy pallet preimages stored un-sized - we do not implement bulk fetch due to possible big calls being stored
|
||||
// We cant efficiently use `state_getStorageSize` since it only allows to query one key at the time
|
||||
emptyMap()
|
||||
} else {
|
||||
runCatching { v2Delegate.getPreimagesFor(requests, chainId) }.getOrDefault(emptyMap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindPreimage(
|
||||
decoded: Any?,
|
||||
runtime: RuntimeSnapshot,
|
||||
): PreImage? = runCatching {
|
||||
val asDictEnum = decoded.castToDictEnum()
|
||||
|
||||
when (asDictEnum.name) {
|
||||
"Available" -> {
|
||||
val valueStruct = asDictEnum.value.castToStruct()
|
||||
val callData = bindByteArray(valueStruct["data"])
|
||||
|
||||
val runtimeCall = GenericCall.fromByteArray(runtime, callData)
|
||||
|
||||
PreImage(encodedCall = callData, call = runtimeCall)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}.getOrNull()
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v2
|
||||
|
||||
import android.util.Log
|
||||
import io.novafoundation.nova.common.data.network.subquery.SubQueryNodes
|
||||
import io.novafoundation.nova.common.utils.LOG_TAG
|
||||
import io.novafoundation.nova.common.utils.filterNotNull
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.AccountVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Delegation
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.delegation.DelegateDetailedStats
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.delegation.DelegateMetadata
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.delegation.DelegateStats
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.vote.UserVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.DelegationsRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.convictionVotingDelegate
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.convictionVotingUndelegate
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.metadata.DelegateMetadataApi
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.metadata.getDelegatesMetadata
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.DelegationsSubqueryApi
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.AllHistoricalVotesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateDelegatorsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateDetailedStatsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateStatsByAddressesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DelegateStatsRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.DirectHistoricalVotesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DelegateDelegatorsResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DelegateStatsResponse
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DelegatedVoteRemote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.DirectVoteRemote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.mapMultiVoteRemoteToAccountVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.RecentVotesDateThreshold
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.common.zeroPoint
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.runtime.ext.accountIdOf
|
||||
import io.novafoundation.nova.runtime.ext.accountIdOrNull
|
||||
import io.novafoundation.nova.runtime.ext.addressOf
|
||||
import io.novafoundation.nova.runtime.ext.externalApi
|
||||
import io.novafoundation.nova.runtime.extrinsic.multi.CallBuilder
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain.ExternalApi.GovernanceDelegations
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Conviction
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Vote
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.mapConvictionFromString
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
|
||||
class Gov2DelegationsRepository(
|
||||
private val delegationsSubqueryApi: DelegationsSubqueryApi,
|
||||
private val delegateMetadataApi: DelegateMetadataApi,
|
||||
) : DelegationsRepository {
|
||||
|
||||
override suspend fun isDelegationSupported(chain: Chain): Boolean {
|
||||
// we heavy rely on SubQuery API for delegations so we require it to be present
|
||||
return chain.externalApi<GovernanceDelegations>() != null
|
||||
}
|
||||
|
||||
override suspend fun getDelegatesStats(
|
||||
recentVotesDateThreshold: RecentVotesDateThreshold,
|
||||
chain: Chain
|
||||
): List<DelegateStats> {
|
||||
return runCatching {
|
||||
val externalApiLink = chain.externalApi<GovernanceDelegations>()?.url ?: return emptyList()
|
||||
val request = DelegateStatsRequest(recentVotesDateThreshold)
|
||||
val response = delegationsSubqueryApi.getDelegateStats(externalApiLink, request)
|
||||
val delegateStats = response.data.delegates.nodes
|
||||
|
||||
mapDelegateStats(delegateStats, chain)
|
||||
}.getOrNull()
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
override suspend fun getDelegatesStatsByAccountIds(
|
||||
recentVotesDateThreshold: RecentVotesDateThreshold,
|
||||
accountIds: List<AccountId>,
|
||||
chain: Chain
|
||||
): List<DelegateStats> {
|
||||
return runCatching {
|
||||
val externalApiLink = chain.externalApi<GovernanceDelegations>()?.url ?: return emptyList()
|
||||
val addresses = accountIds.map { chain.addressOf(it) }
|
||||
val request = DelegateStatsByAddressesRequest(recentVotesDateThreshold, addresses = addresses)
|
||||
val response = delegationsSubqueryApi.getDelegateStats(externalApiLink, request)
|
||||
val delegateStats = response.data.delegates.nodes
|
||||
|
||||
mapDelegateStats(delegateStats, chain)
|
||||
}.getOrNull()
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
override suspend fun getDetailedDelegateStats(
|
||||
delegateAddress: String,
|
||||
recentVotesDateThreshold: RecentVotesDateThreshold,
|
||||
chain: Chain
|
||||
): DelegateDetailedStats? {
|
||||
val externalApiLink = chain.externalApi<GovernanceDelegations>()?.url ?: return null
|
||||
val request = DelegateDetailedStatsRequest(delegateAddress, recentVotesDateThreshold)
|
||||
|
||||
val response = delegationsSubqueryApi.getDetailedDelegateStats(externalApiLink, request)
|
||||
val delegateStats = response.data.delegates.nodes.firstOrNull() ?: return null
|
||||
|
||||
return DelegateDetailedStats(
|
||||
accountId = chain.accountIdOf(delegateAddress),
|
||||
delegationsCount = delegateStats.delegators,
|
||||
delegatedVotes = delegateStats.delegatorVotes,
|
||||
recentVotes = delegateStats.recentVotes.totalCount,
|
||||
allVotes = delegateStats.allVotes.totalCount
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getDelegatesMetadata(chain: Chain): List<DelegateMetadata> {
|
||||
return delegateMetadataApi.getDelegatesMetadata(chain).mapNotNull {
|
||||
val accountId = chain.accountIdOrNull(it.address) ?: return@mapNotNull null
|
||||
|
||||
DelegateMetadata(
|
||||
accountId = accountId,
|
||||
shortDescription = it.shortDescription,
|
||||
longDescription = it.longDescription,
|
||||
profileImageUrl = it.image,
|
||||
isOrganization = it.isOrganization,
|
||||
name = it.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getDelegateMetadata(chain: Chain, delegate: AccountId): DelegateMetadata? {
|
||||
return getDelegatesMetadata(chain)
|
||||
.find { it.accountId.contentEquals(delegate) }
|
||||
}
|
||||
|
||||
override suspend fun getDelegationsTo(delegate: AccountId, chain: Chain): List<Delegation> {
|
||||
return accountSubQueryRequest(delegate, chain) { externalApiLink, delegateAddress ->
|
||||
val request = DelegateDelegatorsRequest(delegateAddress)
|
||||
val response = delegationsSubqueryApi.getDelegateDelegators(externalApiLink, request)
|
||||
response.data.delegations.nodes.map { mapDelegationFromRemote(it, chain, delegate) }
|
||||
}.orEmpty()
|
||||
}
|
||||
|
||||
override suspend fun allHistoricalVotesOf(user: AccountId, chain: Chain): Map<ReferendumId, UserVote>? {
|
||||
return accountSubQueryRequest(user, chain) { externalApiLink, userAddress ->
|
||||
val request = AllHistoricalVotesRequest(userAddress)
|
||||
val response = delegationsSubqueryApi.getAllHistoricalVotes(externalApiLink, request)
|
||||
|
||||
val direct = response.data.direct.toUserVoteMap()
|
||||
val delegated = response.data.delegated.toUserVoteMap(chain)
|
||||
|
||||
(direct + delegated).filterNotNull()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun historicalVoteOf(user: AccountId, referendumId: ReferendumId, chain: Chain): UserVote? {
|
||||
return allHistoricalVotesOf(user, chain)?.get(referendumId)
|
||||
}
|
||||
|
||||
override suspend fun directHistoricalVotesOf(
|
||||
user: AccountId,
|
||||
chain: Chain,
|
||||
recentVotesDateThreshold: RecentVotesDateThreshold?
|
||||
): Map<ReferendumId, UserVote.Direct>? {
|
||||
val timePointThreshold = recentVotesDateThreshold ?: RecentVotesDateThreshold.zeroPoint()
|
||||
|
||||
return accountSubQueryRequest(user, chain) { externalApiLink, userAddress ->
|
||||
val request = DirectHistoricalVotesRequest(userAddress, timePointThreshold)
|
||||
val response = delegationsSubqueryApi.getDirectHistoricalVotes(externalApiLink, request)
|
||||
|
||||
response.data.direct.toUserVoteMap().filterNotNull()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun CallBuilder.delegate(delegate: AccountId, trackId: TrackId, amount: Balance, conviction: Conviction) {
|
||||
convictionVotingDelegate(delegate, trackId, amount, conviction)
|
||||
}
|
||||
|
||||
override suspend fun CallBuilder.undelegate(trackId: TrackId) {
|
||||
convictionVotingUndelegate(trackId)
|
||||
}
|
||||
|
||||
private fun SubQueryNodes<DirectVoteRemote>.toUserVoteMap(): Map<ReferendumId, UserVote.Direct?> {
|
||||
return nodes.associateBy(
|
||||
keySelector = { ReferendumId(it.referendumId) },
|
||||
valueTransform = { directVoteRemote -> UserVote.Direct(mapMultiVoteRemoteToAccountVote(directVoteRemote)) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun SubQueryNodes<DelegatedVoteRemote>.toUserVoteMap(chain: Chain): Map<ReferendumId, UserVote.Delegated?> {
|
||||
return nodes.associateBy(
|
||||
keySelector = { ReferendumId(it.parent.referendumId) },
|
||||
valueTransform = { delegatedVoteRemote ->
|
||||
// delegated votes do not participate in any vote rather than standard
|
||||
val aye = delegatedVoteRemote.parent.standardVote?.aye ?: return@associateBy null
|
||||
val standardVote = delegatedVoteRemote.vote
|
||||
|
||||
UserVote.Delegated(
|
||||
delegate = chain.accountIdOf(delegatedVoteRemote.parent.delegateId),
|
||||
vote = AccountVote.Standard(
|
||||
balance = standardVote.amount,
|
||||
vote = Vote(
|
||||
aye = aye,
|
||||
conviction = mapConvictionFromString(delegatedVoteRemote.vote.conviction)
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapDelegationFromRemote(
|
||||
delegation: DelegateDelegatorsResponse.DelegatorRemote,
|
||||
chain: Chain,
|
||||
delegate: AccountId
|
||||
): Delegation {
|
||||
return Delegation(
|
||||
vote = Delegation.Vote(
|
||||
amount = delegation.delegation.amount,
|
||||
conviction = mapConvictionFromString(delegation.delegation.conviction)
|
||||
),
|
||||
delegator = chain.accountIdOf(delegation.address),
|
||||
delegate = delegate
|
||||
)
|
||||
}
|
||||
|
||||
private inline fun <R> accountSubQueryRequest(
|
||||
accountId: AccountId,
|
||||
chain: Chain,
|
||||
action: (url: String, address: String) -> R
|
||||
): R? {
|
||||
val externalApiLink = chain.externalApi<GovernanceDelegations>()?.url ?: return null
|
||||
val address = chain.addressOf(accountId)
|
||||
|
||||
return runCatching { action(externalApiLink, address) }
|
||||
.onFailure { Log.e(LOG_TAG, "Failed to execute subquery request", it) }
|
||||
.getOrNull()
|
||||
}
|
||||
|
||||
private fun mapDelegateStats(delegateStats: List<DelegateStatsResponse.Delegate>, chain: Chain): List<DelegateStats> {
|
||||
return delegateStats.map { delegate ->
|
||||
DelegateStats(
|
||||
accountId = chain.accountIdOf(delegate.address),
|
||||
delegationsCount = delegate.delegators,
|
||||
delegatedVotes = delegate.delegatorVotes,
|
||||
recentVotes = delegate.delegateVotes.totalCount
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v2
|
||||
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindByteArray
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.cast
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToDictEnum
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct
|
||||
import io.novafoundation.nova.common.utils.castOrNull
|
||||
import io.novafoundation.nova.common.utils.preImage
|
||||
import io.novafoundation.nova.common.utils.storageOrFallback
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.PreImage
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.HexHash
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.PreImageRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.PreImageRequest
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.PreImageRequest.FetchCondition
|
||||
import io.novafoundation.nova.feature_governance_impl.data.preimage.PreImageSizer
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novafoundation.nova.runtime.storage.source.query.StorageQueryContext
|
||||
import io.novafoundation.nova.runtime.storage.source.query.wrapSingleArgumentKeys
|
||||
import io.novasama.substrate_sdk_android.extensions.toHexString
|
||||
import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.Tuple
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.fromByteArray
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.GenericCall
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.RuntimeMetadata
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.module.StorageEntry
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.module.StorageEntryType
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.storage
|
||||
import java.math.BigInteger
|
||||
|
||||
class Gov2PreImageRepository(
|
||||
private val remoteSource: StorageDataSource,
|
||||
private val preImageSizer: PreImageSizer,
|
||||
) : PreImageRepository {
|
||||
|
||||
override suspend fun getPreimageFor(request: PreImageRequest, chainId: ChainId): PreImage? {
|
||||
return remoteSource.query(chainId) {
|
||||
val storage = runtime.metadata.preImageForStorage()
|
||||
val shouldKnowSize = storage.shouldKnowSizeExecuting(request)
|
||||
|
||||
val preImageSize = if (shouldKnowSize) {
|
||||
request.knownSize ?: fetchPreImageLength(request.hash)
|
||||
} else {
|
||||
request.knownSize
|
||||
}
|
||||
|
||||
val shouldFetch = request.fetchIf.shouldFetch(actualPreImageSize = preImageSize)
|
||||
|
||||
val canFetchPreimage = if (storage.requiresSize()) preImageSize != null else true
|
||||
val canReturnValue = shouldFetch && canFetchPreimage
|
||||
|
||||
if (!canReturnValue) return@query null
|
||||
|
||||
val key = storage.preImageStorageKey(request.hash, preImageSize)
|
||||
storage.query(key, binding = { bindPreimage(it, runtime) })
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPreimagesFor(requests: Collection<PreImageRequest>, chainId: ChainId): Map<HexHash, PreImage?> {
|
||||
return remoteSource.query(chainId) {
|
||||
val storage = runtime.metadata.preImageForStorage()
|
||||
val shouldKnowSizes = requests.associateBy(
|
||||
keySelector = { it.hashHex },
|
||||
valueTransform = { request -> storage.shouldKnowSizeExecuting(request) }
|
||||
)
|
||||
val hashesToFetchSize = requests.mapNotNull {
|
||||
if (it.hashHex in shouldKnowSizes && it.knownSize == null) {
|
||||
it.hash
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
val fetchedSizes = fetchPreImagesLength(hashesToFetchSize)
|
||||
|
||||
val preKnownSizes = requests.associateBy(
|
||||
keySelector = { it.hashHex },
|
||||
valueTransform = { it.knownSize }
|
||||
)
|
||||
val allKnownSizes = preKnownSizes + fetchedSizes
|
||||
|
||||
val keysToFetch = requests.mapNotNull { request ->
|
||||
val preImageSize = allKnownSizes[request.hashHex]
|
||||
|
||||
val shouldFetch = request.fetchIf.shouldFetch(actualPreImageSize = preImageSize)
|
||||
val canFetchPreimage = if (storage.requiresSize()) preImageSize != null else true
|
||||
|
||||
if (shouldFetch && canFetchPreimage) {
|
||||
storage.preImageStorageKey(request.hash, preImageSize)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
storage.entries(
|
||||
keysArguments = keysToFetch.wrapSingleArgumentKeys(),
|
||||
keyExtractor = { (hashAndLen: List<*>) -> bindByteArray(hashAndLen.first()).toHexString() },
|
||||
binding = { decoded, _ -> bindPreimage(decoded, runtime) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StorageEntry.shouldKnowSizeExecuting(request: PreImageRequest): Boolean {
|
||||
return requiresSize() || request.fetchIf == FetchCondition.SMALL_SIZE
|
||||
}
|
||||
|
||||
private fun StorageEntry.preImageStorageKey(hash: ByteArray, preImageSize: BigInteger?): Any {
|
||||
return if (requiresSize()) {
|
||||
listOf(hash, preImageSize!!)
|
||||
} else {
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
private fun FetchCondition.shouldFetch(actualPreImageSize: BigInteger?): Boolean {
|
||||
return when (this) {
|
||||
FetchCondition.ALWAYS -> true
|
||||
FetchCondition.SMALL_SIZE ->
|
||||
actualPreImageSize != null &&
|
||||
preImageSizer.satisfiesSizeConstraint(actualPreImageSize, PreImageSizer.SizeConstraint.SMALL)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun StorageQueryContext.fetchPreImageLength(callHash: ByteArray): BigInteger? {
|
||||
return runtime.metadata.preImage().storageOrFallback("RequestStatusFor", "StatusFor")
|
||||
.query(
|
||||
callHash,
|
||||
binding = ::bindPreImageLength
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun StorageQueryContext.fetchPreImagesLength(callHashes: Collection<ByteArray>): Map<HexHash, BigInteger?> {
|
||||
return runtime.metadata.preImage().storageOrFallback("RequestStatusFor", "StatusFor")
|
||||
.entries(
|
||||
keysArguments = callHashes.wrapSingleArgumentKeys(),
|
||||
keyExtractor = { (callHash: ByteArray) -> callHash.toHexString() },
|
||||
binding = { decoded, _ -> bindPreImageLength(decoded) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun bindPreImageLength(decoded: Any?): BigInteger? = runCatching {
|
||||
val asDictEnum = decoded.castToDictEnum()
|
||||
// every variant of RequestStatus is struct that has len field
|
||||
val valueStruct = asDictEnum.value.castToStruct()
|
||||
|
||||
bindNumber(valueStruct["len"])
|
||||
}
|
||||
.getOrNull()
|
||||
|
||||
private fun bindPreimage(
|
||||
decoded: Any?,
|
||||
runtime: RuntimeSnapshot,
|
||||
): PreImage? {
|
||||
val asByteArray = decoded.castOrNull<ByteArray>() ?: return null
|
||||
|
||||
val runtimeCall = runCatching {
|
||||
GenericCall.fromByteArray(runtime, asByteArray)
|
||||
}.getOrNull()
|
||||
|
||||
return runtimeCall?.let {
|
||||
PreImage(
|
||||
encodedCall = asByteArray,
|
||||
call = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun RuntimeMetadata.preImageForStorage(): StorageEntry {
|
||||
return preImage().storage("PreimageFor")
|
||||
}
|
||||
|
||||
private fun StorageEntry.requiresSize(): Boolean {
|
||||
val keys = type.cast<StorageEntryType.NMap>().keys
|
||||
val argument = keys.first()
|
||||
|
||||
// for newer version of the pallet key is (CallHash, Length)
|
||||
return argument is Tuple
|
||||
}
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v2
|
||||
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.BlockNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindList
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToList
|
||||
import io.novafoundation.nova.common.utils.convictionVoting
|
||||
import io.novafoundation.nova.common.utils.filterNotNull
|
||||
import io.novafoundation.nova.common.utils.numberConstant
|
||||
import io.novafoundation.nova.common.utils.sum
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.AccountVote
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Delegation
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumVoter
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.VoteType
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.Voting
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.amountMultiplier
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.isAye
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.votedFor
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumVotingDetails
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.OffChainReferendumVotingDetails.VotingInfo
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.empty
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.offchain.model.referendum.plus
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.ConvictionVotingRepository
|
||||
import io.novafoundation.nova.feature_governance_api.domain.locks.ClaimSchedule
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.convictionVotingRemoveVote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.convictionVotingUnlock
|
||||
import io.novafoundation.nova.feature_governance_impl.data.network.blockchain.extrinsic.convictionVotingVote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.DelegationsSubqueryApi
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.ReferendumSplitAbstainVotersRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.ReferendumVotersRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.request.ReferendumVotesRequest
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.ReferendumVoterRemote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.delegation.v2.stats.response.mapMultiVoteRemoteToAccountVote
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.bindVoting
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.toOffChainVotes
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.votersFor
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.feature_wallet_api.domain.model.Asset
|
||||
import io.novafoundation.nova.feature_wallet_api.domain.model.BalanceLockId
|
||||
import io.novafoundation.nova.runtime.ext.accountIdOf
|
||||
import io.novafoundation.nova.runtime.ext.externalApi
|
||||
import io.novafoundation.nova.runtime.extrinsic.multi.CallBuilder
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.FullChainAssetId
|
||||
import io.novafoundation.nova.runtime.multiNetwork.getRuntime
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.Conviction
|
||||
import io.novafoundation.nova.runtime.multiNetwork.runtime.types.custom.vote.mapConvictionFromString
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.builder.ExtrinsicBuilder
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.storage
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.math.BigInteger
|
||||
|
||||
class GovV2ConvictionVotingRepository(
|
||||
private val remoteStorageSource: StorageDataSource,
|
||||
private val chainRegistry: ChainRegistry,
|
||||
private val delegateSubqueryApi: DelegationsSubqueryApi
|
||||
) : ConvictionVotingRepository {
|
||||
|
||||
override val voteLockId = BalanceLockId.fromFullId("pyconvot")
|
||||
|
||||
override suspend fun maxAvailableForVote(asset: Asset): Balance {
|
||||
return asset.totalInPlanks
|
||||
}
|
||||
|
||||
override suspend fun voteLockingPeriod(chainId: ChainId): BlockNumber {
|
||||
val runtime = chainRegistry.getRuntime(chainId)
|
||||
|
||||
return runtime.metadata.convictionVoting().numberConstant("VoteLockingPeriod", runtime)
|
||||
}
|
||||
|
||||
override suspend fun maxTrackVotes(chainId: ChainId): BigInteger {
|
||||
val runtime = chainRegistry.getRuntime(chainId)
|
||||
|
||||
return runtime.metadata.convictionVoting().numberConstant("MaxVotes", runtime)
|
||||
}
|
||||
|
||||
override fun trackLocksFlow(accountId: AccountId, chainAssetId: FullChainAssetId): Flow<Map<TrackId, Balance>> {
|
||||
return remoteStorageSource.subscribe(chainAssetId.chainId) {
|
||||
runtime.metadata.convictionVoting().storage("ClassLocksFor").observe(accountId, binding = ::bindTrackLocks)
|
||||
.map { it.toMap() }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun votingFor(accountId: AccountId, chainId: ChainId): Map<TrackId, Voting> {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
runtime.metadata.convictionVoting().storage("VotingFor").entries(
|
||||
accountId,
|
||||
keyExtractor = { (_: AccountId, trackId: BigInteger) -> TrackId(trackId) },
|
||||
binding = { decoded, _ -> bindVoting(decoded!!) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun votingFor(accountId: AccountId, chainId: ChainId, trackId: TrackId): Voting? {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
runtime.metadata.convictionVoting().storage("VotingFor").query(
|
||||
accountId,
|
||||
trackId.value,
|
||||
binding = { decoded -> decoded?.let(::bindVoting) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun votingFor(accountId: AccountId, chainId: ChainId, trackIds: Collection<TrackId>): Map<TrackId, Voting> {
|
||||
val keys = trackIds.map { listOf(accountId, it.value) }
|
||||
|
||||
return remoteStorageSource.query(chainId) {
|
||||
runtime.metadata.convictionVoting().storage("VotingFor").entries(
|
||||
keysArguments = keys,
|
||||
keyExtractor = { (_: AccountId, trackId: BigInteger) -> TrackId(trackId) },
|
||||
binding = { decoded, _ -> decoded?.let(::bindVoting) }
|
||||
)
|
||||
}.filterNotNull()
|
||||
}
|
||||
|
||||
override suspend fun votersOf(referendumId: ReferendumId, chain: Chain, type: VoteType): List<ReferendumVoter> {
|
||||
val governanceDelegationsExternalApi = chain.externalApi<Chain.ExternalApi.GovernanceDelegations>()
|
||||
return if (governanceDelegationsExternalApi != null) {
|
||||
runCatching { getVotersFromIndexer(referendumId, chain, governanceDelegationsExternalApi, type) }
|
||||
.getOrElse { getVotersFromChain(referendumId, chain, type) }
|
||||
} else {
|
||||
getVotersFromChain(referendumId, chain, type)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun abstainVotingDetails(referendumId: ReferendumId, chain: Chain): OffChainReferendumVotingDetails? {
|
||||
val api = chain.externalApi<Chain.ExternalApi.GovernanceDelegations>() ?: return null
|
||||
|
||||
return runCatching {
|
||||
val request = ReferendumSplitAbstainVotersRequest(referendumId.value)
|
||||
val response = delegateSubqueryApi.getReferendumAbstainVoters(api.url, request)
|
||||
val trackId = TrackId(response.data.referendum.trackId)
|
||||
val abstainAmountSum = response.data
|
||||
.referendum
|
||||
.castingVotings
|
||||
.nodes
|
||||
.mapNotNull { it.splitAbstainVote?.abstainAmount }
|
||||
.sum()
|
||||
|
||||
val abstainVotes = abstainAmountSum.toBigDecimal() * Conviction.None.amountMultiplier()
|
||||
OffChainReferendumVotingDetails(trackId, VotingInfo.Abstain(abstainVotes))
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private suspend fun getVotersFromIndexer(
|
||||
referendumId: ReferendumId,
|
||||
chain: Chain,
|
||||
api: Chain.ExternalApi.GovernanceDelegations,
|
||||
type: VoteType
|
||||
): List<ReferendumVoter> {
|
||||
val request = ReferendumVotersRequest(referendumId.value, type.isAye())
|
||||
val response = delegateSubqueryApi.getReferendumVoters(api.url, request)
|
||||
return response.data
|
||||
.voters
|
||||
.nodes
|
||||
.mapNotNull { mapVoterFromRemote(it, chain, type) }
|
||||
}
|
||||
|
||||
private suspend fun getVotersFromChain(referendumId: ReferendumId, chain: Chain, type: VoteType): List<ReferendumVoter> {
|
||||
val allVotings = remoteStorageSource.query(chain.id) {
|
||||
runtime.metadata.convictionVoting().storage("VotingFor").entries(
|
||||
keyExtractor = { it },
|
||||
binding = { decoded, _ -> bindVoting(decoded!!) }
|
||||
)
|
||||
}
|
||||
|
||||
return allVotings.votersFor(referendumId)
|
||||
.filter { it.vote.votedFor(type) }
|
||||
}
|
||||
|
||||
override fun ExtrinsicBuilder.unlock(accountId: AccountId, claimable: ClaimSchedule.UnlockChunk.Claimable) {
|
||||
claimable.actions.forEach { claimAction ->
|
||||
when (claimAction) {
|
||||
is ClaimSchedule.ClaimAction.RemoveVote -> {
|
||||
removeVote(claimAction.trackId, claimAction.referendumId)
|
||||
}
|
||||
|
||||
is ClaimSchedule.ClaimAction.Unlock -> {
|
||||
convictionVotingUnlock(claimAction.trackId, accountId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun ExtrinsicBuilder.vote(referendumId: ReferendumId, vote: AccountVote) {
|
||||
convictionVotingVote(referendumId, vote)
|
||||
}
|
||||
|
||||
override fun CallBuilder.vote(referendumId: ReferendumId, vote: AccountVote) {
|
||||
convictionVotingVote(referendumId, vote)
|
||||
}
|
||||
|
||||
override fun ExtrinsicBuilder.removeVote(trackId: TrackId, referendumId: ReferendumId) {
|
||||
convictionVotingRemoveVote(trackId, referendumId)
|
||||
}
|
||||
|
||||
override fun isAbstainVotingAvailable(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun fullVotingDetails(referendumId: ReferendumId, chain: Chain): OffChainReferendumVotingDetails? {
|
||||
val api = chain.externalApi<Chain.ExternalApi.GovernanceDelegations>() ?: return null
|
||||
|
||||
return runCatching {
|
||||
val referendum = delegateSubqueryApi.getReferendumVotes(api.url, ReferendumVotesRequest(referendumId.value))
|
||||
.data
|
||||
.referendum
|
||||
|
||||
val voters = referendum.castingVotings.nodes
|
||||
|
||||
var totalVoting = VotingInfo.Full.empty()
|
||||
|
||||
voters.forEach {
|
||||
totalVoting += it.toOffChainVotes()
|
||||
}
|
||||
|
||||
OffChainReferendumVotingDetails(TrackId(referendum.trackId), totalVoting)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private fun bindTrackLocks(decoded: Any?): List<Pair<TrackId, Balance>> {
|
||||
return bindList(decoded) { item ->
|
||||
val (trackId, balance) = item.castToList()
|
||||
|
||||
TrackId(bindNumber(trackId)) to bindNumber(balance)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapVoterFromRemote(voter: ReferendumVoterRemote, chain: Chain, expectedType: VoteType): ReferendumVoter? {
|
||||
val accountVote = mapMultiVoteRemoteToAccountVote(voter)
|
||||
if (!accountVote.votedFor(expectedType)) return null
|
||||
|
||||
val delegators = voter.delegatorVotes.nodes
|
||||
|
||||
return ReferendumVoter(
|
||||
accountId = chain.accountIdOf(voter.voterId),
|
||||
vote = accountVote,
|
||||
delegators = delegators.map {
|
||||
Delegation(
|
||||
vote = Delegation.Vote(it.vote.amount, mapConvictionFromString(it.vote.conviction)),
|
||||
delegator = chain.accountIdOf(it.delegatorId),
|
||||
delegate = chain.accountIdOf(voter.voterId),
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v2
|
||||
|
||||
import io.novafoundation.nova.common.utils.formatNamed
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.core_db.model.GovernanceDAppLocal
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.GovernanceDAppsRepository
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.details.ReferendumDApp
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GovV2DAppsRepository(
|
||||
private val governanceDAppsDao: GovernanceDAppsDao
|
||||
) : GovernanceDAppsRepository {
|
||||
|
||||
override fun observeReferendumDApps(chainId: ChainId, referendumId: ReferendumId): Flow<List<ReferendumDApp>> {
|
||||
return governanceDAppsDao.observeChainDapps(chainId)
|
||||
.map { dapps ->
|
||||
val v1Dapps = dapps.filter { it.referendumUrlV2 != null }
|
||||
mapV2DappsLocalToDomain(referendumId, v1Dapps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapV2DappsLocalToDomain(referendumId: ReferendumId, dapps: List<GovernanceDAppLocal>): List<ReferendumDApp> {
|
||||
return dapps.map {
|
||||
ReferendumDApp(
|
||||
it.chainId,
|
||||
it.name,
|
||||
it.referendumUrlV2?.formatNamed("referendumId" to referendumId.value.toString())!!,
|
||||
it.iconUrl,
|
||||
it.details
|
||||
)
|
||||
}
|
||||
}
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.repository.v2
|
||||
|
||||
import android.util.Log
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.BlockNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindAccountId
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindBlockNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindBoolean
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindFixedI64
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindList
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindPerbill
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindString
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToDictEnum
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToList
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.getTyped
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.incompatible
|
||||
import io.novafoundation.nova.common.utils.LOG_TAG
|
||||
import io.novafoundation.nova.common.utils.constant
|
||||
import io.novafoundation.nova.common.utils.decodedValue
|
||||
import io.novafoundation.nova.common.utils.filterNotNull
|
||||
import io.novafoundation.nova.common.utils.numberConstant
|
||||
import io.novafoundation.nova.common.utils.referenda
|
||||
import io.novafoundation.nova.common.utils.scheduler
|
||||
import io.novafoundation.nova.common.utils.toByteArray
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ConfirmingSource
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ConfirmingStatus
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.DecidingStatus
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.OnChainReferendum
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.OnChainReferendumStatus
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumDeposit
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.ReferendumId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackId
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackInfo
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.TrackQueue
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.VotingCurve
|
||||
import io.novafoundation.nova.feature_governance_api.data.network.blockhain.model.empty
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.OnChainReferendaRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.getTracksById
|
||||
import io.novafoundation.nova.feature_governance_api.data.thresold.gov2.Gov2VotingThreshold
|
||||
import io.novafoundation.nova.feature_governance_api.data.thresold.gov2.curve.LinearDecreasingCurve
|
||||
import io.novafoundation.nova.feature_governance_api.data.thresold.gov2.curve.ReciprocalCurve
|
||||
import io.novafoundation.nova.feature_governance_api.data.thresold.gov2.curve.SteppedDecreasingCurve
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.bindProposal
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.common.bindTally
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
import io.novafoundation.nova.runtime.multiNetwork.getRuntime
|
||||
import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository
|
||||
import io.novafoundation.nova.runtime.repository.getActiveIssuance
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novasama.substrate_sdk_android.extensions.fromHex
|
||||
import io.novasama.substrate_sdk_android.extensions.toHexString
|
||||
import io.novasama.substrate_sdk_android.hash.Hasher.blake2b256
|
||||
import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.DictEnum
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.Struct
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.primitives.u32
|
||||
import io.novasama.substrate_sdk_android.runtime.definitions.types.toByteArray
|
||||
import io.novasama.substrate_sdk_android.runtime.metadata.storage
|
||||
import io.novasama.substrate_sdk_android.scale.dataType.string
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.math.BigInteger
|
||||
|
||||
private const val ASSEMBLY_ID = "assembly"
|
||||
|
||||
class GovV2OnChainReferendaRepository(
|
||||
private val remoteStorageSource: StorageDataSource,
|
||||
private val chainRegistry: ChainRegistry,
|
||||
private val totalIssuanceRepository: TotalIssuanceRepository,
|
||||
) : OnChainReferendaRepository {
|
||||
|
||||
override suspend fun electorate(chainId: ChainId): Balance {
|
||||
return totalIssuanceRepository.getActiveIssuance(chainId)
|
||||
}
|
||||
|
||||
override suspend fun undecidingTimeout(chainId: ChainId): BlockNumber {
|
||||
val runtime = chainRegistry.getRuntime(chainId)
|
||||
|
||||
return runtime.metadata.referenda().numberConstant("UndecidingTimeout", runtime)
|
||||
}
|
||||
|
||||
override suspend fun getTracks(chainId: ChainId): Collection<TrackInfo> {
|
||||
val runtime = chainRegistry.getRuntime(chainId)
|
||||
val tracksConstant = runtime.metadata.referenda().constant("Tracks").decodedValue(runtime)
|
||||
|
||||
return bindTracks(tracksConstant)
|
||||
}
|
||||
|
||||
override suspend fun getTrackQueues(trackIds: Set<TrackId>, chainId: ChainId): Map<TrackId, TrackQueue> {
|
||||
if (trackIds.isEmpty()) return emptyMap()
|
||||
return remoteStorageSource.query(chainId) {
|
||||
runtime.metadata.referenda().storage("TrackQueue").entries(
|
||||
keysArguments = trackIds.map { listOf(it.value) },
|
||||
keyExtractor = { (trackIdRaw: BigInteger) -> TrackId(trackIdRaw) },
|
||||
binding = { decoded, _ -> bindTrackQueue(decoded) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAllOnChainReferenda(chainId: ChainId): Collection<OnChainReferendum> {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
val allTracks = getTracksById(chainId)
|
||||
|
||||
runtime.metadata.referenda().storage("ReferendumInfoFor").entries(
|
||||
prefixArgs = emptyArray(),
|
||||
keyExtractor = { (id: BigInteger) -> ReferendumId(id) },
|
||||
binding = { decoded, id -> bindReferendum(decoded, id, allTracks, runtime) }
|
||||
).values.filterNotNull()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getOnChainReferenda(chainId: ChainId, referendaIds: Collection<ReferendumId>): Map<ReferendumId, OnChainReferendum> {
|
||||
return remoteStorageSource.query(chainId) {
|
||||
val allTracks = getTracksById(chainId)
|
||||
|
||||
runtime.metadata.referenda().storage("ReferendumInfoFor").entries(
|
||||
keysArguments = referendaIds.map { id -> listOf(id.value) },
|
||||
keyExtractor = { (id: BigInteger) -> ReferendumId(id) },
|
||||
binding = { decoded, id -> bindReferendum(decoded, id, allTracks, runtime) }
|
||||
)
|
||||
}.filterNotNull()
|
||||
}
|
||||
|
||||
override suspend fun onChainReferendumFlow(chainId: ChainId, referendumId: ReferendumId): Flow<OnChainReferendum?> {
|
||||
return remoteStorageSource.subscribe(chainId) {
|
||||
val allTracks = getTracksById(chainId)
|
||||
|
||||
runtime.metadata.referenda().storage("ReferendumInfoFor").observe(
|
||||
referendumId.value,
|
||||
binding = { bindReferendum(it, referendumId, allTracks, runtime) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getReferendaExecutionBlocks(
|
||||
chainId: ChainId,
|
||||
approvedReferendaIds: Collection<ReferendumId>
|
||||
): Map<ReferendumId, BlockNumber> {
|
||||
if (approvedReferendaIds.isEmpty()) return emptyMap()
|
||||
|
||||
return remoteStorageSource.query(chainId) {
|
||||
val referendaIdBySchedulerId = approvedReferendaIds.associateBy { it.enactmentSchedulerId(runtime).toHexString() }
|
||||
|
||||
runtime.metadata.scheduler().storage("Lookup").entries(
|
||||
keysArguments = referendaIdBySchedulerId.keys.map { schedulerIdHex -> listOf(schedulerIdHex.fromHex()) },
|
||||
keyExtractor = { (schedulerId: ByteArray) -> referendaIdBySchedulerId.getValue(schedulerId.toHexString()) },
|
||||
binding = { decoded, _ ->
|
||||
decoded?.let {
|
||||
val (blockNumber, _) = decoded.castToList()
|
||||
|
||||
bindBlockNumber(blockNumber)
|
||||
}
|
||||
}
|
||||
).filterNotNull()
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindReferendum(
|
||||
decoded: Any?,
|
||||
id: ReferendumId,
|
||||
tracksById: Map<TrackId, TrackInfo>,
|
||||
runtime: RuntimeSnapshot
|
||||
): OnChainReferendum? = runCatching {
|
||||
val asDictEnum = decoded.castToDictEnum()
|
||||
|
||||
val referendumStatus = when (asDictEnum.name) {
|
||||
"Ongoing" -> {
|
||||
val status = asDictEnum.value.castToStruct()
|
||||
val trackId = TrackId(bindNumber(status["track"]))
|
||||
val track = tracksById.getValue(trackId)
|
||||
|
||||
OnChainReferendumStatus.Ongoing(
|
||||
track = trackId,
|
||||
proposal = bindProposal(status["proposal"], runtime),
|
||||
submitted = bindBlockNumber(status["submitted"]),
|
||||
submissionDeposit = bindReferendumDeposit(status["submissionDeposit"])!!,
|
||||
decisionDeposit = bindReferendumDeposit(status["decisionDeposit"]),
|
||||
deciding = bindDecidingStatus(status["deciding"]),
|
||||
tally = bindTally(status.getTyped("tally")),
|
||||
inQueue = bindBoolean(status["inQueue"]),
|
||||
threshold = Gov2VotingThreshold(track),
|
||||
)
|
||||
}
|
||||
|
||||
"Approved" -> OnChainReferendumStatus.Approved(bindCompletedReferendumSince(asDictEnum.value))
|
||||
"Rejected" -> OnChainReferendumStatus.Rejected(bindCompletedReferendumSince(asDictEnum.value))
|
||||
"Cancelled" -> OnChainReferendumStatus.Cancelled(bindCompletedReferendumSince(asDictEnum.value))
|
||||
"TimedOut" -> OnChainReferendumStatus.TimedOut(bindCompletedReferendumSince(asDictEnum.value))
|
||||
"Killed" -> OnChainReferendumStatus.Killed(bindNumber(asDictEnum.value))
|
||||
else -> throw IllegalArgumentException("Unsupported referendum status")
|
||||
}
|
||||
|
||||
OnChainReferendum(
|
||||
id = id,
|
||||
status = referendumStatus
|
||||
)
|
||||
}
|
||||
.onFailure { Log.e(this.LOG_TAG, "Failed to decode on-chain referendum $id", it) }
|
||||
.getOrNull()
|
||||
|
||||
private fun bindDecidingStatus(decoded: Any?): DecidingStatus? {
|
||||
if (decoded == null) return null
|
||||
val decodedStruct = decoded.castToStruct()
|
||||
|
||||
val confirming = decodedStruct.get<Any?>("confirming")?.let {
|
||||
ConfirmingStatus(
|
||||
till = bindBlockNumber(it)
|
||||
)
|
||||
}
|
||||
return DecidingStatus(
|
||||
since = bindBlockNumber(decodedStruct["since"]),
|
||||
confirming = ConfirmingSource.OnChain(confirming)
|
||||
)
|
||||
}
|
||||
|
||||
private fun bindCompletedReferendumSince(decoded: Any?): BlockNumber {
|
||||
// first element in tuple
|
||||
val since = decoded.castToList().first()
|
||||
|
||||
return bindNumber(since)
|
||||
}
|
||||
|
||||
private fun bindReferendumDeposit(decoded: Struct.Instance?): ReferendumDeposit? {
|
||||
return decoded?.let {
|
||||
ReferendumDeposit(
|
||||
who = bindAccountId(it["who"]),
|
||||
amount = bindNumber(it["amount"])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindTracks(decoded: Any?): List<TrackInfo> {
|
||||
return bindList(decoded) {
|
||||
val (id, content) = it.castToList()
|
||||
val trackInfoStruct = content.castToStruct()
|
||||
|
||||
TrackInfo(
|
||||
id = TrackId(bindNumber(id)),
|
||||
name = bindString(trackInfoStruct["name"]),
|
||||
preparePeriod = bindBlockNumber(trackInfoStruct["preparePeriod"]),
|
||||
decisionPeriod = bindBlockNumber(trackInfoStruct["decisionPeriod"]),
|
||||
confirmPeriod = bindBlockNumber(trackInfoStruct["confirmPeriod"]),
|
||||
minApproval = bindCurve(trackInfoStruct.getTyped("minApproval")),
|
||||
minSupport = bindCurve(trackInfoStruct.getTyped("minSupport"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindCurve(decoded: DictEnum.Entry<*>): VotingCurve {
|
||||
val valueStruct = decoded.value.castToStruct()
|
||||
|
||||
return when (decoded.name) {
|
||||
"Reciprocal" -> {
|
||||
ReciprocalCurve(
|
||||
factor = bindFixedI64(valueStruct["factor"]),
|
||||
xOffset = bindFixedI64(valueStruct["x_offset"]),
|
||||
yOffset = bindFixedI64(valueStruct["y_offset"])
|
||||
)
|
||||
}
|
||||
|
||||
"LinearDecreasing" -> {
|
||||
LinearDecreasingCurve(
|
||||
length = bindPerbill(valueStruct["length"]),
|
||||
floor = bindPerbill(valueStruct["floor"]),
|
||||
ceil = bindPerbill(valueStruct["ceil"])
|
||||
)
|
||||
}
|
||||
|
||||
"SteppedDecreasing" -> {
|
||||
SteppedDecreasingCurve(
|
||||
begin = bindPerbill(valueStruct["begin"]),
|
||||
end = bindPerbill(valueStruct["end"]),
|
||||
step = bindPerbill(valueStruct["step"]),
|
||||
period = bindPerbill(valueStruct["period"])
|
||||
)
|
||||
}
|
||||
|
||||
else -> incompatible()
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindTrackQueue(decoded: Any?): TrackQueue {
|
||||
if (decoded == null) return TrackQueue.empty()
|
||||
|
||||
val referendumIds = bindList(decoded) {
|
||||
val (referendumIndex, _) = it.castToList()
|
||||
|
||||
ReferendumId(bindNumber(referendumIndex))
|
||||
}
|
||||
|
||||
return TrackQueue(referendumIds)
|
||||
}
|
||||
|
||||
// https://github.com/paritytech/substrate/blob/fc67cbb66d8c484bc7b7506fc1300344d12ecbad/frame/referenda/src/lib.rs#L716
|
||||
private fun ReferendumId.enactmentSchedulerId(runtime: RuntimeSnapshot): ByteArray {
|
||||
val encodedAssemblyId = ASSEMBLY_ID.encodeToByteArray() // 'const bytes' in rust
|
||||
val encodedEnactment = string.toByteArray("enactment") // 'string' in rust
|
||||
val encodedIndex = u32.toByteArray(runtime, value)
|
||||
|
||||
val toHash = encodedAssemblyId + encodedEnactment + encodedIndex
|
||||
|
||||
return toHash.blake2b256()
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.source
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSource
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.SupportedGovernanceOption
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
|
||||
internal class RealGovernanceSourceRegistry(
|
||||
private val governanceV2Source: GovernanceSource,
|
||||
private val governanceV1Source: GovernanceSource,
|
||||
) : GovernanceSourceRegistry {
|
||||
|
||||
override suspend fun sourceFor(option: SupportedGovernanceOption): GovernanceSource {
|
||||
return sourceFor(option.additional.governanceType)
|
||||
}
|
||||
|
||||
override suspend fun sourceFor(option: Chain.Governance): GovernanceSource {
|
||||
return when (option) {
|
||||
Chain.Governance.V1 -> governanceV1Source
|
||||
Chain.Governance.V2 -> governanceV2Source
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.data.source
|
||||
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.ConvictionVotingRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.DelegationsRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.GovernanceDAppsRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.OffChainReferendaInfoRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.OnChainReferendaRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.PreImageRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSource
|
||||
|
||||
internal class StaticGovernanceSource(
|
||||
override val referenda: OnChainReferendaRepository,
|
||||
override val convictionVoting: ConvictionVotingRepository,
|
||||
override val offChainInfo: OffChainReferendaInfoRepository,
|
||||
override val preImageRepository: PreImageRepository,
|
||||
override val dappsRepository: GovernanceDAppsRepository,
|
||||
override val delegationsRepository: DelegationsRepository
|
||||
) : GovernanceSource
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di
|
||||
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import io.novafoundation.nova.common.di.CommonApi
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.core_db.di.DbApi
|
||||
import io.novafoundation.nova.feature_account_api.di.AccountFeatureApi
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.list.SelectTracksCommunicator
|
||||
import io.novafoundation.nova.feature_dapp_api.di.DAppFeatureApi
|
||||
import io.novafoundation.nova.feature_deep_linking.di.DeepLinkingFeatureApi
|
||||
import io.novafoundation.nova.feature_governance_api.di.GovernanceFeatureApi
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.GovernanceRouter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.description.di.DescriptionComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.description.di.ReferendumInfoComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.delegators.di.DelegateDelegatorsComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.detail.main.di.DelegateDetailsComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.detail.votedReferenda.di.VotedReferendaComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.list.di.DelegateListComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.search.di.DelegateSearchComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegated.di.YourDelegationsComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegation.create.chooseAmount.di.NewDelegationChooseAmountComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegation.create.chooseTrack.di.NewDelegationChooseTracksComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegation.create.confirm.di.NewDelegationConfirmComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegation.removeVotes.di.RemoveVotesComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegation.revoke.chooseTracks.di.RevokeDelegationChooseTracksComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegation.revoke.confirm.di.RevokeDelegationConfirmComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.details.di.ReferendumDetailsComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.filters.di.ReferendaFiltersComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.full.di.ReferendumFullDetailsComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.list.di.ReferendaListComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.search.di.ReferendaSearchComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.confirm.di.ConfirmReferendumVoteComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.setup.referenda.di.SetupReferendumVoteComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.setup.tindergov.di.SetupTinderGovVoteComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.setup.tindergov.TinderGovVoteCommunicator
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.voters.di.ReferendumVotersComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.tindergov.basket.di.TinderGovBasketComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.tindergov.cards.di.TinderGovCardsComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.tindergov.confirm.di.ConfirmTinderGovVoteComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.tracks.select.governanceTracks.di.SelectGovernanceTracksComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.unlock.confirm.di.ConfirmGovernanceUnlockComponent
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.unlock.list.di.GovernanceLocksOverviewComponent
|
||||
import io.novafoundation.nova.feature_wallet_api.di.WalletFeatureApi
|
||||
import io.novafoundation.nova.feature_xcm_api.di.XcmFeatureApi
|
||||
import io.novafoundation.nova.runtime.di.RuntimeApi
|
||||
|
||||
@Component(
|
||||
dependencies = [
|
||||
GovernanceFeatureDependencies::class,
|
||||
],
|
||||
modules = [
|
||||
GovernanceFeatureModule::class,
|
||||
]
|
||||
)
|
||||
@FeatureScope
|
||||
interface GovernanceFeatureComponent : GovernanceFeatureApi {
|
||||
|
||||
fun referendaListFactory(): ReferendaListComponent.Factory
|
||||
|
||||
fun referendaSearchFactory(): ReferendaSearchComponent.Factory
|
||||
|
||||
fun referendumDetailsFactory(): ReferendumDetailsComponent.Factory
|
||||
|
||||
fun descriptionFactory(): DescriptionComponent.Factory
|
||||
|
||||
fun referendumInfoFactory(): ReferendumInfoComponent.Factory
|
||||
|
||||
fun referendumFullDetailsFactory(): ReferendumFullDetailsComponent.Factory
|
||||
|
||||
fun setupReferendumVoteFactory(): SetupReferendumVoteComponent.Factory
|
||||
|
||||
fun setupTinderGovVoteFactory(): SetupTinderGovVoteComponent.Factory
|
||||
|
||||
fun confirmReferendumVoteFactory(): ConfirmReferendumVoteComponent.Factory
|
||||
|
||||
fun confirmTinderGovVoteFactory(): ConfirmTinderGovVoteComponent.Factory
|
||||
|
||||
fun referendumVotersFactory(): ReferendumVotersComponent.Factory
|
||||
|
||||
fun confirmGovernanceUnlockFactory(): ConfirmGovernanceUnlockComponent.Factory
|
||||
|
||||
fun governanceLocksOverviewFactory(): GovernanceLocksOverviewComponent.Factory
|
||||
|
||||
fun delegateListFactory(): DelegateListComponent.Factory
|
||||
|
||||
fun delegateSearchFactory(): DelegateSearchComponent.Factory
|
||||
|
||||
fun delegateDetailsFactory(): DelegateDetailsComponent.Factory
|
||||
|
||||
fun votedReferendaFactory(): VotedReferendaComponent.Factory
|
||||
|
||||
fun removeVoteFactory(): RemoveVotesComponent.Factory
|
||||
|
||||
fun delegateDelegatorsFactory(): DelegateDelegatorsComponent.Factory
|
||||
|
||||
fun yourDelegationsFactory(): YourDelegationsComponent.Factory
|
||||
|
||||
fun newDelegationChooseTracks(): NewDelegationChooseTracksComponent.Factory
|
||||
|
||||
fun selectGovernanceTracks(): SelectGovernanceTracksComponent.Factory
|
||||
|
||||
fun newDelegationChooseAmountFactory(): NewDelegationChooseAmountComponent.Factory
|
||||
|
||||
fun newDelegationConfirmFactory(): NewDelegationConfirmComponent.Factory
|
||||
|
||||
fun revokeDelegationChooseTracksFactory(): RevokeDelegationChooseTracksComponent.Factory
|
||||
|
||||
fun revokeDelegationConfirmFactory(): RevokeDelegationConfirmComponent.Factory
|
||||
|
||||
fun referendaFiltersFactory(): ReferendaFiltersComponent.Factory
|
||||
|
||||
fun tinderGovCardsFactory(): TinderGovCardsComponent.Factory
|
||||
|
||||
fun tinderGovBasketFactory(): TinderGovBasketComponent.Factory
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
|
||||
fun create(
|
||||
deps: GovernanceFeatureDependencies,
|
||||
@BindsInstance router: GovernanceRouter,
|
||||
@BindsInstance selectTracksCommunicator: SelectTracksCommunicator,
|
||||
@BindsInstance tinderGovVoteCommunicator: TinderGovVoteCommunicator
|
||||
): GovernanceFeatureComponent
|
||||
}
|
||||
|
||||
@Component(
|
||||
dependencies = [
|
||||
CommonApi::class,
|
||||
RuntimeApi::class,
|
||||
WalletFeatureApi::class,
|
||||
AccountFeatureApi::class,
|
||||
DAppFeatureApi::class,
|
||||
DbApi::class,
|
||||
XcmFeatureApi::class,
|
||||
DeepLinkingFeatureApi::class
|
||||
]
|
||||
)
|
||||
interface GovernanceFeatureDependenciesComponent : GovernanceFeatureDependencies
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di
|
||||
|
||||
import android.content.Context
|
||||
import coil.ImageLoader
|
||||
import com.google.gson.Gson
|
||||
import io.novafoundation.nova.common.address.AddressIconGenerator
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.data.network.NetworkApiCreator
|
||||
import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository
|
||||
import io.novafoundation.nova.common.data.storage.Preferences
|
||||
import io.novafoundation.nova.common.di.modules.Caching
|
||||
import io.novafoundation.nova.common.mixin.actionAwaitable.ActionAwaitableMixin
|
||||
import io.novafoundation.nova.common.mixin.copy.CopyTextLauncher
|
||||
import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory
|
||||
import io.novafoundation.nova.common.presentation.AssetIconProvider
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.common.utils.multiResult.PartialRetriableMixin
|
||||
import io.novafoundation.nova.common.utils.sequrity.AutomaticInteractionGate
|
||||
import io.novafoundation.nova.common.validation.ValidationExecutor
|
||||
import io.novafoundation.nova.common.view.input.chooser.ListChooserMixin
|
||||
import io.novafoundation.nova.core.storage.StorageCache
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.core_db.dao.TinderGovDao
|
||||
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
|
||||
import io.novafoundation.nova.feature_account_api.data.repository.OnChainIdentityRepository
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.IdentityProvider
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.LocalIdentity
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.OnChainIdentity
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.WalletUiUseCase
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.mixin.identity.IdentityMixin
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.navigation.ExtrinsicNavigationWrapper
|
||||
import io.novafoundation.nova.feature_dapp_api.data.repository.DAppMetadataRepository
|
||||
import io.novafoundation.nova.feature_deep_linking.presentation.configuring.LinkBuilderFactory
|
||||
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository
|
||||
import io.novafoundation.nova.feature_wallet_api.domain.interfaces.TokenRepository
|
||||
import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.AmountFormatter
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.TokenFormatter
|
||||
import io.novafoundation.nova.common.presentation.masking.formatter.MaskableValueFormatterFactory
|
||||
import io.novafoundation.nova.common.presentation.masking.formatter.MaskableValueFormatterProvider
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.formatters.AssetModelFormatter
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.mixin.amountChooser.AmountChooserMixin
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.mixin.fee.FeeLoaderMixin
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.mixin.fee.v2.FeeLoaderMixinV2
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.mixin.maxAction.MaxActionProviderFactory
|
||||
import io.novafoundation.nova.feature_xcm_api.converter.MultiLocationConverterFactory
|
||||
import io.novafoundation.nova.feature_xcm_api.converter.chain.ChainMultiLocationConverterFactory
|
||||
import io.novafoundation.nova.runtime.di.ExtrinsicSerialization
|
||||
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
|
||||
import io.novafoundation.nova.runtime.ethereum.StorageSharedRequestsBuilderFactory
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.repository.ChainStateRepository
|
||||
import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository
|
||||
import io.novafoundation.nova.runtime.storage.SampledBlockTimeStorage
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import javax.inject.Named
|
||||
|
||||
interface GovernanceFeatureDependencies {
|
||||
|
||||
val maskableValueFormatterFactory: MaskableValueFormatterFactory
|
||||
|
||||
val maskableValueFormatterProvider: MaskableValueFormatterProvider
|
||||
|
||||
val amountFormatter: AmountFormatter
|
||||
|
||||
val tokenFormatter: TokenFormatter
|
||||
|
||||
val onChainIdentityRepository: OnChainIdentityRepository
|
||||
|
||||
val listChooserMixinFactory: ListChooserMixin.Factory
|
||||
|
||||
val identityMixinFactory: IdentityMixin.Factory
|
||||
|
||||
val partialRetriableMixinFactory: PartialRetriableMixin.Factory
|
||||
|
||||
val storageStorageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory
|
||||
|
||||
val bannerVisibilityRepository: BannerVisibilityRepository
|
||||
|
||||
val assetModelFormatter: AssetModelFormatter
|
||||
|
||||
val chainMultiLocationConverterFactory: ChainMultiLocationConverterFactory
|
||||
|
||||
val assetMultiLocationConverterFactory: MultiLocationConverterFactory
|
||||
|
||||
val assetIconProvider: AssetIconProvider
|
||||
|
||||
val feeLoaderMixinFactory: FeeLoaderMixin.Factory
|
||||
|
||||
val validationExecutor: ValidationExecutor
|
||||
|
||||
val preferences: Preferences
|
||||
|
||||
val walletRepository: WalletRepository
|
||||
|
||||
val chainRegistry: ChainRegistry
|
||||
|
||||
val imageLoader: ImageLoader
|
||||
|
||||
val addressIconGenerator: AddressIconGenerator
|
||||
|
||||
val resourceManager: ResourceManager
|
||||
|
||||
val actionAwaitableMixinFactory: ActionAwaitableMixin.Factory
|
||||
|
||||
val tokenRepository: TokenRepository
|
||||
|
||||
val accountRepository: AccountRepository
|
||||
|
||||
val selectedAccountUseCase: SelectedAccountUseCase
|
||||
|
||||
val chainStateRepository: ChainStateRepository
|
||||
|
||||
val totalIssuanceRepository: TotalIssuanceRepository
|
||||
|
||||
val storageCache: StorageCache
|
||||
|
||||
val sampledBlockTimeStorage: SampledBlockTimeStorage
|
||||
|
||||
val dAppMetadataRepository: DAppMetadataRepository
|
||||
|
||||
val externalAccountActions: ExternalActions.Presentation
|
||||
|
||||
val context: Context
|
||||
|
||||
val amountMixinFactory: AmountChooserMixin.Factory
|
||||
|
||||
val extrinsicService: ExtrinsicService
|
||||
|
||||
val resourceHintsMixinFactory: ResourcesHintsMixinFactory
|
||||
|
||||
val walletUiUseCase: WalletUiUseCase
|
||||
|
||||
val balanceLocksRepository: BalanceLocksRepository
|
||||
|
||||
val computationalCache: ComputationalCache
|
||||
|
||||
val governanceDAppsDao: GovernanceDAppsDao
|
||||
|
||||
val tinderGovDao: TinderGovDao
|
||||
|
||||
val networkApiCreator: NetworkApiCreator
|
||||
|
||||
val feeLoaderMixinV2Factory: FeeLoaderMixinV2.Factory
|
||||
|
||||
val maxActionProviderFactory: MaxActionProviderFactory
|
||||
|
||||
val automaticInteractionGate: AutomaticInteractionGate
|
||||
|
||||
val linkBuilderFactory: LinkBuilderFactory
|
||||
|
||||
val extrinsicNavigationWrapper: ExtrinsicNavigationWrapper
|
||||
|
||||
val copyTextLauncher: CopyTextLauncher.Presentation
|
||||
|
||||
@Caching
|
||||
fun cachingIconGenerator(): AddressIconGenerator
|
||||
|
||||
@ExtrinsicSerialization
|
||||
fun extrinsicGson(): Gson
|
||||
|
||||
@LocalIdentity
|
||||
fun localIdentityProvider(): IdentityProvider
|
||||
|
||||
@OnChainIdentity
|
||||
fun onChainIdentityProvider(): IdentityProvider
|
||||
|
||||
@Named(REMOTE_STORAGE_SOURCE)
|
||||
fun remoteStorageDataSource(): StorageDataSource
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di
|
||||
|
||||
import io.novafoundation.nova.common.di.FeatureApiHolder
|
||||
import io.novafoundation.nova.common.di.FeatureContainer
|
||||
import io.novafoundation.nova.common.di.scope.ApplicationScope
|
||||
import io.novafoundation.nova.core_db.di.DbApi
|
||||
import io.novafoundation.nova.feature_account_api.di.AccountFeatureApi
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.account.wallet.list.SelectTracksCommunicator
|
||||
import io.novafoundation.nova.feature_dapp_api.di.DAppFeatureApi
|
||||
import io.novafoundation.nova.feature_deep_linking.di.DeepLinkingFeatureApi
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.GovernanceRouter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.setup.tindergov.TinderGovVoteCommunicator
|
||||
import io.novafoundation.nova.feature_wallet_api.di.WalletFeatureApi
|
||||
import io.novafoundation.nova.feature_xcm_api.di.XcmFeatureApi
|
||||
import io.novafoundation.nova.runtime.di.RuntimeApi
|
||||
import javax.inject.Inject
|
||||
|
||||
@ApplicationScope
|
||||
class GovernanceFeatureHolder @Inject constructor(
|
||||
featureContainer: FeatureContainer,
|
||||
private val router: GovernanceRouter,
|
||||
private val selectTracksCommunicator: SelectTracksCommunicator,
|
||||
private val tinderGovVoteCommunicator: TinderGovVoteCommunicator
|
||||
) : FeatureApiHolder(featureContainer) {
|
||||
|
||||
override fun initializeDependencies(): Any {
|
||||
val accountFeatureDependencies = DaggerGovernanceFeatureComponent_GovernanceFeatureDependenciesComponent.builder()
|
||||
.commonApi(commonApi())
|
||||
.dbApi(getFeature(DbApi::class.java))
|
||||
.runtimeApi(getFeature(RuntimeApi::class.java))
|
||||
.walletFeatureApi(getFeature(WalletFeatureApi::class.java))
|
||||
.accountFeatureApi(getFeature(AccountFeatureApi::class.java))
|
||||
.dAppFeatureApi(getFeature(DAppFeatureApi::class.java))
|
||||
.xcmFeatureApi(getFeature(XcmFeatureApi::class.java))
|
||||
.deepLinkingFeatureApi(getFeature(DeepLinkingFeatureApi::class.java))
|
||||
.build()
|
||||
|
||||
return DaggerGovernanceFeatureComponent.factory()
|
||||
.create(
|
||||
accountFeatureDependencies,
|
||||
router,
|
||||
selectTracksCommunicator = selectTracksCommunicator,
|
||||
tinderGovVoteCommunicator = tinderGovVoteCommunicator
|
||||
)
|
||||
}
|
||||
}
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.address.AddressIconGenerator
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.data.model.MaskingMode
|
||||
import io.novafoundation.nova.common.data.storage.Preferences
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.common.presentation.AssetIconProvider
|
||||
import io.novafoundation.nova.common.presentation.masking.formatter.MaskableValueFormatterFactory
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.feature_account_api.data.repository.OnChainIdentityRepository
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.IdentityProvider
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.LocalIdentity
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.OnChainIdentity
|
||||
import io.novafoundation.nova.feature_governance_api.data.MutableGovernanceState
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.TreasuryRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSource
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_api.presentation.referenda.common.ReferendaStatusFormatter
|
||||
import io.novafoundation.nova.feature_governance_api.presentation.referenda.details.deeplink.configurators.ReferendumDetailsDeepLinkConfigurator
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.feature_governance_impl.data.preimage.PreImageSizer
|
||||
import io.novafoundation.nova.feature_governance_impl.data.preimage.RealPreImageSizer
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.RealTreasuryRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.source.RealGovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.GovernanceDAppsModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.GovernanceUpdatersModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.deeplink.DeepLinkModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.screens.DelegateModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.screens.ReferendumDetailsModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.screens.ReferendumListModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.screens.ReferendumUnlockModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.screens.ReferendumVoteModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.screens.ReferendumVotersModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.screens.TinderGovModule
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.v1.GovernanceV1
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.v1.GovernanceV1Module
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.v2.GovernanceV2
|
||||
import io.novafoundation.nova.feature_governance_impl.di.modules.v2.GovernanceV2Module
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.common.repository.DelegateCommonRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.identity.GovernanceIdentityProviderFactory
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.common.RealReferendaConstructor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.common.ReferendaConstructor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.track.RealTracksUseCase
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.track.TracksUseCase
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.track.category.RealTrackCategorizer
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.track.category.TrackCategorizer
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.conviction.ConvictionValuesProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.conviction.RealConvictionValuesProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.locks.LocksFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.locks.RealLocksFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.share.RealShareReferendumMixin
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.share.ShareReferendumMixin
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.voters.RealVotersFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.voters.VotersFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.detail.DelegatesSharedComputation
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.common.RealReferendaStatusFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.common.ReferendumFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.common.ReferendumFormatterFactory
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.track.RealTrackFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.track.TrackFormatter
|
||||
import io.novafoundation.nova.feature_wallet_api.di.common.SelectableAssetUseCaseModule
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.AmountFormatter
|
||||
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.network.updaters.multiChain.DelegateToTimelineChainIdHolder
|
||||
import io.novafoundation.nova.runtime.repository.ChainStateRepository
|
||||
import io.novafoundation.nova.runtime.state.SelectableSingleAssetSharedState
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import javax.inject.Named
|
||||
|
||||
@Module(
|
||||
includes = [
|
||||
SelectableAssetUseCaseModule::class,
|
||||
GovernanceV2Module::class,
|
||||
GovernanceV1Module::class,
|
||||
GovernanceUpdatersModule::class,
|
||||
ReferendumDetailsModule::class,
|
||||
ReferendumListModule::class,
|
||||
ReferendumVotersModule::class,
|
||||
ReferendumVoteModule::class,
|
||||
ReferendumUnlockModule::class,
|
||||
DelegateModule::class,
|
||||
GovernanceDAppsModule::class,
|
||||
TinderGovModule::class,
|
||||
DeepLinkModule::class
|
||||
]
|
||||
)
|
||||
class GovernanceFeatureModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTimelineDelegatingHolder(stakingSharedState: GovernanceSharedState) = DelegateToTimelineChainIdHolder(stakingSharedState)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDelegatesSharedComputation(
|
||||
computationalCache: ComputationalCache,
|
||||
delegateCommonRepository: DelegateCommonRepository,
|
||||
chainStateRepository: ChainStateRepository,
|
||||
identityRepository: OnChainIdentityRepository
|
||||
) = DelegatesSharedComputation(
|
||||
computationalCache,
|
||||
delegateCommonRepository,
|
||||
chainStateRepository,
|
||||
identityRepository
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideAssetSharedState(
|
||||
chainRegistry: ChainRegistry,
|
||||
preferences: Preferences,
|
||||
) = GovernanceSharedState(chainRegistry, preferences)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideGovernanceStateUpdater(
|
||||
governanceSharedState: GovernanceSharedState
|
||||
): MutableGovernanceState = governanceSharedState
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideSelectableSharedState(governanceSharedState: GovernanceSharedState): SelectableSingleAssetSharedState<*> = governanceSharedState
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideGovernanceSourceRegistry(
|
||||
@GovernanceV2 governanceV2Source: GovernanceSource,
|
||||
@GovernanceV1 governanceV1Source: GovernanceSource,
|
||||
): GovernanceSourceRegistry = RealGovernanceSourceRegistry(
|
||||
governanceV2Source = governanceV2Source,
|
||||
governanceV1Source = governanceV1Source
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTreasuryRepository(
|
||||
@Named(REMOTE_STORAGE_SOURCE) storageSource: StorageDataSource
|
||||
): TreasuryRepository = RealTreasuryRepository(storageSource)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendumConstructor(
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
chainStateRepository: ChainStateRepository
|
||||
): ReferendaConstructor = RealReferendaConstructor(governanceSourceRegistry, chainStateRepository)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideGovernanceIdentityProviderFactory(
|
||||
@LocalIdentity localProvider: IdentityProvider,
|
||||
@OnChainIdentity onChainProvider: IdentityProvider
|
||||
): GovernanceIdentityProviderFactory = GovernanceIdentityProviderFactory(
|
||||
localProvider = localProvider,
|
||||
onChainProvider = onChainProvider
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun providePreImageSizer(): PreImageSizer = RealPreImageSizer()
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTrackCategorizer(): TrackCategorizer = RealTrackCategorizer()
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTracksFormatter(
|
||||
trackCategorizer: TrackCategorizer,
|
||||
resourceManager: ResourceManager,
|
||||
assetIconProvider: AssetIconProvider
|
||||
): TrackFormatter = RealTrackFormatter(trackCategorizer, resourceManager, assetIconProvider)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaStatusFormatter(
|
||||
resourceManager: ResourceManager
|
||||
): ReferendaStatusFormatter = RealReferendaStatusFormatter(resourceManager)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendumFormatterFactory(
|
||||
resourceManager: ResourceManager,
|
||||
trackFormatter: TrackFormatter,
|
||||
referendaStatusFormatter: ReferendaStatusFormatter,
|
||||
amountFormatter: AmountFormatter
|
||||
) = ReferendumFormatterFactory(
|
||||
resourceManager,
|
||||
trackFormatter,
|
||||
referendaStatusFormatter,
|
||||
amountFormatter
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDefaultReferendumFormatter(
|
||||
referendumFormatterFactory: ReferendumFormatterFactory,
|
||||
maskableValueFormatterFactory: MaskableValueFormatterFactory
|
||||
): ReferendumFormatter = referendumFormatterFactory.create(maskableValueFormatterFactory.create(MaskingMode.DISABLED))
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideVotersFormatter(
|
||||
resourceManager: ResourceManager,
|
||||
addressIconGenerator: AddressIconGenerator
|
||||
): VotersFormatter = RealVotersFormatter(addressIconGenerator, resourceManager)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideLocksFormatter(
|
||||
resourceManager: ResourceManager,
|
||||
amountFormatter: AmountFormatter
|
||||
): LocksFormatter = RealLocksFormatter(resourceManager, amountFormatter)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideConvictionValuesProvider(): ConvictionValuesProvider = RealConvictionValuesProvider()
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTracksUseCase(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
): TracksUseCase = RealTracksUseCase(governanceSharedState, governanceSourceRegistry)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideShareReferendumMixin(
|
||||
referendumLinkConfigurator: ReferendumDetailsDeepLinkConfigurator
|
||||
): ShareReferendumMixin = RealShareReferendumMixin(referendumLinkConfigurator)
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.data.network.NetworkApiCreator
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_impl.data.dapps.GovernanceDAppsSyncService
|
||||
import io.novafoundation.nova.feature_governance_impl.data.dapps.remote.GovernanceDappsFetcher
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.dapp.GovernanceDAppsInteractor
|
||||
|
||||
@Module
|
||||
class GovernanceDAppsModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideGovernanceDappsFetcher(apiCreator: NetworkApiCreator) = apiCreator.create(GovernanceDappsFetcher::class.java)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideGovernanceSyncService(
|
||||
dao: GovernanceDAppsDao,
|
||||
chainFetcher: GovernanceDappsFetcher
|
||||
) = GovernanceDAppsSyncService(dao, chainFetcher)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideGovernanceDAppInteractor(
|
||||
governanceDAppsSyncService: GovernanceDAppsSyncService,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry
|
||||
): GovernanceDAppsInteractor = GovernanceDAppsInteractor(
|
||||
governanceDAppsSyncService = governanceDAppsSyncService,
|
||||
governanceSourceRegistry = governanceSourceRegistry
|
||||
)
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.core.storage.StorageCache
|
||||
import io.novafoundation.nova.core.updater.UpdateSystem
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
|
||||
import io.novafoundation.nova.runtime.ethereum.StorageSharedRequestsBuilderFactory
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.network.updaters.BlockTimeUpdater
|
||||
import io.novafoundation.nova.runtime.network.updaters.InactiveIssuanceUpdater
|
||||
import io.novafoundation.nova.runtime.network.updaters.SharedAssetBlockNumberUpdater
|
||||
import io.novafoundation.nova.runtime.network.updaters.TotalIssuanceUpdater
|
||||
import io.novafoundation.nova.runtime.network.updaters.multiChain.AsSharedStateUpdater
|
||||
import io.novafoundation.nova.runtime.network.updaters.multiChain.DelegateToTimeLineChainUpdater
|
||||
import io.novafoundation.nova.runtime.network.updaters.multiChain.DelegateToTimelineChainIdHolder
|
||||
import io.novafoundation.nova.runtime.network.updaters.multiChain.GroupBySyncChainMultiChainUpdateSystem
|
||||
import io.novafoundation.nova.runtime.storage.SampledBlockTimeStorage
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import javax.inject.Named
|
||||
|
||||
@Module
|
||||
class GovernanceUpdatersModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideUpdateSystem(
|
||||
totalIssuanceUpdater: TotalIssuanceUpdater,
|
||||
inactiveIssuanceUpdater: InactiveIssuanceUpdater,
|
||||
blockNumberUpdater: SharedAssetBlockNumberUpdater,
|
||||
blockTimeUpdater: BlockTimeUpdater,
|
||||
chainRegistry: ChainRegistry,
|
||||
singleAssetSharedState: GovernanceSharedState,
|
||||
storageSharedRequestsBuilderFactory: StorageSharedRequestsBuilderFactory,
|
||||
): UpdateSystem = GroupBySyncChainMultiChainUpdateSystem(
|
||||
updaters = listOf(
|
||||
AsSharedStateUpdater(totalIssuanceUpdater),
|
||||
AsSharedStateUpdater(inactiveIssuanceUpdater),
|
||||
DelegateToTimeLineChainUpdater(blockNumberUpdater),
|
||||
DelegateToTimeLineChainUpdater(blockTimeUpdater),
|
||||
),
|
||||
chainRegistry = chainRegistry,
|
||||
singleAssetSharedState = singleAssetSharedState,
|
||||
storageSharedRequestsBuilderFactory = storageSharedRequestsBuilderFactory,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun blockTimeUpdater(
|
||||
chainIdHolder: DelegateToTimelineChainIdHolder,
|
||||
chainRegistry: ChainRegistry,
|
||||
sampledBlockTimeStorage: SampledBlockTimeStorage,
|
||||
@Named(REMOTE_STORAGE_SOURCE) remoteStorage: StorageDataSource,
|
||||
) = BlockTimeUpdater(chainIdHolder, chainRegistry, sampledBlockTimeStorage, remoteStorage)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideBlockNumberUpdater(
|
||||
chainRegistry: ChainRegistry,
|
||||
chainIdHolder: DelegateToTimelineChainIdHolder,
|
||||
storageCache: StorageCache,
|
||||
) = SharedAssetBlockNumberUpdater(chainRegistry, chainIdHolder, storageCache)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTotalInsuranceUpdater(
|
||||
sharedState: GovernanceSharedState,
|
||||
chainRegistry: ChainRegistry,
|
||||
storageCache: StorageCache,
|
||||
) = TotalIssuanceUpdater(
|
||||
sharedState,
|
||||
storageCache,
|
||||
chainRegistry
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideInactiveInsuranceUpdater(
|
||||
sharedState: GovernanceSharedState,
|
||||
chainRegistry: ChainRegistry,
|
||||
storageCache: StorageCache,
|
||||
) = InactiveIssuanceUpdater(
|
||||
sharedState,
|
||||
storageCache,
|
||||
chainRegistry
|
||||
)
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.deeplink
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.common.utils.sequrity.AutomaticInteractionGate
|
||||
import io.novafoundation.nova.feature_deep_linking.presentation.configuring.LinkBuilderFactory
|
||||
import io.novafoundation.nova.feature_governance_api.data.MutableGovernanceState
|
||||
import io.novafoundation.nova.feature_governance_api.di.deeplinks.GovernanceDeepLinks
|
||||
import io.novafoundation.nova.feature_governance_api.presentation.referenda.details.deeplink.configurators.ReferendumDetailsDeepLinkConfigurator
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.GovernanceRouter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.details.deeplink.ReferendumDeepLinkHandler
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.details.deeplink.RealReferendumDetailsDeepLinkConfigurator
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
|
||||
@Module
|
||||
class DeepLinkModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDeepLinkConfigurator(
|
||||
linkBuilderFactory: LinkBuilderFactory
|
||||
): ReferendumDetailsDeepLinkConfigurator {
|
||||
return RealReferendumDetailsDeepLinkConfigurator(linkBuilderFactory)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendumDeepLinkHandler(
|
||||
router: GovernanceRouter,
|
||||
chainRegistry: ChainRegistry,
|
||||
mutableGovernanceState: MutableGovernanceState,
|
||||
automaticInteractionGate: AutomaticInteractionGate
|
||||
): ReferendumDeepLinkHandler {
|
||||
return ReferendumDeepLinkHandler(
|
||||
router,
|
||||
chainRegistry,
|
||||
mutableGovernanceState,
|
||||
automaticInteractionGate
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDeepLinks(referendum: ReferendumDeepLinkHandler): GovernanceDeepLinks {
|
||||
return GovernanceDeepLinks(listOf(referendum))
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.screens
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.address.AddressIconGenerator
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.data.repository.BannerVisibilityRepository
|
||||
import io.novafoundation.nova.common.data.storage.Preferences
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.common.validation.ValidationSystem
|
||||
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
|
||||
import io.novafoundation.nova.feature_account_api.data.repository.OnChainIdentityRepository
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_api.domain.delegation.delegate.delegators.DelegateDelegatorsInteractor
|
||||
import io.novafoundation.nova.feature_governance_api.domain.delegation.delegate.details.model.DelegateDetailsInteractor
|
||||
import io.novafoundation.nova.feature_governance_api.domain.delegation.delegate.label.DelegateLabelUseCase
|
||||
import io.novafoundation.nova.feature_governance_api.domain.delegation.delegate.list.DelegateListInteractor
|
||||
import io.novafoundation.nova.feature_governance_api.domain.delegation.delegation.common.chooseTrack.ChooseTrackInteractor
|
||||
import io.novafoundation.nova.feature_governance_api.domain.delegation.delegation.create.chooseAmount.NewDelegationChooseAmountInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.RealRemoveVotesSuggestionRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.RemoveVotesSuggestionRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.common.RecentVotesTimePointProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.common.repository.DelegateCommonRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.common.repository.RealDelegateCommonRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.delegators.RealDelegateDelegatorsInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.details.RealDelegateDetailsInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.label.RealDelegateLabelUseCase
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.list.RealDelegateListInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegation.create.chooseAmount.RealNewDelegationChooseAmountInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegation.create.chooseAmount.validation.ChooseDelegationAmountValidationSystem
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegation.create.chooseAmount.validation.chooseDelegationAmount
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegation.create.chooseTrack.RealChooseTrackInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.track.category.TrackCategorizer
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.common.voters.VotersFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.common.DelegateMappers
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.common.RealDelegateMappers
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.delegation.delegate.detail.DelegatesSharedComputation
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.track.TrackFormatter
|
||||
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.repository.ChainStateRepository
|
||||
|
||||
@Module
|
||||
class DelegateModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideRecentVotesTimePointProvider(
|
||||
chainStateRepository: ChainStateRepository
|
||||
): RecentVotesTimePointProvider {
|
||||
return RecentVotesTimePointProvider(chainStateRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDelegateCommonRepository(
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
accountRepository: AccountRepository,
|
||||
recentVotesTimePointProvider: RecentVotesTimePointProvider
|
||||
): DelegateCommonRepository = RealDelegateCommonRepository(
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
accountRepository = accountRepository,
|
||||
recentVotesTimePointProvider = recentVotesTimePointProvider
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDelegateListInteractor(
|
||||
bannerVisibilityRepository: BannerVisibilityRepository,
|
||||
delegatesSharedComputation: DelegatesSharedComputation
|
||||
): DelegateListInteractor = RealDelegateListInteractor(
|
||||
bannerVisibilityRepository = bannerVisibilityRepository,
|
||||
delegatesSharedComputation = delegatesSharedComputation
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDelegateDetailsInteractor(
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
chainStateRepository: ChainStateRepository,
|
||||
identityRepository: OnChainIdentityRepository,
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
accountRepository: AccountRepository,
|
||||
recentVotesTimePointProvider: RecentVotesTimePointProvider
|
||||
): DelegateDetailsInteractor = RealDelegateDetailsInteractor(
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
chainStateRepository = chainStateRepository,
|
||||
identityRepository = identityRepository,
|
||||
governanceSharedState = governanceSharedState,
|
||||
accountRepository = accountRepository,
|
||||
recentVotesTimePointProvider = recentVotesTimePointProvider
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideNewDelegationChooseTrackInteractor(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
chainStateRepository: ChainStateRepository,
|
||||
accountRepository: AccountRepository,
|
||||
trackCategorizer: TrackCategorizer,
|
||||
removeVotesSuggestionRepository: RemoveVotesSuggestionRepository,
|
||||
chainRegistry: ChainRegistry
|
||||
): ChooseTrackInteractor = RealChooseTrackInteractor(
|
||||
governanceSharedState = governanceSharedState,
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
chainStateRepository = chainStateRepository,
|
||||
accountRepository = accountRepository,
|
||||
trackCategorizer = trackCategorizer,
|
||||
removeVotesSuggestionRepository = removeVotesSuggestionRepository,
|
||||
chainRegistry = chainRegistry
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDelegateDelegatorsInteractor(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
identityRepository: OnChainIdentityRepository,
|
||||
): DelegateDelegatorsInteractor = RealDelegateDelegatorsInteractor(
|
||||
governanceSharedState = governanceSharedState,
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
identityRepository = identityRepository
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDelegateMappers(
|
||||
resourceManager: ResourceManager,
|
||||
addressIconGenerator: AddressIconGenerator,
|
||||
trackFormatter: TrackFormatter,
|
||||
votersFormatter: VotersFormatter
|
||||
): DelegateMappers = RealDelegateMappers(resourceManager, addressIconGenerator, trackFormatter, votersFormatter)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideNewDelegationChooseAmountInteractor(
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
chainStateRepository: ChainStateRepository,
|
||||
selectedChainState: GovernanceSharedState,
|
||||
extrinsicService: ExtrinsicService,
|
||||
locksRepository: BalanceLocksRepository,
|
||||
computationalCache: ComputationalCache,
|
||||
accountRepository: AccountRepository,
|
||||
): NewDelegationChooseAmountInteractor {
|
||||
return RealNewDelegationChooseAmountInteractor(
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
chainStateRepository = chainStateRepository,
|
||||
selectedChainState = selectedChainState,
|
||||
extrinsicService = extrinsicService,
|
||||
locksRepository = locksRepository,
|
||||
computationalCache = computationalCache,
|
||||
accountRepository = accountRepository
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideNewDelegationChooseAmountValidationSystem(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
accountRepository: AccountRepository
|
||||
): ChooseDelegationAmountValidationSystem {
|
||||
return ValidationSystem.chooseDelegationAmount(governanceSharedState, accountRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDelegateLabelUseCase(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
identityRepository: OnChainIdentityRepository,
|
||||
): DelegateLabelUseCase = RealDelegateLabelUseCase(governanceSharedState, governanceSourceRegistry, identityRepository)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideRemoveVotesSuggestionRepository(preferences: Preferences): RemoveVotesSuggestionRepository = RealRemoveVotesSuggestionRepository(preferences)
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.screens
|
||||
|
||||
import com.google.gson.Gson
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.multibindings.IntoSet
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.feature_account_api.data.repository.OnChainIdentityRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.repository.TreasuryRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.details.ReferendumDetailsInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.data.preimage.PreImageSizer
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.common.ReferendaConstructor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.OffChainReferendumVotingSharedComputation
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.RealReferendumDetailsInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.RealReferendumPreImageParser
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.ReferendumCallAdapter
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.ReferendumPreImageParser
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.batch.BatchAdapter
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.treasury.TreasuryApproveProposalAdapter
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.treasury.TreasurySpendAdapter
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.treasury.TreasurySpendLocalAdapter
|
||||
import io.novafoundation.nova.feature_xcm_api.converter.MultiLocationConverterFactory
|
||||
import io.novafoundation.nova.feature_xcm_api.converter.chain.ChainMultiLocationConverterFactory
|
||||
import io.novafoundation.nova.runtime.di.ExtrinsicSerialization
|
||||
import io.novafoundation.nova.runtime.repository.ChainStateRepository
|
||||
|
||||
@Module
|
||||
class ReferendumDetailsModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
@IntoSet
|
||||
fun provideTreasuryApproveParser(
|
||||
treasuryRepository: TreasuryRepository
|
||||
): ReferendumCallAdapter = TreasuryApproveProposalAdapter(treasuryRepository)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
@IntoSet
|
||||
fun provideTreasurySpendParser(
|
||||
chainLocationConverter: ChainMultiLocationConverterFactory,
|
||||
assetLocationConverter: MultiLocationConverterFactory
|
||||
): ReferendumCallAdapter = TreasurySpendAdapter(chainLocationConverter, assetLocationConverter)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
@IntoSet
|
||||
fun provideTreasurySpendLocalParser(): ReferendumCallAdapter = TreasurySpendLocalAdapter()
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
@IntoSet
|
||||
fun provideBatchAdapter(): ReferendumCallAdapter = BatchAdapter()
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun providePreImageParser(
|
||||
callAdapters: Set<@JvmSuppressWildcards ReferendumCallAdapter>
|
||||
): ReferendumPreImageParser {
|
||||
return RealReferendumPreImageParser(callAdapters)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendumDetailsInteractor(
|
||||
preImageParser: ReferendumPreImageParser,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
chainStateRepository: ChainStateRepository,
|
||||
referendaConstructor: ReferendaConstructor,
|
||||
preImageSizer: PreImageSizer,
|
||||
@ExtrinsicSerialization callFormatter: Gson,
|
||||
identityRepository: OnChainIdentityRepository,
|
||||
offChainReferendumVotingSharedComputation: OffChainReferendumVotingSharedComputation
|
||||
): ReferendumDetailsInteractor = RealReferendumDetailsInteractor(
|
||||
preImageParser = preImageParser,
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
chainStateRepository = chainStateRepository,
|
||||
referendaConstructor = referendaConstructor,
|
||||
preImageSizer = preImageSizer,
|
||||
callFormatter = callFormatter,
|
||||
identityRepository = identityRepository,
|
||||
offChainReferendumVotingSharedComputation = offChainReferendumVotingSharedComputation
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideOffChainReferendumVotingSharedComputation(
|
||||
computationalCache: ComputationalCache,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
) = OffChainReferendumVotingSharedComputation(computationalCache, governanceSourceRegistry)
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.screens
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.feature_account_api.data.repository.OnChainIdentityRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.list.ReferendaListInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.filters.PreferencesReferendaFiltersRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.filters.ReferendaFiltersRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.delegation.delegate.common.RecentVotesTimePointProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.filters.RealReferendaFiltersInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.filters.ReferendaFiltersInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.common.ReferendaConstructor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.RealReferendaListInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.ReferendaSharedComputation
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.filtering.RealReferendaFilteringProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.filtering.ReferendaFilteringProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.repository.RealReferendaCommonRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.repository.ReferendaCommonRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.sorting.RealReferendaSortingProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.sorting.ReferendaSortingProvider
|
||||
import io.novafoundation.nova.runtime.repository.ChainStateRepository
|
||||
|
||||
@Module
|
||||
class ReferendumListModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaFiltersRepository(): ReferendaFiltersRepository {
|
||||
return PreferencesReferendaFiltersRepository()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaFiltersInteractor(
|
||||
referendaFiltersRepository: ReferendaFiltersRepository
|
||||
): ReferendaFiltersInteractor {
|
||||
return RealReferendaFiltersInteractor(referendaFiltersRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaSortingProvider(): ReferendaSortingProvider {
|
||||
return RealReferendaSortingProvider()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaFilteringProvider(): ReferendaFilteringProvider {
|
||||
return RealReferendaFilteringProvider()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaCommonRepository(
|
||||
chainStateRepository: ChainStateRepository,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
referendaConstructor: ReferendaConstructor,
|
||||
referendaSortingProvider: ReferendaSortingProvider,
|
||||
identityRepository: OnChainIdentityRepository,
|
||||
recentVotesTimePointProvider: RecentVotesTimePointProvider
|
||||
): ReferendaCommonRepository {
|
||||
return RealReferendaCommonRepository(
|
||||
chainStateRepository = chainStateRepository,
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
referendaConstructor = referendaConstructor,
|
||||
referendaSortingProvider = referendaSortingProvider,
|
||||
identityRepository = identityRepository,
|
||||
recentVotesTimePointProvider = recentVotesTimePointProvider
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaSharedComputation(
|
||||
computationalCache: ComputationalCache,
|
||||
referendaCommonRepository: ReferendaCommonRepository
|
||||
): ReferendaSharedComputation {
|
||||
return ReferendaSharedComputation(computationalCache, referendaCommonRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaListInteractor(
|
||||
referendaCommonRepository: ReferendaCommonRepository,
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
referendaSharedComputation: ReferendaSharedComputation,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
referendaSortingProvider: ReferendaSortingProvider,
|
||||
referendaFilteringProvider: ReferendaFilteringProvider
|
||||
): ReferendaListInteractor = RealReferendaListInteractor(
|
||||
referendaCommonRepository = referendaCommonRepository,
|
||||
governanceSharedState = governanceSharedState,
|
||||
referendaSharedComputation = referendaSharedComputation,
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
referendaSortingProvider = referendaSortingProvider,
|
||||
referendaFilteringProvider = referendaFilteringProvider
|
||||
)
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.screens
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.unlock.GovernanceUnlockInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.unlock.RealGovernanceUnlockInteractor
|
||||
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository
|
||||
import io.novafoundation.nova.runtime.repository.ChainStateRepository
|
||||
|
||||
@Module
|
||||
class ReferendumUnlockModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideGovernanceLocksOverviewInteractor(
|
||||
selectedAssetState: GovernanceSharedState,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
chainStateRepository: ChainStateRepository,
|
||||
computationalCache: ComputationalCache,
|
||||
accountRepository: AccountRepository,
|
||||
balanceLocksRepository: BalanceLocksRepository,
|
||||
extrinsicService: ExtrinsicService,
|
||||
): GovernanceUnlockInteractor {
|
||||
return RealGovernanceUnlockInteractor(
|
||||
selectedAssetState = selectedAssetState,
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
chainStateRepository = chainStateRepository,
|
||||
computationalCache = computationalCache,
|
||||
accountRepository = accountRepository,
|
||||
balanceLocksRepository = balanceLocksRepository,
|
||||
extrinsicService = extrinsicService
|
||||
)
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.screens
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.common.mixin.hints.ResourcesHintsMixinFactory
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.common.validation.ValidationSystem
|
||||
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.vote.VoteReferendumInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.vote.RealVoteReferendumInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.vote.validations.referendum.VoteReferendumValidationSystem
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.vote.validations.referendum.voteReferendumValidationSystem
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.common.LocksChangeFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.common.RealLocksChangeFormatter
|
||||
import io.novafoundation.nova.feature_governance_impl.presentation.referenda.vote.hints.ReferendumVoteHintsMixinFactory
|
||||
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.AmountFormatter
|
||||
import io.novafoundation.nova.runtime.repository.ChainStateRepository
|
||||
|
||||
@Module
|
||||
class ReferendumVoteModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendumVoteInteractor(
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
chainStateRepository: ChainStateRepository,
|
||||
selectedChainState: GovernanceSharedState,
|
||||
accountRepository: AccountRepository,
|
||||
locksRepository: BalanceLocksRepository,
|
||||
extrinsicService: ExtrinsicService,
|
||||
computationalCache: ComputationalCache
|
||||
): VoteReferendumInteractor {
|
||||
return RealVoteReferendumInteractor(
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
chainStateRepository = chainStateRepository,
|
||||
selectedChainState = selectedChainState,
|
||||
accountRepository = accountRepository,
|
||||
extrinsicService = extrinsicService,
|
||||
locksRepository = locksRepository,
|
||||
computationalCache = computationalCache
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideHintsMixinFactory(
|
||||
resHintsMixinFactory: ResourcesHintsMixinFactory
|
||||
): ReferendumVoteHintsMixinFactory = ReferendumVoteHintsMixinFactory(resHintsMixinFactory)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideLocksChangeFormatter(
|
||||
resourceManager: ResourceManager,
|
||||
amountFormatter: AmountFormatter
|
||||
): LocksChangeFormatter = RealLocksChangeFormatter(resourceManager, amountFormatter)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideValidationSystem(
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
): VoteReferendumValidationSystem = ValidationSystem.voteReferendumValidationSystem(governanceSourceRegistry, governanceSharedState)
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.screens
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.IdentityProvider
|
||||
import io.novafoundation.nova.feature_account_api.domain.account.identity.OnChainIdentity
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_api.domain.referendum.voters.ReferendumVotersInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.voters.RealReferendumVotersInteractor
|
||||
|
||||
@Module
|
||||
class ReferendumVotersModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaVotersInteractor(
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
@OnChainIdentity identityProvider: IdentityProvider,
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
): ReferendumVotersInteractor = RealReferendumVotersInteractor(
|
||||
governanceSourceRegistry = governanceSourceRegistry,
|
||||
identityProvider = identityProvider,
|
||||
governanceSharedState = governanceSharedState,
|
||||
)
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.screens
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.data.memory.ComputationalCache
|
||||
import io.novafoundation.nova.common.data.network.NetworkApiCreator
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.core_db.dao.TinderGovDao
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSourceRegistry
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.summary.ReferendaSummaryInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.tindergov.TinderGovBasketInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.tindergov.TinderGovInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.data.GovernanceSharedState
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.RealReferendumSummaryDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.ReferendumSummaryApi
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.summary.v2.ReferendumSummaryDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.tindergov.RealTinderGovBasketRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.tindergov.RealTinderGovVotingPowerRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.tindergov.TinderGovBasketRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.tindergov.TinderGovVotingPowerRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.RealReferendumDetailsRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.ReferendumDetailsRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.details.call.ReferendumPreImageParser
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.ReferendaSharedComputation
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.list.filtering.ReferendaFilteringProvider
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.tindergov.RealTinderGovBasketInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.referendum.tindergov.RealTinderGovInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.summary.RealReferendaSummaryInteractor
|
||||
import io.novafoundation.nova.feature_governance_impl.domain.summary.ReferendaSummarySharedComputation
|
||||
import io.novafoundation.nova.feature_wallet_api.domain.AssetUseCase
|
||||
|
||||
@Module
|
||||
class TinderGovModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendumSummaryApi(apiCreator: NetworkApiCreator): ReferendumSummaryApi {
|
||||
return apiCreator.create(ReferendumSummaryApi::class.java)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideSummaryDataSource(
|
||||
referendumSummaryApi: ReferendumSummaryApi
|
||||
): ReferendumSummaryDataSource {
|
||||
return RealReferendumSummaryDataSource(referendumSummaryApi)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTinderGovBasketRepository(dao: TinderGovDao): TinderGovBasketRepository {
|
||||
return RealTinderGovBasketRepository(dao)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTinderGovVotingPowerRepository(
|
||||
tinderGovDao: TinderGovDao
|
||||
): TinderGovVotingPowerRepository {
|
||||
return RealTinderGovVotingPowerRepository(tinderGovDao)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendumDetailsRepository(
|
||||
dataSource: ReferendumSummaryDataSource
|
||||
): ReferendumDetailsRepository {
|
||||
return RealReferendumDetailsRepository(dataSource)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTinderGovInteractor(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
referendaSharedComputation: ReferendaSharedComputation,
|
||||
accountRepository: AccountRepository,
|
||||
preImageParser: ReferendumPreImageParser,
|
||||
tinderGovVotingPowerRepository: TinderGovVotingPowerRepository,
|
||||
referendaFilteringProvider: ReferendaFilteringProvider,
|
||||
assetUseCase: AssetUseCase,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
): TinderGovInteractor = RealTinderGovInteractor(
|
||||
governanceSharedState,
|
||||
referendaSharedComputation,
|
||||
accountRepository,
|
||||
preImageParser,
|
||||
tinderGovVotingPowerRepository,
|
||||
referendaFilteringProvider,
|
||||
governanceSourceRegistry,
|
||||
assetUseCase,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaSummarySharedComputation(
|
||||
computationalCache: ComputationalCache,
|
||||
referendumDetailsRepository: ReferendumDetailsRepository,
|
||||
accountRepository: AccountRepository
|
||||
) = ReferendaSummarySharedComputation(
|
||||
computationalCache,
|
||||
referendumDetailsRepository,
|
||||
accountRepository
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideReferendaSummaryInteractor(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
referendaSummarySharedComputation: ReferendaSummarySharedComputation
|
||||
): ReferendaSummaryInteractor = RealReferendaSummaryInteractor(
|
||||
governanceSharedState,
|
||||
referendaSummarySharedComputation
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTinderGovBasketInteractor(
|
||||
governanceSharedState: GovernanceSharedState,
|
||||
accountRepository: AccountRepository,
|
||||
tinderGovBasketRepository: TinderGovBasketRepository,
|
||||
tinderGovVotingPowerRepository: TinderGovVotingPowerRepository,
|
||||
assetUseCase: AssetUseCase,
|
||||
tinderGovInteractor: TinderGovInteractor,
|
||||
governanceSourceRegistry: GovernanceSourceRegistry,
|
||||
): TinderGovBasketInteractor = RealTinderGovBasketInteractor(
|
||||
governanceSharedState = governanceSharedState,
|
||||
accountRepository = accountRepository,
|
||||
tinderGovBasketRepository = tinderGovBasketRepository,
|
||||
tinderGovVotingPowerRepository = tinderGovVotingPowerRepository,
|
||||
assetUseCase = assetUseCase,
|
||||
tinderGovInteractor = tinderGovInteractor,
|
||||
governanceSourceRegistry = governanceSourceRegistry
|
||||
)
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.v1
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.feature_governance_api.data.source.GovernanceSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.PolkassemblyV1ReferendaDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.subsquare.v1.SubSquareV1ReferendaDataSource
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.MultiSourceOffChainReferendaInfoRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.UnsupportedDelegationsRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.v1.GovV1ConvictionVotingRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.v1.GovV1DAppsRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.v1.GovV1OnChainReferendaRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.v1.GovV1PreImageRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.repository.v2.Gov2PreImageRepository
|
||||
import io.novafoundation.nova.feature_governance_impl.data.source.StaticGovernanceSource
|
||||
import io.novafoundation.nova.feature_wallet_api.data.repository.BalanceLocksRepository
|
||||
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import javax.inject.Named
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Qualifier
|
||||
annotation class GovernanceV1
|
||||
|
||||
@Module(includes = [PolkassemblyV1Module::class, SubSquareV1Module::class])
|
||||
class GovernanceV1Module {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideOnChainReferendaRepository(
|
||||
@Named(REMOTE_STORAGE_SOURCE) storageSource: StorageDataSource,
|
||||
chainRegistry: ChainRegistry,
|
||||
totalIssuanceRepository: TotalIssuanceRepository,
|
||||
) = GovV1OnChainReferendaRepository(storageSource, chainRegistry, totalIssuanceRepository)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideConvictionVotingRepository(
|
||||
@Named(REMOTE_STORAGE_SOURCE) storageSource: StorageDataSource,
|
||||
chainRegistry: ChainRegistry,
|
||||
balanceLocksRepository: BalanceLocksRepository
|
||||
) = GovV1ConvictionVotingRepository(storageSource, chainRegistry, balanceLocksRepository)
|
||||
|
||||
@Provides
|
||||
@GovernanceV1
|
||||
@FeatureScope
|
||||
fun provideOffChainInfoRepository(
|
||||
polkassembly: PolkassemblyV1ReferendaDataSource,
|
||||
subSquare: SubSquareV1ReferendaDataSource,
|
||||
) = MultiSourceOffChainReferendaInfoRepository(
|
||||
subSquareReferendaDataSource = subSquare,
|
||||
polkassemblyReferendaDataSource = polkassembly
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun providePreImageRepository(
|
||||
@Named(REMOTE_STORAGE_SOURCE) storageSource: StorageDataSource,
|
||||
v2Delegate: Gov2PreImageRepository,
|
||||
) = GovV1PreImageRepository(storageSource, v2Delegate)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDappsRepository(governanceDAppsDao: GovernanceDAppsDao): GovV1DAppsRepository {
|
||||
return GovV1DAppsRepository(governanceDAppsDao)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
@GovernanceV1
|
||||
fun provideGovernanceSource(
|
||||
referendaRepository: GovV1OnChainReferendaRepository,
|
||||
convictionVotingRepository: GovV1ConvictionVotingRepository,
|
||||
@GovernanceV1 offChainInfoRepository: MultiSourceOffChainReferendaInfoRepository,
|
||||
preImageRepository: GovV1PreImageRepository,
|
||||
governanceV1DAppsRepository: GovV1DAppsRepository
|
||||
): GovernanceSource = StaticGovernanceSource(
|
||||
referenda = referendaRepository,
|
||||
convictionVoting = convictionVotingRepository,
|
||||
offChainInfo = offChainInfoRepository,
|
||||
preImageRepository = preImageRepository,
|
||||
dappsRepository = governanceV1DAppsRepository,
|
||||
delegationsRepository = UnsupportedDelegationsRepository()
|
||||
)
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package io.novafoundation.nova.feature_governance_impl.di.modules.v1
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.data.network.NetworkApiCreator
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.PolkassemblyV1Api
|
||||
import io.novafoundation.nova.feature_governance_impl.data.offchain.referendum.polkassembly.v1.PolkassemblyV1ReferendaDataSource
|
||||
|
||||
@Module
|
||||
class PolkassemblyV1Module {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideApi(apiCreator: NetworkApiCreator): PolkassemblyV1Api = apiCreator.create(PolkassemblyV1Api::class.java)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideDataSource(api: PolkassemblyV1Api): PolkassemblyV1ReferendaDataSource = PolkassemblyV1ReferendaDataSource(api)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user