Prepare for Play Store release: simplify dashboard, clean debug logs

- Simplify dashboard card: remove referral/staking/perwerde fields (not yet on-chain), keep roles + trust score + action button
- Remove all debug Log.d/e/w calls added during development (PEZ_STAKE, RuntimeFactory, ExtrinsicBuilder, etc.)
- Change Play Store track from beta to production
- Add release notes (whatsnew-en-US)
This commit is contained in:
2026-02-17 06:13:59 +03:00
parent 93e94cbf15
commit 9c7bb7c6e9
35 changed files with 53 additions and 433 deletions
+1 -1
View File
@@ -168,7 +168,7 @@ void createBindReleaseFileTask(String destination) {
play {
serviceAccountCredentials = file(System.env.CI_PLAY_KEY ?: "../key/fake.json")
track = "beta"
track = "production"
releaseStatus = "completed"
}
@@ -1,6 +1,5 @@
package io.novafoundation.nova.common.utils
import android.util.Log
import io.novasama.substrate_sdk_android.runtime.AccountId
import io.novasama.substrate_sdk_android.runtime.definitions.registry.TypeRegistry
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.DictEnum
@@ -8,8 +7,6 @@ import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.MULT
import io.novasama.substrate_sdk_android.runtime.definitions.types.primitives.FixedByteArray
import io.novasama.substrate_sdk_android.runtime.definitions.types.skipAliases
private const val TAG = "PezkuwiAddressConstructor"
/**
* Custom address constructor that handles Pezkuwi chains which use different type names.
* Pezkuwi uses "pezsp_runtime::multiaddress::MultiAddress" instead of standard "Address".
@@ -28,59 +25,39 @@ object PezkuwiAddressConstructor {
* Checks the actual type structure to determine the correct encoding format.
*/
fun constructInstance(typeRegistry: TypeRegistry, accountId: AccountId): Any {
// Try to find the address type
var foundTypeName: String? = null
val addressType = ADDRESS_TYPE_NAMES.firstNotNullOfOrNull { name ->
typeRegistry[name]?.also { foundTypeName = name }
}
Log.d(TAG, "Found address type: $foundTypeName, type class: ${addressType?.javaClass?.simpleName}")
// If no address type found, return the raw accountId (for chains with simple AccountId)
if (addressType == null) {
Log.d(TAG, "No address type found, returning raw accountId")
return accountId
}
val resolvedType = addressType.skipAliases()
Log.d(TAG, "Resolved type after skipAliases: ${resolvedType?.javaClass?.simpleName}, name: ${resolvedType?.name}")
// Check the actual type structure
return when (resolvedType) {
is DictEnum -> {
// Use the actual variant name from the type
// Standard chains use "Id", but Pezkuwi uses numeric variants like "0"
val variantNames = resolvedType.elements.values.map { it.name }
Log.d(TAG, "Type is DictEnum with variants: $variantNames")
// Use "Id" if available, otherwise use the first variant (index 0)
val idVariantName = if (variantNames.contains(MULTI_ADDRESS_ID)) {
MULTI_ADDRESS_ID
} else {
resolvedType.elements[0]?.name ?: MULTI_ADDRESS_ID
}
Log.d(TAG, "Using variant name: $idVariantName")
DictEnum.Entry(idVariantName, accountId)
}
is FixedByteArray -> {
Log.d(TAG, "Type is FixedByteArray with length: ${resolvedType.length}, returning raw accountId")
// GenericAccountId or similar - return raw
accountId
}
null -> {
Log.d(TAG, "Resolved type is null for type: $foundTypeName")
// If this is a MultiAddress type that couldn't resolve, use variant "0"
if (foundTypeName?.contains("MultiAddress") == true || foundTypeName?.contains("multiaddress") == true) {
Log.d(TAG, "Type appears to be MultiAddress, using variant 0")
DictEnum.Entry("0", accountId)
} else {
Log.d(TAG, "Returning raw accountId")
accountId
}
}
else -> {
Log.d(TAG, "Unknown type: ${resolvedType.javaClass.simpleName}, returning raw accountId")
// Unknown type, try raw accountId instead of DictEnum
accountId
}
}
@@ -2047,8 +2047,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Puntuación de confianza</string>
<string name="pezkuwi_dashboard_referral">Referido</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Solicitar y Acciones</string>
</resources>
@@ -2047,8 +2047,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Score de confiance</string>
<string name="pezkuwi_dashboard_referral">Parrainage</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Demande et Actions</string>
</resources>
@@ -2047,8 +2047,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Bizalmi pontszám</string>
<string name="pezkuwi_dashboard_referral">Ajánlás</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Jelentkezés és Műveletek</string>
</resources>
@@ -2033,8 +2033,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Skor Kepercayaan</string>
<string name="pezkuwi_dashboard_referral">Referral</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Ajukan &amp; Tindakan</string>
</resources>
@@ -2047,8 +2047,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Punteggio di fiducia</string>
<string name="pezkuwi_dashboard_referral">Referral</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Richiesta e Azioni</string>
</resources>
@@ -2033,8 +2033,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">信頼スコア</string>
<string name="pezkuwi_dashboard_referral">紹介</string>
<string name="pezkuwi_dashboard_staking">ステーキング</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">申請とアクション</string>
</resources>
@@ -2033,8 +2033,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">신뢰 점수</string>
<string name="pezkuwi_dashboard_referral">추천</string>
<string name="pezkuwi_dashboard_staking">스테이킹</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">신청 및 작업</string>
</resources>
@@ -2760,8 +2760,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Pûana Pêbaweriyê</string>
<string name="pezkuwi_dashboard_referral">Referral</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Serlêdan û Karên</string>
</resources>
@@ -2075,8 +2075,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Wynik zaufania</string>
<string name="pezkuwi_dashboard_referral">Polecenie</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Wniosek i Akcje</string>
</resources>
@@ -2047,8 +2047,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Pontuação de confiança</string>
<string name="pezkuwi_dashboard_referral">Indicação</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Candidatura e Ações</string>
</resources>
@@ -2075,8 +2075,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Рейтинг доверия</string>
<string name="pezkuwi_dashboard_referral">Реферал</string>
<string name="pezkuwi_dashboard_staking">Стейкинг</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Заявка и Действия</string>
</resources>
@@ -2,8 +2,5 @@
<resources>
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Güven Puanı</string>
<string name="pezkuwi_dashboard_referral">Referans</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Başvuru ve İşlemler</string>
</resources>
@@ -2033,8 +2033,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Điểm tin cậy</string>
<string name="pezkuwi_dashboard_referral">Giới thiệu</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Đăng ký &amp; Hành động</string>
</resources>
@@ -2033,8 +2033,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">信任评分</string>
<string name="pezkuwi_dashboard_referral">推荐</string>
<string name="pezkuwi_dashboard_staking">质押</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">申请与操作</string>
</resources>
-3
View File
@@ -2762,8 +2762,5 @@
<string name="pezkuwi_dashboard_title">Pezkuwi</string>
<string name="pezkuwi_dashboard_trust_score">Trust Score</string>
<string name="pezkuwi_dashboard_referral">Referral</string>
<string name="pezkuwi_dashboard_staking">Staking</string>
<string name="pezkuwi_dashboard_perwerde">Perwerde</string>
<string name="pezkuwi_dashboard_basvuru">Apply &amp; Actions</string>
</resources>
+7
View File
@@ -0,0 +1,7 @@
Pezkuwi Wallet - Your gateway to the Pezkuwi blockchain ecosystem.
- Send and receive HEZ tokens
- Stake HEZ via nomination pools on Asset Hub
- View your Pezkuwi dashboard with roles and trust score
- Multi-chain support for Polkadot ecosystem
- Secure account management with biometric authentication
@@ -350,39 +350,7 @@ class RealExtrinsicService(
}
// Build extrinsic
val extrinsic = try {
Log.d("RealExtrinsicService", "Building extrinsic for chain ${chain.name} (${chain.id})")
extrinsicBuilder.buildExtrinsic()
} catch (e: Exception) {
Log.e("RealExtrinsicService", "Failed to build extrinsic for chain ${chain.name}", e)
Log.e("RealExtrinsicService", "SigningMode: $signingMode, Chain: ${chain.id}")
Log.e("RealExtrinsicService", "Exception class: ${e::class.java.name}")
Log.e("RealExtrinsicService", "Message: ${e.message}")
Log.e("RealExtrinsicService", "Cause: ${e.cause?.message}")
Log.e("RealExtrinsicService", "Full stack trace:", e)
// Get runtime diagnostics
try {
val runtime = chainRegistry.getRuntime(chain.id)
val typeRegistry = runtime.typeRegistry
val hasExtrinsicSignature = typeRegistry["ExtrinsicSignature"] != null
val hasMultiSignature = typeRegistry["MultiSignature"] != null
val hasMultiAddress = typeRegistry["MultiAddress"] != null
val hasAddress = typeRegistry["Address"] != null
Log.e(
"RealExtrinsicService",
"Types: ExtrinsicSig=$hasExtrinsicSignature, MultiSig=$hasMultiSignature, " +
"MultiAddress=$hasMultiAddress, Address=$hasAddress"
)
// Check extrinsic extensions
val signedExtensions = runtime.metadata.extrinsic.signedExtensions.map { it.id }
Log.e("RealExtrinsicService", "Signed extensions: $signedExtensions")
} catch (diagEx: Exception) {
Log.e("RealExtrinsicService", "Failed to get diagnostics: ${diagEx.message}")
}
throw e
}
val extrinsic = extrinsicBuilder.buildExtrinsic()
val signingHierarchy = signer.getSigningHierarchy()
@@ -4,8 +4,5 @@ import java.math.BigInteger
data class PezkuwiDashboardData(
val roles: List<String>,
val trustScore: BigInteger,
val totalReferrals: Int,
val stakedAmount: BigInteger,
val perwerdePoints: Int
val trustScore: BigInteger
)
@@ -1,15 +1,12 @@
package io.novafoundation.nova.feature_assets.data.repository
import io.novafoundation.nova.common.data.network.runtime.binding.bindInt
import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
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.feature_assets.data.model.PezkuwiDashboardData
import io.novafoundation.nova.runtime.ext.ChainGeneses
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
import io.novasama.substrate_sdk_android.runtime.AccountId
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.DictEnum
import io.novasama.substrate_sdk_android.runtime.metadata.moduleOrNull
import io.novasama.substrate_sdk_android.runtime.metadata.storage
import java.math.BigInteger
@@ -23,16 +20,10 @@ class PezkuwiDashboardRepository(
val roles = queryRoles(chainId, accountId)
val trustScore = queryTrustScore(chainId, accountId)
val totalReferrals = queryReferrals(chainId, accountId)
val stakedAmount = queryStakedAmount(chainId, accountId)
val perwerdePoints = queryPerwerdePoints(chainId, accountId)
return PezkuwiDashboardData(
roles = roles,
trustScore = trustScore,
totalReferrals = totalReferrals,
stakedAmount = stakedAmount,
perwerdePoints = perwerdePoints
trustScore = trustScore
)
}
@@ -56,64 +47,4 @@ class PezkuwiDashboardRepository(
})
}
}.getOrDefault(BigInteger.ZERO)
private suspend fun queryReferrals(chainId: String, accountId: AccountId): Int = runCatching {
remoteStorageDataSource.query(chainId) {
val referralModule = runtime.metadata.moduleOrNull("Referral") ?: return@query 0
referralModule.storage("ReferrerStatsStorage").query(accountId, binding = { decoded ->
decoded?.castToStruct()?.let { struct ->
bindInt(struct["total_referrals"])
} ?: 0
})
}
}.getOrDefault(0)
private suspend fun queryStakedAmount(chainId: String, accountId: AccountId): BigInteger = runCatching {
remoteStorageDataSource.query(chainId) {
val stakingModule = runtime.metadata.moduleOrNull("StakingScore") ?: return@query BigInteger.ZERO
val relayChainKey = DictEnum.Entry("RelayChain", null)
val assetHubKey = DictEnum.Entry("AssetHub", null)
val relayStaked = runCatching {
stakingModule.storage("CachedStakingDetails").query(accountId, relayChainKey, binding = { decoded ->
decoded?.castToStruct()?.let { struct ->
bindNumber(struct["staked_amount"])
} ?: BigInteger.ZERO
})
}.getOrDefault(BigInteger.ZERO)
val assetHubStaked = runCatching {
stakingModule.storage("CachedStakingDetails").query(accountId, assetHubKey, binding = { decoded ->
decoded?.castToStruct()?.let { struct ->
bindNumber(struct["staked_amount"])
} ?: BigInteger.ZERO
})
}.getOrDefault(BigInteger.ZERO)
relayStaked.add(assetHubStaked)
}
}.getOrDefault(BigInteger.ZERO)
private suspend fun queryPerwerdePoints(chainId: String, accountId: AccountId): Int = runCatching {
remoteStorageDataSource.query(chainId) {
val perwerdeModule = runtime.metadata.moduleOrNull("Perwerde") ?: return@query 0
val courseIds = perwerdeModule.storage("StudentCourses").query(accountId, binding = { decoded ->
decoded?.castToList()?.map { bindInt(it) } ?: emptyList()
})
if (courseIds.isEmpty()) return@query 0
courseIds.sumOf { courseId ->
runCatching {
perwerdeModule.storage("Enrollments").query(courseId, accountId, binding = { decoded ->
decoded?.castToStruct()?.let { struct ->
bindInt(struct["points_earned"])
} ?: 0
})
}.getOrDefault(0)
}
}
}.getOrDefault(0)
}
@@ -228,10 +228,7 @@ class BalanceListViewModel(
.map { data ->
PezkuwiDashboardModel(
roles = data.roles,
trustScore = data.trustScore.toString(),
referralPoints = data.totalReferrals.toString(),
stakingPoints = data.stakedAmount.toString(),
perwerdePoints = data.perwerdePoints.toString()
trustScore = data.trustScore.toString()
)
}
.getOrNull()
@@ -2,8 +2,5 @@ package io.novafoundation.nova.feature_assets.presentation.balance.list.model
data class PezkuwiDashboardModel(
val roles: List<String>,
val trustScore: String,
val referralPoints: String,
val stakingPoints: String,
val perwerdePoints: String
val trustScore: String
)
@@ -58,9 +58,6 @@ class PezkuwiDashboardHolder(
fun bind(model: PezkuwiDashboardModel) {
bindRoles(model.roles)
binder.pezkuwiDashboardTrustValue.text = model.trustScore
binder.pezkuwiDashboardReferralValue.text = model.referralPoints
binder.pezkuwiDashboardStakingValue.text = model.stakingPoints
binder.pezkuwiDashboardPerwerdeValue.text = model.perwerdePoints
}
private fun bindRoles(roles: List<String>) {
@@ -37,106 +37,23 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal">
android:orientation="vertical">
<LinearLayout
android:layout_width="0dp"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
android:text="@string/pezkuwi_dashboard_trust_score"
android:textColor="#B0BEC5"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pezkuwi_dashboard_trust_score"
android:textColor="#B0BEC5"
android:textSize="12sp" />
<TextView
android:id="@+id/pezkuwiDashboardTrustValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
<TextView
android:id="@+id/pezkuwiDashboardTrustValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pezkuwi_dashboard_referral"
android:textColor="#B0BEC5"
android:textSize="12sp" />
<TextView
android:id="@+id/pezkuwiDashboardReferralValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pezkuwi_dashboard_staking"
android:textColor="#B0BEC5"
android:textSize="12sp" />
<TextView
android:id="@+id/pezkuwiDashboardStakingValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pezkuwi_dashboard_perwerde"
android:textColor="#B0BEC5"
android:textSize="12sp" />
<TextView
android:id="@+id/pezkuwiDashboardPerwerdeValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
android:layout_marginTop="2dp"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
@@ -22,7 +22,6 @@ import io.novafoundation.nova.runtime.multiNetwork.ChainWithAsset
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
import io.novafoundation.nova.runtime.repository.TotalIssuanceRepository
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
@@ -64,12 +63,9 @@ class StakingSharedComputation(
return computationalCache.useSharedFlow(key, scope) {
flow {
Log.d("PEZ_STAKE", "activeEraFlow: fetching remote activeEra for chainId=$chainId")
val era = stakingRepository.getActiveEraIndex(chainId)
Log.d("PEZ_STAKE", "activeEraFlow: got remote activeEra=$era")
emit(era)
Log.d("PEZ_STAKE", "activeEraFlow: starting local observation for chainId=$chainId")
emitAll(stakingRepository.observeActiveEraIndex(chainId))
}
}
@@ -80,15 +76,8 @@ class StakingSharedComputation(
return computationalCache.useSharedFlow(key, scope) {
activeEraFlow(chainId, scope).map { eraIndex ->
Log.d("PEZ_STAKE", "electedExposures: fetching validators for chainId=$chainId, era=$eraIndex")
try {
val exposures = stakingRepository.getElectedValidatorsExposure(chainId, eraIndex)
Log.d("PEZ_STAKE", "electedExposures: got ${exposures.size} validators for chainId=$chainId")
exposures to eraIndex
} catch (e: Exception) {
Log.e("PEZ_STAKE", "electedExposures: FAILED for chainId=$chainId, era=$eraIndex", e)
throw e
}
val exposures = stakingRepository.getElectedValidatorsExposure(chainId, eraIndex)
exposures to eraIndex
}
}
}
@@ -98,32 +87,23 @@ class StakingSharedComputation(
return computationalCache.useSharedFlow(key, scope) {
electedExposuresWithActiveEraFlow(chainId, scope).map { (exposures, activeEraIndex) ->
Log.d("PEZ_STAKE", "activeEraInfo: calculating minStake for chainId=$chainId, era=$activeEraIndex, validators=${exposures.size}")
try {
val minBond = stakingRepository.minimumNominatorBond(chainId)
Log.d("PEZ_STAKE", "activeEraInfo: minBond=$minBond")
val bagListLocator = bagListRepository.bagListLocatorOrNull(chainId)
val totalIssuance = totalIssuanceRepository.getTotalIssuance(chainId)
val bagListScoreConverter = BagListScoreConverter.U128(totalIssuance)
val maxElectingVoters = bagListRepository.maxElectingVotes(chainId)
val bagListSize = bagListRepository.bagListSize(chainId)
Log.d("PEZ_STAKE", "activeEraInfo: bagListSize=$bagListSize, maxElectingVoters=$maxElectingVoters")
val minBond = stakingRepository.minimumNominatorBond(chainId)
val bagListLocator = bagListRepository.bagListLocatorOrNull(chainId)
val totalIssuance = totalIssuanceRepository.getTotalIssuance(chainId)
val bagListScoreConverter = BagListScoreConverter.U128(totalIssuance)
val maxElectingVoters = bagListRepository.maxElectingVotes(chainId)
val bagListSize = bagListRepository.bagListSize(chainId)
val minStake = minimumStake(
exposures = exposures.values,
minimumNominatorBond = minBond,
bagListLocator = bagListLocator,
bagListScoreConverter = bagListScoreConverter,
bagListSize = bagListSize,
maxElectingVoters = maxElectingVoters
)
Log.d("PEZ_STAKE", "activeEraInfo: minStake=$minStake")
val minStake = minimumStake(
exposures = exposures.values,
minimumNominatorBond = minBond,
bagListLocator = bagListLocator,
bagListScoreConverter = bagListScoreConverter,
bagListSize = bagListSize,
maxElectingVoters = maxElectingVoters
)
ActiveEraInfo(activeEraIndex, exposures, minStake)
} catch (e: Exception) {
Log.e("PEZ_STAKE", "activeEraInfo: FAILED for chainId=$chainId", e)
throw e
}
ActiveEraInfo(activeEraIndex, exposures, minStake)
}
}
}
@@ -29,7 +29,6 @@ import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Ba
import io.novafoundation.nova.feature_wallet_api.domain.model.Asset
import io.novafoundation.nova.feature_wallet_api.domain.validation.sufficientBalance
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
import android.util.Log
import kotlinx.coroutines.CoroutineScope
class DirectStakingPropertiesFactory(
@@ -102,10 +101,7 @@ private class DirectStakingProperties(
private val stakingChainId = stakingOption.chain.parentId ?: stakingOption.chain.id
override suspend fun minStake(): Balance {
Log.d("PEZ_STAKE", "DirectStaking.minStake() called, stakingChainId=$stakingChainId")
val result = stakingSharedComputation.minStake(stakingChainId, scope)
Log.d("PEZ_STAKE", "DirectStaking.minStake() returned: $result")
return result
return stakingSharedComputation.minStake(stakingChainId, scope)
}
private fun StartMultiStakingValidationSystemBuilder.noConflictingStaking() {
@@ -8,7 +8,6 @@ import io.novafoundation.nova.feature_staking_impl.domain.recommendations.settin
import io.novafoundation.nova.feature_staking_impl.domain.staking.start.common.selection.StartMultiStakingSelection
import io.novafoundation.nova.feature_staking_impl.domain.staking.start.setupAmount.SingleStakingRecommendation
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
@@ -21,42 +20,21 @@ class DirectStakingRecommendation(
) : SingleStakingRecommendation {
private val recommendator = scope.async {
Log.d("PEZ_STAKE", "DirectRecommendation: creating validator recommender...")
try {
val result = validatorRecommenderFactory.create(scope)
Log.d("PEZ_STAKE", "DirectRecommendation: validator recommender created")
result
} catch (e: Exception) {
Log.e("PEZ_STAKE", "DirectRecommendation: validator recommender FAILED", e)
throw e
}
validatorRecommenderFactory.create(scope)
}
private val recommendationSettingsProvider = scope.async {
Log.d("PEZ_STAKE", "DirectRecommendation: creating settings provider...")
try {
val result = recommendationSettingsProviderFactory.create(scope)
Log.d("PEZ_STAKE", "DirectRecommendation: settings provider created")
result
} catch (e: Exception) {
Log.e("PEZ_STAKE", "DirectRecommendation: settings provider FAILED", e)
throw e
}
recommendationSettingsProviderFactory.create(scope)
}
override suspend fun recommendedSelection(stake: Balance): StartMultiStakingSelection {
Log.d("PEZ_STAKE", "DirectRecommendation: awaiting settings provider...")
val provider = recommendationSettingsProvider.await()
Log.d("PEZ_STAKE", "DirectRecommendation: got settings provider")
val stakingChainId = stakingOption.chain.parentId ?: stakingOption.chain.id
val maximumValidatorsPerNominator = stakingConstantsRepository.maxValidatorsPerNominator(stakingChainId, stake)
val recommendationSettings = provider.recommendedSettings(maximumValidatorsPerNominator)
Log.d("PEZ_STAKE", "DirectRecommendation: awaiting recommender...")
val recommendator = recommendator.await()
Log.d("PEZ_STAKE", "DirectRecommendation: got recommender, getting recommendations...")
val recommendedValidators = recommendator.recommendations(recommendationSettings)
Log.d("PEZ_STAKE", "DirectRecommendation: got ${recommendedValidators.size} recommended validators")
return DirectStakingSelection(
validators = recommendedValidators,
@@ -5,7 +5,6 @@ import io.novafoundation.nova.feature_staking_impl.domain.nominationPools.pools.
import io.novafoundation.nova.feature_staking_impl.domain.staking.start.common.selection.StartMultiStakingSelection
import io.novafoundation.nova.feature_staking_impl.domain.staking.start.setupAmount.SingleStakingRecommendation
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
@@ -16,24 +15,11 @@ class NominationPoolRecommendation(
) : SingleStakingRecommendation {
private val recommendator = scope.async {
Log.d("PEZ_STAKE", "NomPoolRecommendation: creating recommender...")
try {
val result = nominationPoolRecommenderFactory.create(stakingOption, scope)
Log.d("PEZ_STAKE", "NomPoolRecommendation: recommender created successfully")
result
} catch (e: Exception) {
Log.e("PEZ_STAKE", "NomPoolRecommendation: recommender creation FAILED", e)
throw e
}
nominationPoolRecommenderFactory.create(stakingOption, scope)
}
override suspend fun recommendedSelection(stake: Balance): StartMultiStakingSelection? {
Log.d("PEZ_STAKE", "NomPoolRecommendation: awaiting recommender...")
val recommendedPool = recommendator.await().recommendedPool() ?: run {
Log.d("PEZ_STAKE", "NomPoolRecommendation: no recommended pool found")
return null
}
Log.d("PEZ_STAKE", "NomPoolRecommendation: recommended pool=${recommendedPool.id}")
val recommendedPool = recommendator.await().recommendedPool() ?: return null
return NominationPoolSelection(recommendedPool, stakingOption, stake)
}
@@ -13,7 +13,6 @@ import io.novafoundation.nova.feature_staking_impl.domain.staking.start.setupAmo
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 android.util.Log
import kotlin.coroutines.cancellation.CancellationException
class AutomaticMultiStakingSelectionType(
@@ -46,14 +45,8 @@ class AutomaticMultiStakingSelectionType(
}
override suspend fun updateSelectionFor(stake: Balance) {
Log.d("PEZ_STAKE", "updateSelectionFor: stake=$stake")
val stakingProperties = typePropertiesFor(stake)
Log.d("PEZ_STAKE", "updateSelectionFor: got properties type=${stakingProperties.stakingType}")
val candidates = stakingProperties.recommendation.recommendedSelection(stake) ?: run {
Log.d("PEZ_STAKE", "updateSelectionFor: recommendedSelection returned null, returning")
return
}
Log.d("PEZ_STAKE", "updateSelectionFor: got recommended selection")
val candidates = stakingProperties.recommendation.recommendedSelection(stake) ?: return
val recommendableSelection = RecommendableMultiStakingSelection(
source = SelectionTypeSource.Automatic,
@@ -62,25 +55,18 @@ class AutomaticMultiStakingSelectionType(
)
selectionStore.updateSelection(recommendableSelection)
Log.d("PEZ_STAKE", "updateSelectionFor: selection updated successfully")
}
private suspend fun typePropertiesFor(stake: Balance): SingleStakingProperties {
Log.d("PEZ_STAKE", "typePropertiesFor: trying ${candidates.size} candidates")
for ((index, candidate) in candidates.withIndex()) {
Log.d("PEZ_STAKE", "typePropertiesFor: checking candidate $index type=${candidate.stakingType}")
for (candidate in candidates) {
try {
val minStake = candidate.minStake()
Log.d("PEZ_STAKE", "typePropertiesFor: candidate $index minStake=$minStake, stake=$stake, allows=${minStake <= stake}")
if (minStake <= stake) return candidate
} catch (e: CancellationException) {
Log.d("PEZ_STAKE", "typePropertiesFor: candidate $index cancelled, rethrowing")
throw e
} catch (e: Exception) {
Log.e("PEZ_STAKE", "typePropertiesFor: candidate $index minStake() threw", e)
} catch (_: Exception) {
}
}
Log.d("PEZ_STAKE", "typePropertiesFor: no candidate allows, finding minimum")
return candidates.findWithMinimumStake()
}
@@ -1,6 +1,5 @@
package io.novafoundation.nova.runtime.extrinsic
import android.util.Log
import io.novafoundation.nova.runtime.extrinsic.extensions.AuthorizeCall
import io.novafoundation.nova.runtime.extrinsic.extensions.ChargeAssetTxPayment
import io.novafoundation.nova.runtime.extrinsic.extensions.CheckAppId
@@ -11,8 +10,6 @@ import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot
import io.novasama.substrate_sdk_android.runtime.extrinsic.builder.ExtrinsicBuilder
import io.novasama.substrate_sdk_android.runtime.extrinsic.v5.transactionExtension.TransactionExtension
private const val TAG = "CustomTxExtensions"
object CustomTransactionExtensions {
fun applyDefaultValues(builder: ExtrinsicBuilder) {
@@ -34,8 +31,6 @@ object CustomTransactionExtensions {
val extensions = mutableListOf<TransactionExtension>()
val signedExtIds = runtime.metadata.extrinsic.signedExtensions.map { it.id }
Log.d(TAG, "Metadata signed extensions: $signedExtIds")
// Add extensions based on what the metadata requires
if ("AuthorizeCall" in signedExtIds) {
extensions.add(AuthorizeCall())
@@ -57,7 +52,6 @@ object CustomTransactionExtensions {
extensions.add(CheckAppId())
}
Log.d(TAG, "Extensions to add: ${extensions.map { it.name }}")
return extensions
}
}
@@ -1,6 +1,5 @@
package io.novafoundation.nova.runtime.extrinsic
import android.util.Log
import io.novafoundation.nova.common.utils.orZero
import io.novafoundation.nova.runtime.ext.requireGenesisHash
import io.novafoundation.nova.runtime.extrinsic.extensions.PezkuwiCheckMortality
@@ -20,8 +19,6 @@ import io.novasama.substrate_sdk_android.runtime.extrinsic.v5.transactionExtensi
import io.novasama.substrate_sdk_android.runtime.extrinsic.v5.transactionExtension.extensions.CheckTxVersion
import io.novasama.substrate_sdk_android.runtime.extrinsic.v5.transactionExtension.extensions.checkMetadataHash.CheckMetadataHash
private const val TAG = "ExtrinsicBuilderFactory"
class ExtrinsicBuilderFactory(
private val chainRegistry: ChainRegistry,
private val mortalityConstructor: MortalityConstructor,
@@ -45,19 +42,10 @@ class ExtrinsicBuilderFactory(
): Sequence<ExtrinsicBuilder> {
val runtime = chainRegistry.getRuntime(chain.id)
// Log metadata extensions
val metadataExtensions = runtime.metadata.extrinsic.signedExtensions.map { it.id }
Log.d(TAG, "Chain: ${chain.name}, Metadata extensions: $metadataExtensions")
val mortality = mortalityConstructor.constructMortality(chain.id)
val metadataProof = metadataShortenerService.generateMetadataProof(chain.id)
// Log custom extensions
val customExtensions = CustomTransactionExtensions.defaultValues(runtime).map { it.name }
Log.d(TAG, "Custom extensions to add: $customExtensions")
val isPezkuwi = isPezkuwiChain(runtime)
Log.d(TAG, "isPezkuwiChain: $isPezkuwi")
return generateSequence {
ExtrinsicBuilder(
@@ -67,7 +55,6 @@ class ExtrinsicBuilderFactory(
).apply {
// Use custom CheckMortality for Pezkuwi chains to avoid type lookup issues
if (isPezkuwi) {
Log.d(TAG, "Using PezkuwiCheckMortality for ${chain.name}")
setTransactionExtension(PezkuwiCheckMortality(mortality.era, mortality.blockHash.fromHex()))
} else {
setTransactionExtension(CheckMortality(mortality.era, mortality.blockHash.fromHex()))
@@ -79,8 +66,6 @@ class ExtrinsicBuilderFactory(
setTransactionExtension(CheckTxVersion(metadataProof.usedVersion.transactionVersion))
CustomTransactionExtensions.defaultValues(runtime).forEach(::setTransactionExtension)
Log.d(TAG, "All extensions set for ${chain.name}")
}
}
}
@@ -1,6 +1,5 @@
package io.novafoundation.nova.runtime.multiNetwork.runtime
import android.util.Log
import com.google.gson.Gson
import io.novafoundation.nova.common.utils.md5
import io.novafoundation.nova.common.utils.newLimitedThreadPoolExecutor
@@ -79,8 +78,6 @@ class RuntimeFactory(
val metadataReader = RuntimeMetadataReader.read(runtimeMetadataRaw)
Log.d("RuntimeFactory", "Constructing metadata of version ${metadataReader.metadataVersion} for chain $chainId")
val schema = metadataReader.metadataPostV14.schema
val typePreset = if (metadataReader.metadataVersion < 14) {
@@ -93,13 +90,9 @@ class RuntimeFactory(
)
}
Log.d("RuntimeFactory", "DEBUG: TypesUsage for chain $chainId = $typesUsage")
val (types, baseHash, ownHash) = when (typesUsage) {
TypesUsage.BASE -> {
Log.d("RuntimeFactory", "DEBUG: Loading BASE types for $chainId")
val (types, baseHash) = constructBaseTypes(typePreset)
Log.d("RuntimeFactory", "DEBUG: BASE types loaded, hash=$baseHash, typeCount=${types.size}")
Triple(types, baseHash, null)
}
@@ -169,7 +162,6 @@ class RuntimeFactory(
val typePreset = try {
parseNetworkVersioning(ownTypesTree, withoutVersioning, runtimeVersion)
} catch (e: IllegalArgumentException) {
Log.w("RuntimeFactory", "No versioning info in chain types for $chainId, using base definitions")
withoutVersioning
}
@@ -178,12 +170,7 @@ class RuntimeFactory(
private suspend fun constructBaseTypes(initialPreset: TypePreset): Pair<TypePreset, String> {
val baseTypesRaw = runCatching { runtimeFilesCache.getBaseTypes() }
.getOrElse {
Log.e("RuntimeFactory", "DEBUG: BaseTypes NOT in cache!")
throw BaseTypesNotInCacheException
}
Log.d("RuntimeFactory", "BaseTypes loaded, len=${baseTypesRaw.length}")
.getOrElse { throw BaseTypesNotInCacheException }
val typePreset = parseBaseDefinitions(fromJson(baseTypesRaw), initialPreset)
@@ -1,6 +1,5 @@
package io.novafoundation.nova.runtime.network.updaters
import android.util.Log
import io.novafoundation.nova.common.utils.Modules
import io.novafoundation.nova.common.utils.system
import io.novafoundation.nova.core.storage.StorageCache
@@ -37,7 +36,6 @@ class BlockNumberUpdater(
return storageSubscriptionBuilder.subscribe(storageKey)
.onEach {
Log.d("BlockNumberUpdater", "Block number updated: ${it.value}")
storageCache.insert(it, scopeValue.id)
}
.noSideAffects()
@@ -1,6 +1,5 @@
package io.novafoundation.nova.runtime.util
import android.util.Log
import io.novasama.substrate_sdk_android.runtime.AccountId
import io.novasama.substrate_sdk_android.runtime.definitions.types.RuntimeType
import io.novasama.substrate_sdk_android.runtime.definitions.types.composite.DictEnum
@@ -8,18 +7,14 @@ import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.MULT
import io.novasama.substrate_sdk_android.runtime.definitions.types.primitives.FixedByteArray
import io.novasama.substrate_sdk_android.runtime.definitions.types.skipAliases
private const val TAG = "AccountLookup"
fun RuntimeType<*, *>.constructAccountLookupInstance(accountId: AccountId): Any {
val resolvedType = skipAliases()
Log.d(TAG, "Type name: ${this.name}, resolved type: ${resolvedType?.javaClass?.simpleName}")
return when (resolvedType) {
is DictEnum -> {
// MultiAddress type - wrap in the appropriate variant
// Standard chains use "Id", but Pezkuwi uses numeric variants like "0"
val variantNames = resolvedType.elements.values.map { it.name }
Log.d(TAG, "DictEnum variants: $variantNames")
// Use "Id" if available (standard chains), otherwise use the first variant (index 0)
// which is always the AccountId variant in MultiAddress
@@ -29,30 +24,22 @@ fun RuntimeType<*, *>.constructAccountLookupInstance(accountId: AccountId): Any
// For chains like Pezkuwi that use numeric variant names
resolvedType.elements[0]?.name ?: MULTI_ADDRESS_ID
}
Log.d(TAG, "Using variant name: $idVariantName")
DictEnum.Entry(idVariantName, accountId)
}
is FixedByteArray -> {
// GenericAccountId or similar - return raw accountId
Log.d(TAG, "FixedByteArray type, returning raw accountId")
accountId
}
null -> {
// For Pezkuwi chains where alias might not resolve properly
// Check if the original type name suggests MultiAddress
Log.d(TAG, "Resolved type is null, checking original type name: ${this.name}")
if (this.name?.contains("MultiAddress") == true || this.name?.contains("multiaddress") == true) {
// For unresolved MultiAddress types, use "0" which is the standard first variant (AccountId)
Log.d(TAG, "Type name contains MultiAddress, using DictEnum.Entry with variant 0")
DictEnum.Entry("0", accountId)
} else {
Log.d(TAG, "Unknown type with null resolution, returning raw accountId")
accountId
}
}
else -> {
// Unknown type - for Pezkuwi compatibility, try raw accountId instead of throwing
Log.w(TAG, "Unknown address type: ${this.name} (${resolvedType.javaClass.simpleName}), trying raw accountId")
// Unknown type - for Pezkuwi compatibility, try raw accountId
accountId
}
}