Initial commit: Pezkuwi Wallet Android

Complete rebrand of Nova Wallet for Pezkuwichain ecosystem.

## Features
- Full Pezkuwichain support (HEZ & PEZ tokens)
- Polkadot ecosystem compatibility
- Staking, Governance, DeFi, NFTs
- XCM cross-chain transfers
- Hardware wallet support (Ledger, Polkadot Vault)
- WalletConnect v2
- Push notifications

## Languages
- English, Turkish, Kurmanci (Kurdish), Spanish, French, German, Russian, Japanese, Chinese, Korean, Portuguese, Vietnamese

Based on Nova Wallet by Novasama Technologies GmbH
© Dijital Kurdistan Tech Institute 2026
This commit is contained in:
2026-01-23 01:31:12 +03:00
commit 31c8c5995f
7621 changed files with 425838 additions and 0 deletions
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"/>
@@ -0,0 +1,26 @@
package io.novafoundation.nova.feature_proxy_impl.data.common
import io.novafoundation.nova.feature_proxy_api.data.common.DepositBaseAndFactor
import io.novafoundation.nova.feature_proxy_api.data.common.ProxyDepositCalculator
import io.novafoundation.nova.feature_proxy_api.data.repository.ProxyConstantsRepository
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
import java.math.BigInteger
class RealProxyDepositCalculator(
private val proxyConstantsRepository: ProxyConstantsRepository
) : ProxyDepositCalculator {
override fun calculateProxyDepositForQuantity(baseAndFactor: DepositBaseAndFactor, proxiesCount: Int): BigInteger {
return if (proxiesCount == 0) {
BigInteger.ZERO
} else {
baseAndFactor.baseAmount + baseAndFactor.factorAmount * proxiesCount.toBigInteger()
}
}
override suspend fun calculateProxyDepositForQuantity(chainId: ChainId, proxiesCount: Int): BigInteger {
val depositAndFactor = proxyConstantsRepository.getDepositConstants(chainId)
return calculateProxyDepositForQuantity(depositAndFactor, proxiesCount)
}
}
@@ -0,0 +1,148 @@
package io.novafoundation.nova.feature_proxy_impl.data.repository
import io.novafoundation.nova.common.address.AccountIdKey
import io.novafoundation.nova.common.address.intoKey
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.getTyped
import io.novafoundation.nova.common.utils.Modules
import io.novafoundation.nova.common.utils.numberConstant
import io.novafoundation.nova.common.utils.proxy
import io.novafoundation.nova.feature_proxy_api.data.model.OnChainProxiedModel
import io.novafoundation.nova.feature_proxy_api.data.model.OnChainProxyModel
import io.novafoundation.nova.feature_proxy_api.data.model.ProxiesMap
import io.novafoundation.nova.feature_proxy_api.data.model.ProxyPermission
import io.novafoundation.nova.feature_proxy_api.data.repository.GetProxyRepository
import io.novafoundation.nova.feature_proxy_api.domain.model.ProxyType
import io.novafoundation.nova.feature_proxy_api.domain.model.fromString
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.getRuntime
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
import io.novasama.substrate_sdk_android.runtime.AccountId
import io.novasama.substrate_sdk_android.runtime.metadata.module
import io.novasama.substrate_sdk_android.runtime.metadata.storage
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import java.math.BigInteger
class RealGetProxyRepository(
private val remoteSource: StorageDataSource,
private val localSource: StorageDataSource,
private val chainRegistry: ChainRegistry,
) : GetProxyRepository {
override suspend fun getAllProxies(chainId: ChainId): ProxiesMap {
return receiveAllProxiesInChain(chainId)
}
override suspend fun getDelegatedProxyTypesRemote(chainId: ChainId, proxiedAccountId: AccountId, proxyAccountId: AccountId): List<ProxyType> {
return getDelegatedProxyTypes(remoteSource, chainId, proxiedAccountId, proxyAccountId)
}
// TODO: use it for staking after merge "add staking proxy" branch
override suspend fun getDelegatedProxyTypesLocal(chainId: ChainId, proxiedAccountId: AccountId, proxyAccountId: AccountId): List<ProxyType> {
return getDelegatedProxyTypes(localSource, chainId, proxiedAccountId, proxyAccountId)
}
override suspend fun getProxiesQuantity(chainId: ChainId, proxiedAccountId: AccountId): Int {
val proxied = getAllProxiesFor(localSource, chainId, proxiedAccountId)
return proxied.proxies.size
}
override suspend fun getProxyDeposit(chainId: ChainId, proxiedAccountId: AccountId): BigInteger {
val proxied = getAllProxiesFor(localSource, chainId, proxiedAccountId)
return proxied.deposit
}
override suspend fun maxProxiesQuantity(chain: Chain): Int {
val runtime = chainRegistry.getRuntime(chain.id)
val constantQuery = runtime.metadata.proxy()
return constantQuery.numberConstant("MaxProxies", runtime).toInt()
}
override fun proxiesByTypeFlow(chain: Chain, accountId: AccountId, proxyType: ProxyType): Flow<List<ProxyPermission>> {
return localSource.subscribe(chain.id) {
runtime.metadata.module(Modules.PROXY)
.storage("Proxies")
.observe(
accountId,
binding = { bindProxyAccounts(it) }
)
}.map { proxied ->
proxied.proxies
.filter { it.proxyType.name == proxyType.name }
.map { ProxyPermission(accountId.intoKey(), it.proxy, it.proxyType) }
}
}
override fun proxiesQuantityByTypeFlow(chain: Chain, accountId: AccountId, proxyType: ProxyType): Flow<Int> {
return proxiesByTypeFlow(chain, accountId, proxyType)
.map { it.size }
}
private suspend fun getDelegatedProxyTypes(
storageDataSource: StorageDataSource,
chainId: ChainId,
proxiedAccountId: AccountId,
proxyAccountId: AccountId
): List<ProxyType> {
val proxied = getAllProxiesFor(storageDataSource, chainId, proxiedAccountId)
return proxied.proxies
.filter { it.proxy == proxyAccountId.intoKey() }
.map { it.proxyType }
}
private suspend fun getAllProxiesFor(storageDataSource: StorageDataSource, chainId: ChainId, accountId: AccountId): OnChainProxiedModel {
return storageDataSource.query(chainId) {
runtime.metadata.module(Modules.PROXY)
.storage("Proxies")
.query(
keyArguments = arrayOf(accountId),
binding = { result -> bindProxyAccounts(result) }
)
}
}
private suspend fun receiveAllProxiesInChain(chainId: ChainId): Map<AccountIdKey, OnChainProxiedModel> {
return remoteSource.query(chainId) {
runtime.metadata.module(Modules.PROXY)
.storage("Proxies")
.entries(
keyExtractor = { (accountId: AccountId) -> AccountIdKey(accountId) },
binding = { result, _ -> bindProxyAccounts(result) },
recover = { _, _ ->
// Do nothing if entry binding throws an exception
}
)
}
}
private fun bindProxyAccounts(dynamicInstance: Any?): OnChainProxiedModel {
if (dynamicInstance == null) return OnChainProxiedModel(emptyList(), BigInteger.ZERO)
val root = dynamicInstance.castToList()
val proxies = root[0].castToList()
return OnChainProxiedModel(
proxies = proxies.map {
val proxy = it.castToStruct()
val proxyAccountId: ByteArray = proxy.getTyped("delegate")
val proxyType = proxy.get<Any?>("proxyType").castToDictEnum()
val delay = proxy.getTyped<BigInteger>("delay")
OnChainProxyModel(
proxy = proxyAccountId.intoKey(),
proxyType = ProxyType.fromString(proxyType.name),
delay = delay
)
},
deposit = root[1].cast()
)
}
}
@@ -0,0 +1,23 @@
package io.novafoundation.nova.feature_proxy_impl.data.repository
import io.novafoundation.nova.common.utils.numberConstant
import io.novafoundation.nova.common.utils.proxy
import io.novafoundation.nova.feature_proxy_api.data.common.DepositBaseAndFactor
import io.novafoundation.nova.feature_proxy_api.data.repository.ProxyConstantsRepository
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
import io.novafoundation.nova.runtime.multiNetwork.getRuntime
class RealProxyConstantsRepository(
private val chainRegestry: ChainRegistry
) : ProxyConstantsRepository {
override suspend fun getDepositConstants(chainId: ChainId): DepositBaseAndFactor {
val runtime = chainRegestry.getRuntime(chainId)
val constantQuery = runtime.metadata.proxy()
return DepositBaseAndFactor(
baseAmount = constantQuery.numberConstant("ProxyDepositBase", runtime),
factorAmount = constantQuery.numberConstant("ProxyDepositFactor", runtime)
)
}
}
@@ -0,0 +1,35 @@
package io.novafoundation.nova.feature_proxy_impl.di
import dagger.Component
import io.novafoundation.nova.common.di.CommonApi
import io.novafoundation.nova.common.di.scope.FeatureScope
import io.novafoundation.nova.feature_proxy_api.di.ProxyFeatureApi
import io.novafoundation.nova.runtime.di.RuntimeApi
@Component(
dependencies = [
ProxyFeatureDependencies::class
],
modules = [
ProxyFeatureModule::class,
]
)
@FeatureScope
interface ProxyFeatureComponent : ProxyFeatureApi {
@Component.Factory
interface Factory {
fun create(
deps: ProxyFeatureDependencies
): ProxyFeatureComponent
}
@Component(
dependencies = [
CommonApi::class,
RuntimeApi::class
]
)
interface VoteFeatureDependenciesComponent : ProxyFeatureDependencies
}
@@ -0,0 +1,18 @@
package io.novafoundation.nova.feature_proxy_impl.di
import io.novafoundation.nova.runtime.di.LOCAL_STORAGE_SOURCE
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
import javax.inject.Named
interface ProxyFeatureDependencies {
@Named(REMOTE_STORAGE_SOURCE)
fun remoteStorageSource(): StorageDataSource
@Named(LOCAL_STORAGE_SOURCE)
fun localStorageSource(): StorageDataSource
fun chainRegistry(): ChainRegistry
}
@@ -0,0 +1,22 @@
package io.novafoundation.nova.feature_proxy_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.runtime.di.RuntimeApi
import javax.inject.Inject
@ApplicationScope
class ProxyFeatureHolder @Inject constructor(
featureContainer: FeatureContainer
) : FeatureApiHolder(featureContainer) {
override fun initializeDependencies(): Any {
val dependencies = DaggerProxyFeatureComponent_VoteFeatureDependenciesComponent.builder()
.commonApi(commonApi())
.runtimeApi(getFeature(RuntimeApi::class.java))
.build()
return DaggerProxyFeatureComponent.factory()
.create(dependencies)
}
}
@@ -0,0 +1,48 @@
package io.novafoundation.nova.feature_proxy_impl.di
import dagger.Module
import dagger.Provides
import io.novafoundation.nova.common.di.scope.FeatureScope
import io.novafoundation.nova.feature_proxy_api.data.common.ProxyDepositCalculator
import io.novafoundation.nova.feature_proxy_api.data.repository.GetProxyRepository
import io.novafoundation.nova.feature_proxy_api.data.repository.ProxyConstantsRepository
import io.novafoundation.nova.feature_proxy_impl.data.common.RealProxyDepositCalculator
import io.novafoundation.nova.feature_proxy_impl.data.repository.RealGetProxyRepository
import io.novafoundation.nova.feature_proxy_impl.data.repository.RealProxyConstantsRepository
import io.novafoundation.nova.runtime.di.LOCAL_STORAGE_SOURCE
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
import javax.inject.Named
@Module
class ProxyFeatureModule {
@Provides
@FeatureScope
fun provideProxyRepository(
@Named(REMOTE_STORAGE_SOURCE) remoteSource: StorageDataSource,
@Named(LOCAL_STORAGE_SOURCE) localSource: StorageDataSource,
chainRegistry: ChainRegistry
): GetProxyRepository = RealGetProxyRepository(
remoteSource = remoteSource,
localSource = localSource,
chainRegistry
)
@Provides
@FeatureScope
fun provideProxyConstantsRepository(
chainRegistry: ChainRegistry
): ProxyConstantsRepository = RealProxyConstantsRepository(
chainRegistry
)
@Provides
@FeatureScope
fun provideProxyDepositCalculator(
proxyConstantsRepository: ProxyConstantsRepository
): ProxyDepositCalculator {
return RealProxyDepositCalculator(proxyConstantsRepository)
}
}