mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-27 12:37:57 +00:00
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:
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"/>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.novafoundation.nova.web3names.data.endpoints
|
||||
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface TransferRecipientsApi {
|
||||
|
||||
@GET
|
||||
suspend fun getTransferRecipientsRaw(
|
||||
@Url url: String
|
||||
): String
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package io.novafoundation.nova.web3names.data.endpoints.model
|
||||
|
||||
class TransferRecipientDetailsRemoteV1(
|
||||
val account: String,
|
||||
val description: String?
|
||||
)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package io.novafoundation.nova.web3names.data.endpoints.model
|
||||
|
||||
class TransferRecipientDetailsRemoteV2(
|
||||
val description: String?
|
||||
)
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package io.novafoundation.nova.web3names.data.provider
|
||||
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.ChainId
|
||||
|
||||
interface Web3NamesServiceChainIdProvider {
|
||||
fun getChainId(): ChainId
|
||||
}
|
||||
|
||||
class RealWeb3NamesServiceChainIdProvider(private val chainId: ChainId) : Web3NamesServiceChainIdProvider {
|
||||
|
||||
override fun getChainId(): ChainId {
|
||||
return chainId
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
package io.novafoundation.nova.web3names.data.repository
|
||||
|
||||
import io.novafoundation.nova.caip.caip19.Caip19MatcherFactory
|
||||
import io.novafoundation.nova.caip.caip19.Caip19Parser
|
||||
import io.novafoundation.nova.caip.caip19.matchers.Caip19Matcher
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindList
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.bindString
|
||||
import io.novafoundation.nova.common.data.network.runtime.binding.castToStruct
|
||||
import io.novafoundation.nova.runtime.ext.isValidAddress
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novafoundation.nova.web3names.data.provider.Web3NamesServiceChainIdProvider
|
||||
import io.novafoundation.nova.web3names.data.serviceEndpoint.ServiceEndpoint
|
||||
import io.novafoundation.nova.web3names.data.serviceEndpoint.W3NRecepient
|
||||
import io.novafoundation.nova.web3names.data.serviceEndpoint.W3NServiceEndpointHandlerFactory
|
||||
import io.novafoundation.nova.web3names.domain.exceptions.Web3NamesException.ChainProviderNotFoundException
|
||||
import io.novafoundation.nova.web3names.domain.exceptions.Web3NamesException.UnsupportedAsset
|
||||
import io.novafoundation.nova.web3names.domain.exceptions.Web3NamesException.ValidAccountNotFoundException
|
||||
import io.novafoundation.nova.web3names.domain.models.Web3NameAccount
|
||||
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
|
||||
|
||||
class RealWeb3NamesRepository(
|
||||
private val remoteStorageSource: StorageDataSource,
|
||||
private val web3NamesServiceChainIdProvider: Web3NamesServiceChainIdProvider,
|
||||
private val caip19MatcherFactory: Caip19MatcherFactory,
|
||||
private val caip19Parser: Caip19Parser,
|
||||
private val serviceEndpointHandlerFactory: W3NServiceEndpointHandlerFactory,
|
||||
) : Web3NamesRepository {
|
||||
|
||||
override suspend fun queryWeb3NameAccount(web3Name: String, chain: Chain, chainAsset: Chain.Asset): List<Web3NameAccount> {
|
||||
val caip19Matcher = caip19MatcherFactory.getCaip19Matcher(chain, chainAsset)
|
||||
if (caip19Matcher.isUnsupported()) throw UnsupportedAsset(web3Name, chainAsset)
|
||||
|
||||
val owner = getWeb3NameAccountOwner(web3Name) ?: throw ChainProviderNotFoundException(web3Name)
|
||||
val serviceEndpoints = getDidServiceEndpoints(owner)
|
||||
val serviceEndpointHandler = serviceEndpointHandlerFactory.getHandler(serviceEndpoints) ?: throw ValidAccountNotFoundException(web3Name, chain.name)
|
||||
|
||||
val recipients = serviceEndpointHandler.getRecipients(web3Name, chain)
|
||||
|
||||
return findChainRecipients(recipients, web3Name, chain, caip19Matcher)
|
||||
}
|
||||
|
||||
private suspend fun getWeb3NameAccountOwner(web3Name: String): AccountId? {
|
||||
return remoteStorageSource.query(web3NamesServiceChainIdProvider.getChainId()) {
|
||||
runtime.metadata
|
||||
.module("Web3Names")
|
||||
.storage("Owner")
|
||||
.query(web3Name.toByteArray(), binding = ::bindOwners)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getDidServiceEndpoints(accountId: AccountId): List<ServiceEndpoint> {
|
||||
val serviceEndpoints = remoteStorageSource.query(web3NamesServiceChainIdProvider.getChainId()) {
|
||||
runtime.metadata.module("Did")
|
||||
.storage("ServiceEndpoints")
|
||||
.entries(
|
||||
accountId,
|
||||
keyExtractor = { it },
|
||||
binding = { data, _ -> bindEndpoint(data) }
|
||||
)
|
||||
}
|
||||
|
||||
return serviceEndpoints.values.toList()
|
||||
}
|
||||
|
||||
private fun findChainRecipients(
|
||||
recipients: List<W3NRecepient>,
|
||||
w3nIdentifier: String,
|
||||
chain: Chain,
|
||||
caip19Matcher: Caip19Matcher
|
||||
): List<Web3NameAccount> {
|
||||
val matchingRecipients = recipients.groupBy { it.chainIdCaip19 }
|
||||
.filterKeys {
|
||||
val caip19Identifier = caip19Parser.parseCaip19(it).getOrNull() ?: return@filterKeys false
|
||||
|
||||
caip19Matcher.match(caip19Identifier)
|
||||
}
|
||||
|
||||
if (matchingRecipients.isEmpty()) {
|
||||
throw ValidAccountNotFoundException(w3nIdentifier, chain.name)
|
||||
}
|
||||
|
||||
val web3NameAccounts = matchingRecipients.flatMap { (_, chainRecipients) -> chainRecipients }
|
||||
.map {
|
||||
Web3NameAccount(
|
||||
address = it.account,
|
||||
description = it.description,
|
||||
isValid = chain.isValidAddress(it.account)
|
||||
)
|
||||
}
|
||||
|
||||
if (web3NameAccounts.none(Web3NameAccount::isValid)) {
|
||||
throw ValidAccountNotFoundException(w3nIdentifier, chain.name)
|
||||
}
|
||||
|
||||
return web3NameAccounts
|
||||
}
|
||||
|
||||
private fun bindOwners(data: Any?): AccountId? {
|
||||
if (data == null) return null
|
||||
|
||||
val ownerStruct = data.castToStruct()
|
||||
return ownerStruct.get<AccountId>("owner")
|
||||
}
|
||||
|
||||
private fun bindEndpoint(data: Any?): ServiceEndpoint {
|
||||
val endpointStruct = data.castToStruct()
|
||||
|
||||
val serviceTypes = bindList(endpointStruct["serviceTypes"]) { bindString(it) }
|
||||
val urls = bindList(endpointStruct["urls"]) { bindString(it) }
|
||||
val id = bindString(endpointStruct["id"])
|
||||
|
||||
return ServiceEndpoint(id, serviceTypes, urls)
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package io.novafoundation.nova.web3names.data.repository
|
||||
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.web3names.domain.models.Web3NameAccount
|
||||
|
||||
interface Web3NamesRepository {
|
||||
|
||||
suspend fun queryWeb3NameAccount(web3Name: String, chain: Chain, chainAsset: Chain.Asset): List<Web3NameAccount>
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package io.novafoundation.nova.web3names.data.serviceEndpoint
|
||||
|
||||
class ServiceEndpoint(
|
||||
val id: String,
|
||||
val serviceTypes: List<String>,
|
||||
val urls: List<String>
|
||||
)
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package io.novafoundation.nova.web3names.data.serviceEndpoint
|
||||
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.web3names.data.endpoints.TransferRecipientsApi
|
||||
import io.novafoundation.nova.web3names.domain.exceptions.Web3NamesException
|
||||
|
||||
class W3NRecepient(
|
||||
val chainIdCaip19: String,
|
||||
val account: String,
|
||||
val description: String?
|
||||
)
|
||||
|
||||
abstract class W3NServiceEndpointHandler(
|
||||
private val endpoint: ServiceEndpoint,
|
||||
private val transferRecipientApi: TransferRecipientsApi
|
||||
) {
|
||||
|
||||
suspend fun getRecipients(web3Name: String, chain: Chain): List<W3NRecepient> {
|
||||
val url = endpoint.urls.firstOrNull() ?: throw Web3NamesException.ValidAccountNotFoundException(web3Name, chain.id)
|
||||
val recipientsContent = transferRecipientApi.getTransferRecipientsRaw(url)
|
||||
|
||||
if (!verifyIntegrity(serviceEndpointId = endpoint.id, serviceEndpointContent = recipientsContent)) {
|
||||
throw Web3NamesException.IntegrityCheckFailed(web3Name)
|
||||
}
|
||||
|
||||
return parseRecipients(recipientsContent)
|
||||
}
|
||||
|
||||
abstract fun verifyIntegrity(serviceEndpointId: String, serviceEndpointContent: String): Boolean
|
||||
|
||||
protected abstract fun parseRecipients(content: String): List<W3NRecepient>
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package io.novafoundation.nova.web3names.data.serviceEndpoint
|
||||
|
||||
import com.google.gson.Gson
|
||||
import io.novafoundation.nova.web3names.data.endpoints.TransferRecipientsApi
|
||||
|
||||
private const val TRANSFER_ASSETS_PROVIDER_DID_SERVICE_TYPE_V1 = "KiltTransferAssetRecipientV1"
|
||||
private const val TRANSFER_ASSETS_PROVIDER_DID_SERVICE_TYPE_V2 = "KiltTransferAssetRecipientV2"
|
||||
|
||||
class W3NServiceEndpointHandlerFactory(
|
||||
private val transferRecipientsApi: TransferRecipientsApi,
|
||||
private val gson: Gson
|
||||
) {
|
||||
|
||||
fun getHandler(serviceEndpoints: List<ServiceEndpoint>): W3NServiceEndpointHandler? {
|
||||
val v2ServiceEndpoint = serviceEndpoints.firstOrNull { TRANSFER_ASSETS_PROVIDER_DID_SERVICE_TYPE_V2 in it.serviceTypes }
|
||||
if (v2ServiceEndpoint != null) {
|
||||
return W3NServiceEndpointHandlerV2(v2ServiceEndpoint, transferRecipientsApi, gson)
|
||||
}
|
||||
|
||||
val v1ServiceEndpoint = serviceEndpoints.firstOrNull { TRANSFER_ASSETS_PROVIDER_DID_SERVICE_TYPE_V1 in it.serviceTypes }
|
||||
if (v1ServiceEndpoint != null) {
|
||||
return W3NServiceEndpointHandlerV1(v1ServiceEndpoint, transferRecipientsApi, gson)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package io.novafoundation.nova.web3names.data.serviceEndpoint
|
||||
|
||||
import com.google.gson.Gson
|
||||
import io.ipfs.multibase.Multibase
|
||||
import io.novafoundation.nova.common.utils.fromJson
|
||||
import io.novafoundation.nova.web3names.data.endpoints.TransferRecipientsApi
|
||||
import io.novafoundation.nova.web3names.data.endpoints.model.TransferRecipientDetailsRemoteV1
|
||||
import io.novasama.substrate_sdk_android.hash.Hasher.blake2b256
|
||||
|
||||
private typealias RecipientsByChainV1 = Map<String, List<TransferRecipientDetailsRemoteV1>>
|
||||
|
||||
class W3NServiceEndpointHandlerV1(
|
||||
endpoint: ServiceEndpoint,
|
||||
transferRecipientApi: TransferRecipientsApi,
|
||||
private val gson: Gson
|
||||
) : W3NServiceEndpointHandler(endpoint, transferRecipientApi) {
|
||||
|
||||
override fun verifyIntegrity(serviceEndpointId: String, serviceEndpointContent: String): Boolean = runCatching {
|
||||
val expectedHash = Multibase.decode(serviceEndpointId)
|
||||
|
||||
val actualHash = serviceEndpointContent.encodeToByteArray().blake2b256()
|
||||
|
||||
expectedHash.contentEquals(actualHash)
|
||||
}.getOrDefault(false)
|
||||
|
||||
override fun parseRecipients(content: String): List<W3NRecepient> {
|
||||
val recipients = gson.fromJson<RecipientsByChainV1>(content)
|
||||
return recipients.flatMap { (chainId, recipients) ->
|
||||
recipients.map { recipient ->
|
||||
W3NRecepient(
|
||||
chainIdCaip19 = chainId,
|
||||
account = recipient.account,
|
||||
description = recipient.description
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package io.novafoundation.nova.web3names.data.serviceEndpoint
|
||||
|
||||
import com.google.gson.Gson
|
||||
import io.ipfs.multibase.Multibase
|
||||
import io.novafoundation.nova.common.utils.fromJson
|
||||
import io.novafoundation.nova.web3names.data.endpoints.TransferRecipientsApi
|
||||
import io.novafoundation.nova.web3names.data.endpoints.model.TransferRecipientDetailsRemoteV2
|
||||
import io.novasama.substrate_sdk_android.hash.Hasher.blake2b256
|
||||
import org.erdtman.jcs.JsonCanonicalizer
|
||||
|
||||
private typealias RecipientsByChainV2 = Map<String, Map<String, TransferRecipientDetailsRemoteV2>>
|
||||
|
||||
class W3NServiceEndpointHandlerV2(
|
||||
endpoint: ServiceEndpoint,
|
||||
transferRecipientApi: TransferRecipientsApi,
|
||||
private val gson: Gson
|
||||
) : W3NServiceEndpointHandler(endpoint, transferRecipientApi) {
|
||||
|
||||
override fun verifyIntegrity(serviceEndpointId: String, serviceEndpointContent: String): Boolean = runCatching {
|
||||
val expectedHash = Multibase.decode(serviceEndpointId)
|
||||
val canonizedJson = JsonCanonicalizer(serviceEndpointContent).encodedString
|
||||
|
||||
val actualHash = canonizedJson.encodeToByteArray().blake2b256()
|
||||
|
||||
expectedHash.contentEquals(actualHash)
|
||||
}.getOrDefault(false)
|
||||
|
||||
override fun parseRecipients(content: String): List<W3NRecepient> {
|
||||
val fromJson = gson.fromJson<RecipientsByChainV2>(content)
|
||||
return fromJson.flatMap { (chainId, recipients) ->
|
||||
recipients.map { recipient ->
|
||||
W3NRecepient(
|
||||
chainIdCaip19 = chainId,
|
||||
account = recipient.key,
|
||||
description = recipient.value.description
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package io.novafoundation.nova.web3names.di
|
||||
|
||||
import io.novafoundation.nova.web3names.domain.networking.Web3NamesInteractor
|
||||
|
||||
interface Web3NamesApi {
|
||||
|
||||
val web3NamesInteractor: Web3NamesInteractor
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.novafoundation.nova.web3names.di
|
||||
|
||||
import com.google.gson.Gson
|
||||
import io.novafoundation.nova.caip.caip19.Caip19MatcherFactory
|
||||
import io.novafoundation.nova.caip.caip19.Caip19Parser
|
||||
import io.novafoundation.nova.common.data.network.NetworkApiCreator
|
||||
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import javax.inject.Named
|
||||
|
||||
interface Web3NamesDependencies {
|
||||
|
||||
val networkApiCreator: NetworkApiCreator
|
||||
|
||||
val gson: Gson
|
||||
|
||||
val caip19Parser: Caip19Parser
|
||||
|
||||
val caip19MatcherFactory: Caip19MatcherFactory
|
||||
|
||||
@Named(REMOTE_STORAGE_SOURCE)
|
||||
fun remoteStorageSource(): StorageDataSource
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package io.novafoundation.nova.web3names.di
|
||||
|
||||
import dagger.Component
|
||||
import io.novafoundation.nova.caip.di.CaipApi
|
||||
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.runtime.di.RuntimeApi
|
||||
|
||||
@Component(
|
||||
modules = [
|
||||
Web3NamesModule::class
|
||||
],
|
||||
dependencies = [
|
||||
Web3NamesDependencies::class
|
||||
]
|
||||
)
|
||||
@FeatureScope
|
||||
abstract class Web3NamesFeatureComponent : Web3NamesApi {
|
||||
|
||||
@Component(
|
||||
dependencies = [
|
||||
CommonApi::class,
|
||||
DbApi::class,
|
||||
RuntimeApi::class,
|
||||
CaipApi::class
|
||||
]
|
||||
)
|
||||
interface Web3NamesDependenciesComponent : Web3NamesDependencies
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package io.novafoundation.nova.web3names.di
|
||||
|
||||
import io.novafoundation.nova.caip.di.CaipApi
|
||||
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.runtime.di.RuntimeApi
|
||||
import javax.inject.Inject
|
||||
|
||||
@ApplicationScope
|
||||
class Web3NamesHolder @Inject constructor(
|
||||
featureContainer: FeatureContainer
|
||||
) : FeatureApiHolder(featureContainer) {
|
||||
|
||||
override fun initializeDependencies(): Any {
|
||||
val dbDependencies = DaggerWeb3NamesFeatureComponent_Web3NamesDependenciesComponent.builder()
|
||||
.commonApi(commonApi())
|
||||
.dbApi(getFeature(DbApi::class.java))
|
||||
.runtimeApi(getFeature(RuntimeApi::class.java))
|
||||
.caipApi(getFeature(CaipApi::class.java))
|
||||
.build()
|
||||
|
||||
return DaggerWeb3NamesFeatureComponent.builder()
|
||||
.web3NamesDependencies(dbDependencies)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package io.novafoundation.nova.web3names.di
|
||||
|
||||
import com.google.gson.Gson
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.caip.caip19.Caip19MatcherFactory
|
||||
import io.novafoundation.nova.caip.caip19.Caip19Parser
|
||||
import io.novafoundation.nova.common.data.network.NetworkApiCreator
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
|
||||
import io.novafoundation.nova.runtime.ext.Geneses
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
import io.novafoundation.nova.web3names.data.endpoints.TransferRecipientsApi
|
||||
import io.novafoundation.nova.web3names.data.provider.RealWeb3NamesServiceChainIdProvider
|
||||
import io.novafoundation.nova.web3names.data.provider.Web3NamesServiceChainIdProvider
|
||||
import io.novafoundation.nova.web3names.data.repository.RealWeb3NamesRepository
|
||||
import io.novafoundation.nova.web3names.data.repository.Web3NamesRepository
|
||||
import io.novafoundation.nova.web3names.data.serviceEndpoint.W3NServiceEndpointHandlerFactory
|
||||
import io.novafoundation.nova.web3names.domain.networking.RealWeb3NamesInteractor
|
||||
import io.novafoundation.nova.web3names.domain.networking.Web3NamesInteractor
|
||||
import javax.inject.Named
|
||||
|
||||
@Module
|
||||
class Web3NamesModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideWeb3NamesServiceChainIdProvider(): Web3NamesServiceChainIdProvider {
|
||||
return RealWeb3NamesServiceChainIdProvider(Chain.Geneses.KILT)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTransferRecipientApi(
|
||||
networkApiCreator: NetworkApiCreator
|
||||
): TransferRecipientsApi {
|
||||
return networkApiCreator.create(TransferRecipientsApi::class.java)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideW3NServiceEndpointHandlerFactory(
|
||||
transferRecipientApi: TransferRecipientsApi,
|
||||
gson: Gson
|
||||
) = W3NServiceEndpointHandlerFactory(
|
||||
transferRecipientApi,
|
||||
gson
|
||||
)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideWeb3NamesRepository(
|
||||
@Named(REMOTE_STORAGE_SOURCE) storageDataSource: StorageDataSource,
|
||||
web3NamesServiceChainIdProvider: Web3NamesServiceChainIdProvider,
|
||||
caip19MatcherFactory: Caip19MatcherFactory,
|
||||
caip19Parser: Caip19Parser,
|
||||
w3NServiceEndpointHandlerFactory: W3NServiceEndpointHandlerFactory
|
||||
): Web3NamesRepository {
|
||||
return RealWeb3NamesRepository(
|
||||
storageDataSource,
|
||||
web3NamesServiceChainIdProvider,
|
||||
caip19MatcherFactory,
|
||||
caip19Parser,
|
||||
w3NServiceEndpointHandlerFactory
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideWeb3NamesInteractor(
|
||||
web3NamesRepository: Web3NamesRepository
|
||||
): Web3NamesInteractor {
|
||||
return RealWeb3NamesInteractor(
|
||||
web3NamesRepository
|
||||
)
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package io.novafoundation.nova.web3names.domain.exceptions
|
||||
|
||||
class ParseWeb3NameException : Exception()
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.novafoundation.nova.web3names.domain.exceptions
|
||||
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novasama.substrate_sdk_android.extensions.requirePrefix
|
||||
|
||||
sealed class Web3NamesException(identifier: String) : Exception() {
|
||||
|
||||
val web3Name: String = identifier.requirePrefix("w3n:")
|
||||
|
||||
class ChainProviderNotFoundException(identifier: String) : Web3NamesException(identifier)
|
||||
|
||||
class IntegrityCheckFailed(identifier: String) : Web3NamesException(identifier)
|
||||
|
||||
class ValidAccountNotFoundException(identifier: String, val chainName: String) : Web3NamesException(identifier)
|
||||
|
||||
class UnknownException(web3NameInput: String, val chainName: String) : Web3NamesException(web3NameInput)
|
||||
|
||||
class UnsupportedAsset(identifier: String, val chainAsset: Chain.Asset) : Web3NamesException(identifier)
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package io.novafoundation.nova.web3names.domain.models
|
||||
|
||||
class Web3NameAccount(
|
||||
val address: String,
|
||||
val description: String?,
|
||||
val isValid: Boolean,
|
||||
)
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package io.novafoundation.nova.web3names.domain.networking
|
||||
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novafoundation.nova.web3names.data.repository.Web3NamesRepository
|
||||
import io.novafoundation.nova.web3names.domain.exceptions.ParseWeb3NameException
|
||||
import io.novafoundation.nova.web3names.domain.models.Web3NameAccount
|
||||
|
||||
interface Web3NamesInteractor {
|
||||
|
||||
fun isValidWeb3Name(raw: String): Boolean
|
||||
|
||||
suspend fun queryAccountsByWeb3Name(w3nIdentifier: String, chain: Chain, chainAsset: Chain.Asset): List<Web3NameAccount>
|
||||
|
||||
fun removePrefix(w3nIdentifier: String): String
|
||||
}
|
||||
|
||||
class RealWeb3NamesInteractor(
|
||||
private val web3NamesRepository: Web3NamesRepository
|
||||
) : Web3NamesInteractor {
|
||||
|
||||
override fun isValidWeb3Name(raw: String): Boolean {
|
||||
return parseToWeb3Name(raw).isSuccess
|
||||
}
|
||||
|
||||
override suspend fun queryAccountsByWeb3Name(w3nIdentifier: String, chain: Chain, chainAsset: Chain.Asset): List<Web3NameAccount> {
|
||||
require(isValidWeb3Name(w3nIdentifier))
|
||||
|
||||
val web3NameNoPrefix = parseToWeb3Name(w3nIdentifier).getOrThrow()
|
||||
|
||||
return web3NamesRepository.queryWeb3NameAccount(web3NameNoPrefix, chain, chainAsset)
|
||||
}
|
||||
|
||||
override fun removePrefix(w3nIdentifier: String): String {
|
||||
require(isValidWeb3Name(w3nIdentifier))
|
||||
|
||||
return parseToWeb3Name(w3nIdentifier).getOrThrow()
|
||||
}
|
||||
|
||||
private fun parseToWeb3Name(raw: String): Result<String> {
|
||||
return runCatching {
|
||||
val (web3NameKey, web3NameValue) = raw.split(":", limit = 2)
|
||||
|
||||
if (web3NameKey.trim() == "w3n") {
|
||||
web3NameValue.trim()
|
||||
} else {
|
||||
throw ParseWeb3NameException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user