From 7a1e7d8270ccb49bacfcaa94b034e1f13ffbbb98 Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Tue, 24 Feb 2026 04:12:12 +0300 Subject: [PATCH] fix: Era type encoding, CheckMortality cleanup, and release log guard - Add Era AliasTo in PezkuwiPathTypeMapping for correct SCALE encoding - Remove redundant isPezkuwi CheckMortality logic from ExtrinsicBuilderFactory and PolkadotExternalSignInteractor (standard path now works for all chains) - Remove payload/signature hex logs from PezkuwiKeyPairSigner (security) - Wrap debug logs with BuildConfig.DEBUG in PezkuwiKeyPairSigner, MetadataShortenerService, and WalletConnectSessionsEvent --- .../PolkadotExternalSignInteractor.kt | 20 +--------------- .../list/WalletConnectSessionsEvent.kt | 23 +++++++++--------- .../extrinsic/ExtrinsicBuilderFactory.kt | 16 +------------ .../metadata/MetadataShortenerService.kt | 22 +++++++++++------ .../extrinsic/signer/PezkuwiKeyPairSigner.kt | 23 +++++++----------- .../multiNetwork/runtime/RuntimeFactory.kt | 1 - .../custom/pezkuwi/PezkuwiPathTypeMapping.kt | 24 +++++++++---------- 7 files changed, 50 insertions(+), 79 deletions(-) diff --git a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt index 96543fb..0dea7a6 100644 --- a/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt +++ b/feature-external-sign-impl/src/main/java/io/novafoundation/nova/feature_external_sign_impl/domain/sign/polkadot/PolkadotExternalSignInteractor.kt @@ -39,8 +39,6 @@ import io.novafoundation.nova.runtime.ext.anyAddressToAccountId import io.novafoundation.nova.runtime.ext.utilityAsset import io.novafoundation.nova.runtime.extrinsic.CustomTransactionExtensions import io.novafoundation.nova.runtime.extrinsic.extensions.ChargeAssetTxPayment.Companion.chargeAssetTxPayment -import io.novafoundation.nova.runtime.extrinsic.extensions.PezkuwiCheckImmortal -import io.novafoundation.nova.runtime.extrinsic.extensions.PezkuwiCheckMortality import io.novafoundation.nova.runtime.extrinsic.metadata.MetadataShortenerService import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain @@ -50,7 +48,6 @@ import io.novasama.substrate_sdk_android.extensions.fromHex import io.novasama.substrate_sdk_android.runtime.AccountId import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot import io.novasama.substrate_sdk_android.runtime.definitions.types.fromHex -import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.Era import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.EraType import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.GenericCall import io.novasama.substrate_sdk_android.runtime.extrinsic.BatchMode @@ -224,19 +221,9 @@ class PolkadotExternalSignInteractor( val signingContext = signingContextFactory.default(chain) - val isPezkuwi = isPezkuwiChain(runtime) - val extrinsic = with(parsedExtrinsic) { ExtrinsicBuilder(runtime, ExtrinsicVersion.V4, BatchMode.BATCH_ALL).apply { - // Use custom CheckMortality for Pezkuwi chains to avoid DictEnum type lookup issues - if (isPezkuwi) { - when (era) { - is Era.Mortal -> setTransactionExtension(PezkuwiCheckMortality(era, blockHash)) - is Era.Immortal -> setTransactionExtension(PezkuwiCheckImmortal(genesisHash)) - } - } else { - setTransactionExtension(CheckMortality(era, blockHash)) - } + setTransactionExtension(CheckMortality(era, blockHash)) setTransactionExtension(CheckGenesis(genesisHash)) setTransactionExtension(ChargeTransactionPayment(tip)) setTransactionExtension(CheckMetadataHash(actualMetadataHash.checkMetadataHash)) @@ -363,11 +350,6 @@ class PolkadotExternalSignInteractor( private fun PolkadotSignPayload.Json.tryDecodeAssetId(runtime: RuntimeSnapshot): Any? { return assetId?.let(runtime::decodeCustomTxPaymentId) } - - private fun isPezkuwiChain(runtime: RuntimeSnapshot): Boolean { - val signedExtIds = runtime.metadata.extrinsic.signedExtensions.map { it.id } - return signedExtIds.any { it == "AuthorizeCall" } - } } private fun CheckMetadataHashMode(hash: ByteArray?): CheckMetadataHashMode { diff --git a/feature-wallet-connect-impl/src/main/java/io/novafoundation/nova/feature_wallet_connect_impl/presentation/sessions/list/WalletConnectSessionsEvent.kt b/feature-wallet-connect-impl/src/main/java/io/novafoundation/nova/feature_wallet_connect_impl/presentation/sessions/list/WalletConnectSessionsEvent.kt index e5fb8cc..f38256e 100644 --- a/feature-wallet-connect-impl/src/main/java/io/novafoundation/nova/feature_wallet_connect_impl/presentation/sessions/list/WalletConnectSessionsEvent.kt +++ b/feature-wallet-connect-impl/src/main/java/io/novafoundation/nova/feature_wallet_connect_impl/presentation/sessions/list/WalletConnectSessionsEvent.kt @@ -2,6 +2,7 @@ package io.novafoundation.nova.feature_wallet_connect_impl.presentation.sessions import android.util.Log import com.walletconnect.web3.wallet.client.Wallet +import io.novafoundation.nova.feature_wallet_connect_impl.BuildConfig import com.walletconnect.web3.wallet.client.Web3Wallet import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose @@ -26,51 +27,51 @@ fun Web3Wallet.sessionEventsFlow(scope: CoroutineScope): Flow= MINIMUM_METADATA_VERSION_TO_CALCULATE_HASH val hasSignedExtension = runtimeMetadata.extrinsic.hasSignedExtension(DefaultSignedExtensions.CHECK_METADATA_HASH) - Log.d( - "MetadataShortenerService", - "Chain: ${chain.name}, disabledByConfig=$disabledByConfig, canBeEnabled=$canBeEnabled, " + - "atLeastMinimumVersion=$atLeastMinimumVersion, hasSignedExtension=$hasSignedExtension" - ) - Log.d("MetadataShortenerService", "chain.additional: ${chain.additional}, disabledCheckMetadataHash=${chain.additional?.disabledCheckMetadataHash}") + if (BuildConfig.DEBUG) { + Log.d( + "MetadataShortenerService", + "Chain: ${chain.name}, disabledByConfig=$disabledByConfig, canBeEnabled=$canBeEnabled, " + + "atLeastMinimumVersion=$atLeastMinimumVersion, hasSignedExtension=$hasSignedExtension" + ) + Log.d("MetadataShortenerService", "chain.additional: ${chain.additional}, disabledCheckMetadataHash=${chain.additional?.disabledCheckMetadataHash}") + } val result = canBeEnabled && atLeastMinimumVersion && hasSignedExtension - Log.d("MetadataShortenerService", "shouldCalculateMetadataHash result: $result (will use ${if (result) "ENABLED" else "DISABLED"} mode)") + if (BuildConfig.DEBUG) { + Log.d( + "MetadataShortenerService", + "shouldCalculateMetadataHash result: $result (will use ${if (result) "ENABLED" else "DISABLED"} mode)" + ) + } return result } } diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/extrinsic/signer/PezkuwiKeyPairSigner.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/extrinsic/signer/PezkuwiKeyPairSigner.kt index a5b161c..1235ac8 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/extrinsic/signer/PezkuwiKeyPairSigner.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/extrinsic/signer/PezkuwiKeyPairSigner.kt @@ -1,6 +1,7 @@ package io.novafoundation.nova.runtime.extrinsic.signer import android.util.Log +import io.novafoundation.nova.runtime.BuildConfig import io.novafoundation.nova.sr25519.BizinikiwSr25519 import io.novasama.substrate_sdk_android.encrypt.SignatureWrapper import io.novasama.substrate_sdk_android.runtime.AccountId @@ -30,23 +31,20 @@ class PezkuwiKeyPairSigner private constructor( fun fromSeed(seed: ByteArray): PezkuwiKeyPairSigner { require(seed.size == 32) { "Seed must be 32 bytes, got ${seed.size}" } - Log.d("PezkuwiSigner", "Creating signer from seed") + if (BuildConfig.DEBUG) Log.d("PezkuwiSigner", "Creating signer from seed") // Expand seed to 96-byte keypair val expandedKeypair = BizinikiwSr25519.keypairFromSeed(seed) - Log.d("PezkuwiSigner", "Expanded keypair size: ${expandedKeypair.size}") + if (BuildConfig.DEBUG) Log.d("PezkuwiSigner", "Expanded keypair size: ${expandedKeypair.size}") // Extract 64-byte secret key and 32-byte public key val secretKey = BizinikiwSr25519.secretKeyFromKeypair(expandedKeypair) val publicKey = BizinikiwSr25519.publicKeyFromKeypair(expandedKeypair) - Log.d("PezkuwiSigner", "Secret key size: ${secretKey.size}") - Log.d("PezkuwiSigner", "Public key: ${publicKey.toHex()}") + if (BuildConfig.DEBUG) Log.d("PezkuwiSigner", "Secret key size: ${secretKey.size}") return PezkuwiKeyPairSigner(secretKey, publicKey) } - - private fun ByteArray.toHex(): String = joinToString("") { "%02x".format(it) } } override suspend fun signInheritedImplication( @@ -55,9 +53,10 @@ class PezkuwiKeyPairSigner private constructor( ): SignatureWrapper { val payload = inheritedImplication.signingPayload() - Log.d("PezkuwiSigner", "=== SIGNING WITH BIZINIKIWI ===") - Log.d("PezkuwiSigner", "Payload size: ${payload.size}") - Log.d("PezkuwiSigner", "Payload: ${payload.toHex()}") + if (BuildConfig.DEBUG) { + Log.d("PezkuwiSigner", "=== SIGNING WITH BIZINIKIWI ===") + Log.d("PezkuwiSigner", "Payload size: ${payload.size}") + } // Use BizinikiwSr25519 native library with "bizinikiwi" signing context val signature = BizinikiwSr25519.sign( @@ -66,17 +65,13 @@ class PezkuwiKeyPairSigner private constructor( message = payload ) - Log.d("PezkuwiSigner", "Signature: ${signature.toHex()}") - // Verify locally val verified = BizinikiwSr25519.verify(signature, payload, publicKey) - Log.d("PezkuwiSigner", "Local verification: $verified") + if (BuildConfig.DEBUG) Log.d("PezkuwiSigner", "Local verification: $verified") return SignatureWrapper.Sr25519(signature) } - private fun ByteArray.toHex(): String = joinToString("") { "%02x".format(it) } - suspend fun signRaw(payload: SignerPayloadRaw): SignedRaw { // Use BizinikiwSr25519 native library with "bizinikiwi" signing context val signature = BizinikiwSr25519.sign( diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeFactory.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeFactory.kt index 923e018..a6eba77 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeFactory.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/RuntimeFactory.kt @@ -207,7 +207,6 @@ class RuntimeFactory( "pezsp_runtime.multiaddress.MultiAddress" to "MultiAddress", "pezsp_runtime.MultiSignature" to "ExtrinsicSignature", "pezsp_runtime.MultiSignature" to "MultiSignature", - "pezsp_runtime.generic.era.Era" to "Era", // Fee-related types "pezframe_support.dispatch.DispatchInfo" to "DispatchInfo", "pezpallet_transaction_payment.types.RuntimeDispatchInfo" to "RuntimeDispatchInfo", diff --git a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/types/custom/pezkuwi/PezkuwiPathTypeMapping.kt b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/types/custom/pezkuwi/PezkuwiPathTypeMapping.kt index 9b5ec34..7fcf58f 100644 --- a/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/types/custom/pezkuwi/PezkuwiPathTypeMapping.kt +++ b/runtime/src/main/java/io/novafoundation/nova/runtime/multiNetwork/runtime/types/custom/pezkuwi/PezkuwiPathTypeMapping.kt @@ -7,25 +7,25 @@ import io.novasama.substrate_sdk_android.runtime.definitions.v14.typeMapping.Pat * PathMatchTypeMapping for Pezkuwi chains that use pezsp_* and pezframe_* package prefixes * instead of the standard sp_* and frame_* prefixes used by Polkadot/Substrate chains. * - * This maps specific Pezkuwi type paths to standard type names: - * - RuntimeCall/RuntimeEvent -> GenericCall/GenericEvent + * This maps specific Pezkuwi type paths to standard type names during metadata parsing. + * Aliasing at parse time ensures the type ID mapping also uses the correct type. * - * IMPORTANT: Era, MultiSignature, MultiAddress, and Weight types are NOT aliased here. - * They need to be parsed as actual types from metadata. RuntimeFactory.addPezkuwiTypeAliases() - * handles copying these types to standard names after parsing. + * Era MUST be aliased here (not in RuntimeFactory.addPezkuwiTypeAliases) because the built-in + * EraType has special encode/decode logic for Era.Mortal/Era.Immortal that the raw DictEnum + * from metadata doesn't support. Aliasing at parse time ensures the type ID resolves correctly. * - * NOTE: Weight types (pezsp_weights.weight_v2.Weight) are NOT aliased because the SDK - * doesn't have a WeightV1 type defined. They are parsed as structs from metadata. + * MultiSignature, MultiAddress: NOT aliased here — their DictEnum versions from metadata are + * structurally identical to built-ins. RuntimeFactory.addPezkuwiTypeAliases() copies them. + * + * Weight types: NOT aliased — SDK doesn't have a WeightV1 type. Parsed as structs from metadata. */ fun PezkuwiPathTypeMapping(): PathMatchTypeMapping = PathMatchTypeMapping( - // NOTE: Do NOT alias pezsp_runtime.generic.era.Era, pezsp_runtime.MultiSignature, - // pezsp_runtime.multiaddress.MultiAddress, or pezsp_weights.weight_v2.Weight here. - // These need to be parsed as actual types from metadata. - // RuntimeFactory.addPezkuwiTypeAliases() copies the parsed types to standard names. - // Runtime call/event types for Pezkuwi "*.RuntimeCall" to AliasTo("GenericCall"), "*.RuntimeEvent" to AliasTo("GenericEvent"), "*_runtime.Call" to AliasTo("GenericCall"), "*_runtime.Event" to AliasTo("GenericEvent"), + + // Era: alias to built-in EraType so ExtrinsicBuilder can encode Era.Mortal/Era.Immortal + "pezsp_runtime.generic.era.Era" to AliasTo("Era"), )