mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-21 22:38:01 +00:00
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
This commit is contained in:
+1
-19
@@ -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 {
|
||||
|
||||
+12
-11
@@ -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<WalletConnectSessi
|
||||
setWalletDelegate(object : Web3Wallet.WalletDelegate {
|
||||
|
||||
override fun onAuthRequest(authRequest: Wallet.Model.AuthRequest, verifyContext: Wallet.Model.VerifyContext) {
|
||||
Log.d("WalletConnect", "Auth request: $authRequest")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "Auth request: $authRequest")
|
||||
}
|
||||
|
||||
override fun onConnectionStateChange(state: Wallet.Model.ConnectionState) {
|
||||
Log.d("WalletConnect", "on connection state change: $state")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "on connection state change: $state")
|
||||
}
|
||||
|
||||
override fun onError(error: Wallet.Model.Error) {
|
||||
Log.e("WalletConnect", "Wallet Connect error", error.throwable)
|
||||
if (BuildConfig.DEBUG) Log.e("WalletConnect", "Wallet Connect error", error.throwable)
|
||||
}
|
||||
|
||||
override fun onProposalExpired(proposal: Wallet.Model.ExpiredProposal) {
|
||||
Log.d("WalletConnect", "Proposal expired: $proposal")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "Proposal expired: $proposal")
|
||||
}
|
||||
|
||||
override fun onRequestExpired(request: Wallet.Model.ExpiredRequest) {
|
||||
Log.d("WalletConnect", "Request expired: $request")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "Request expired: $request")
|
||||
}
|
||||
|
||||
override fun onSessionDelete(sessionDelete: Wallet.Model.SessionDelete) {
|
||||
Log.d("WalletConnect", "on session delete: $sessionDelete")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "on session delete: $sessionDelete")
|
||||
channel.trySend(WalletConnectSessionsEvent.SessionDeleted(sessionDelete))
|
||||
}
|
||||
|
||||
override fun onSessionExtend(session: Wallet.Model.Session) {
|
||||
Log.d("WalletConnect", "On session extend: $session")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "On session extend: $session")
|
||||
}
|
||||
|
||||
override fun onSessionProposal(sessionProposal: Wallet.Model.SessionProposal, verifyContext: Wallet.Model.VerifyContext) {
|
||||
Log.d("WalletConnect", "on session proposal: $sessionProposal")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "on session proposal: $sessionProposal")
|
||||
channel.trySend(WalletConnectSessionsEvent.SessionProposal(sessionProposal))
|
||||
}
|
||||
|
||||
override fun onSessionRequest(sessionRequest: Wallet.Model.SessionRequest, verifyContext: Wallet.Model.VerifyContext) {
|
||||
Log.d("WalletConnect", "on session request: $sessionRequest")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "on session request: $sessionRequest")
|
||||
channel.trySend(WalletConnectSessionsEvent.SessionRequest(sessionRequest))
|
||||
}
|
||||
|
||||
override fun onSessionSettleResponse(settleSessionResponse: Wallet.Model.SettledSessionResponse) {
|
||||
Log.d("WalletConnect", "on session settled: $settleSessionResponse")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "on session settled: $settleSessionResponse")
|
||||
channel.trySend(WalletConnectSessionsEvent.SessionSettlement(settleSessionResponse))
|
||||
}
|
||||
|
||||
override fun onSessionUpdateResponse(sessionUpdateResponse: Wallet.Model.SessionUpdateResponse) {
|
||||
Log.d("WalletConnect", "on session update: $sessionUpdateResponse")
|
||||
if (BuildConfig.DEBUG) Log.d("WalletConnect", "on session update: $sessionUpdateResponse")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
+1
-15
@@ -2,13 +2,11 @@ package io.novafoundation.nova.runtime.extrinsic
|
||||
|
||||
import io.novafoundation.nova.common.utils.orZero
|
||||
import io.novafoundation.nova.runtime.ext.requireGenesisHash
|
||||
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
|
||||
import io.novafoundation.nova.runtime.multiNetwork.getRuntime
|
||||
import io.novasama.substrate_sdk_android.extensions.fromHex
|
||||
import io.novasama.substrate_sdk_android.runtime.RuntimeSnapshot
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.BatchMode
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.ExtrinsicVersion
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.builder.ExtrinsicBuilder
|
||||
@@ -45,20 +43,13 @@ class ExtrinsicBuilderFactory(
|
||||
val mortality = mortalityConstructor.constructMortality(chain.id)
|
||||
val metadataProof = metadataShortenerService.generateMetadataProof(chain.id)
|
||||
|
||||
val isPezkuwi = isPezkuwiChain(runtime)
|
||||
|
||||
return generateSequence {
|
||||
ExtrinsicBuilder(
|
||||
runtime = runtime,
|
||||
extrinsicVersion = ExtrinsicVersion.V4,
|
||||
batchMode = options.batchMode,
|
||||
).apply {
|
||||
// Use custom CheckMortality for Pezkuwi chains to avoid type lookup issues
|
||||
if (isPezkuwi) {
|
||||
setTransactionExtension(PezkuwiCheckMortality(mortality.era, mortality.blockHash.fromHex()))
|
||||
} else {
|
||||
setTransactionExtension(CheckMortality(mortality.era, mortality.blockHash.fromHex()))
|
||||
}
|
||||
setTransactionExtension(CheckMortality(mortality.era, mortality.blockHash.fromHex()))
|
||||
setTransactionExtension(CheckGenesis(chain.requireGenesisHash().fromHex()))
|
||||
setTransactionExtension(ChargeTransactionPayment(chain.additional?.defaultTip.orZero()))
|
||||
setTransactionExtension(CheckMetadataHash(metadataProof.checkMetadataHash))
|
||||
@@ -69,9 +60,4 @@ class ExtrinsicBuilderFactory(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isPezkuwiChain(runtime: RuntimeSnapshot): Boolean {
|
||||
val signedExtIds = runtime.metadata.extrinsic.signedExtensions.map { it.id }
|
||||
return signedExtIds.any { it == "AuthorizeCall" }
|
||||
}
|
||||
}
|
||||
|
||||
+15
-7
@@ -2,6 +2,7 @@ package io.novafoundation.nova.runtime.extrinsic.metadata
|
||||
|
||||
import android.util.Log
|
||||
import io.novafoundation.nova.common.utils.hasSignedExtension
|
||||
import io.novafoundation.nova.runtime.BuildConfig
|
||||
import io.novafoundation.nova.metadata_shortener.MetadataShortener
|
||||
import io.novafoundation.nova.runtime.ext.shouldDisableMetadataHashCheck
|
||||
import io.novafoundation.nova.runtime.ext.utilityAsset
|
||||
@@ -173,15 +174,22 @@ internal class RealMetadataShortenerService(
|
||||
val atLeastMinimumVersion = runtimeMetadata.metadataVersion >= 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
|
||||
}
|
||||
}
|
||||
|
||||
+9
-14
@@ -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(
|
||||
|
||||
-1
@@ -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",
|
||||
|
||||
+12
-12
@@ -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"),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user