Updated on 2026-08-14
This commit is contained in:
parent
eb07388729
commit
3f6bcd3a0e
23 changed files with 226 additions and 101 deletions
|
|
@ -227,8 +227,8 @@ dependencies {
|
|||
implementation(projects.features.usedesk.impl)
|
||||
implementation(projects.features.hotWallet.api)
|
||||
implementation(projects.features.hotWallet.impl)
|
||||
implementation(projects.features.kyc.api)
|
||||
//TODO disable for release because of the permissions
|
||||
// implementation(projects.features.kyc.api)
|
||||
// implementation(projects.features.kyc.impl)
|
||||
implementation(projects.features.welcome.api)
|
||||
implementation(projects.features.welcome.impl)
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
|||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.visa.model.VisaActivationInput
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
import com.tangem.operations.ScanTask
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
|
|
@ -501,7 +499,12 @@ internal class DefaultTangemSdkManager(
|
|||
): CompletionResult<VisaSignedDataByCustomerWallet> {
|
||||
return runTaskAsyncReturnOnMain(
|
||||
runnable = VisaCustomerWalletApproveTask(
|
||||
visaDataForApprove = visaDataForApprove,
|
||||
VisaCustomerWalletApproveTask.Input(
|
||||
cardId = visaDataForApprove.customerWalletCardId,
|
||||
targetAddress = visaDataForApprove.targetAddress,
|
||||
hashToSign = visaDataForApprove.dataToSign.hashToSign,
|
||||
sign = visaDataForApprove.dataToSign::sign,
|
||||
),
|
||||
),
|
||||
cardId = visaDataForApprove.customerWalletCardId,
|
||||
initialMessage = Message(resources.getStringSafe(R.string.initial_message_tap_header)),
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
|||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.visa.model.VisaActivationInput
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.domain.tasks.visa
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils.toKeccak
|
||||
import com.tangem.blockchain.common.UnmarshalHelper
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.Card
|
||||
|
|
@ -10,7 +11,6 @@ import com.tangem.common.core.CardSession
|
|||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toDecompressedPublicKey
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.core.error.ext.tangemError
|
||||
|
|
@ -22,15 +22,13 @@ import com.tangem.domain.card.common.visa.VisaWalletPublicKeyUtility
|
|||
import com.tangem.domain.card.common.visa.VisaWalletPublicKeyUtility.findKeyWithoutDerivation
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.visa.error.VisaActivationError
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
||||
import com.tangem.domain.visa.model.sign
|
||||
import com.tangem.operations.ScanTask
|
||||
import com.tangem.operations.derivation.DeriveWalletPublicKeyTask
|
||||
import com.tangem.operations.sign.SignHashCommand
|
||||
|
||||
class VisaCustomerWalletApproveTask(
|
||||
private val visaDataForApprove: VisaDataForApprove,
|
||||
private val visaDataForApprove: Input,
|
||||
) : CardSessionRunnable<VisaSignedDataByCustomerWallet> {
|
||||
|
||||
override fun run(session: CardSession, callback: CompletionCallback<VisaSignedDataByCustomerWallet>) {
|
||||
|
|
@ -44,7 +42,7 @@ class VisaCustomerWalletApproveTask(
|
|||
return
|
||||
}
|
||||
|
||||
if (visaDataForApprove.customerWalletCardId != null && card.cardId != visaDataForApprove.customerWalletCardId) {
|
||||
if (visaDataForApprove.cardId != null && card.cardId != visaDataForApprove.cardId) {
|
||||
callback(CompletionResult.Failure(VisaActivationError.CardIdNotMatched.tangemError))
|
||||
return
|
||||
}
|
||||
|
|
@ -153,6 +151,12 @@ class VisaCustomerWalletApproveTask(
|
|||
)
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_TASK_KEY] - Get this public function from Blockchain SDK
|
||||
private fun hashPersonalMessage(message: ByteArray): ByteArray {
|
||||
val prefix = "\u0019Ethereum Signed Message:\n${message.size}".toByteArray()
|
||||
return (prefix + message).toKeccak()
|
||||
}
|
||||
|
||||
private fun signApproveData(
|
||||
targetWalletPublicKey: ByteArray,
|
||||
derivationPath: DerivationPath?,
|
||||
|
|
@ -160,10 +164,11 @@ class VisaCustomerWalletApproveTask(
|
|||
session: CardSession,
|
||||
callback: CompletionCallback<VisaSignedDataByCustomerWallet>,
|
||||
) {
|
||||
val hashToSign = visaDataForApprove.dataToSign.hashToSign.hexToBytes()
|
||||
val content = "Tangem Pay wants to sign in with your account. Nonce: ${visaDataForApprove.hashToSign}"
|
||||
val hash = hashPersonalMessage(content.toByteArray(Charsets.UTF_8))
|
||||
|
||||
val signTask = SignHashCommand(
|
||||
hash = hashToSign,
|
||||
hash = hash,
|
||||
walletPublicKey = targetWalletPublicKey,
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
|
|
@ -173,7 +178,7 @@ class VisaCustomerWalletApproveTask(
|
|||
is CompletionResult.Success -> {
|
||||
val rsvSignature = UnmarshalHelper.unmarshalSignatureExtended(
|
||||
signature = result.data.signature,
|
||||
hash = hashToSign,
|
||||
hash = hash,
|
||||
publicKey = extendedPublicKey?.publicKey?.toDecompressedPublicKey()
|
||||
?: targetWalletPublicKey.toDecompressedPublicKey(),
|
||||
).asRSVLegacyEVM().toHexString().lowercase()
|
||||
|
|
@ -181,10 +186,7 @@ class VisaCustomerWalletApproveTask(
|
|||
scanCard(
|
||||
session = session,
|
||||
callback = callback,
|
||||
signedData = visaDataForApprove.dataToSign.sign(
|
||||
signature = rsvSignature,
|
||||
customerWalletAddress = visaDataForApprove.targetAddress,
|
||||
),
|
||||
signedData = visaDataForApprove.sign(rsvSignature, visaDataForApprove.targetAddress),
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
|
|
@ -211,4 +213,11 @@ class VisaCustomerWalletApproveTask(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Input(
|
||||
val cardId: String? = null,
|
||||
val targetAddress: String,
|
||||
val hashToSign: String,
|
||||
val sign: (signature: String, customerWalletAddress: String) -> VisaSignedDataByCustomerWallet,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,19 +1,7 @@
|
|||
package com.tangem.datasource.api.pay
|
||||
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.pay.models.request.ActivationByCardWalletRequest
|
||||
import com.tangem.datasource.api.pay.models.request.ActivationByCustomerWalletRequest
|
||||
import com.tangem.datasource.api.pay.models.request.ActivationStatusRequest
|
||||
import com.tangem.datasource.api.pay.models.request.ExchangeAccessTokenRequest
|
||||
import com.tangem.datasource.api.pay.models.request.GenerateNoneByCardIdRequest
|
||||
import com.tangem.datasource.api.pay.models.request.GenerateNoneByCardWalletRequest
|
||||
import com.tangem.datasource.api.pay.models.request.GetAccessTokenByCardIdRequest
|
||||
import com.tangem.datasource.api.pay.models.request.GetAccessTokenByCardWalletRequest
|
||||
import com.tangem.datasource.api.pay.models.request.GetCardWalletAcceptanceRequest
|
||||
import com.tangem.datasource.api.pay.models.request.GetCustomerWalletAcceptanceRequest
|
||||
import com.tangem.datasource.api.pay.models.request.RefreshTokenByCardIdRequest
|
||||
import com.tangem.datasource.api.pay.models.request.RefreshTokenByCardWalletRequest
|
||||
import com.tangem.datasource.api.pay.models.request.SetPinCodeRequest
|
||||
import com.tangem.datasource.api.pay.models.request.*
|
||||
import com.tangem.datasource.api.pay.models.response.*
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
|
|
@ -33,9 +21,17 @@ interface TangemPayApi {
|
|||
@Body request: GenerateNoneByCardWalletRequest,
|
||||
): ApiResponse<GenerateNonceResponse>
|
||||
|
||||
@POST("v1/auth/challenge")
|
||||
suspend fun generateNonceByCustomerWallet(
|
||||
@Body request: GenerateNonceByCustomerWalletRequest,
|
||||
): ApiResponse<GenerateNonceResponse>
|
||||
|
||||
@POST("v1/auth/token")
|
||||
suspend fun getAccessTokenByCardId(@Body request: GetAccessTokenByCardIdRequest): ApiResponse<JWTResponse>
|
||||
|
||||
@POST("v1/auth/token")
|
||||
suspend fun getTokenByCustomerWallet(@Body request: GetTokenByCustomerWalletRequest): ApiResponse<JWTResponse>
|
||||
|
||||
@POST("v1/auth/token")
|
||||
suspend fun getAccessTokenByCardWallet(@Body request: GetAccessTokenByCardWalletRequest): ApiResponse<JWTResponse>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.datasource.api.pay.models.request
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GenerateNonceByCustomerWalletRequest(
|
||||
@Json(name = "auth_type") val authType: String = "customer_wallet",
|
||||
@Json(name = "customer_wallet_address") val customerWalletAddress: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.datasource.api.pay.models.request
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GetTokenByCustomerWalletRequest(
|
||||
@Json(name = "auth_type") val authType: String = "customer_wallet",
|
||||
@Json(name = "session_id") val sessionId: String,
|
||||
@Json(name = "signature") val signature: String,
|
||||
@Json(name = "message_format") val messageFormat: String,
|
||||
)
|
||||
|
|
@ -50,6 +50,7 @@ dependencies {
|
|||
/** Libs - Tangem */
|
||||
implementation(tangemDeps.blockchain)
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(projects.libs.tangemSdkApi)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.core)
|
||||
|
|
|
|||
|
|
@ -2,39 +2,52 @@ package com.tangem.data.pay
|
|||
|
||||
import arrow.core.Either
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.common.map
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.models.response.VisaErrorResponseJsonAdapter
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.KycStartInfo
|
||||
import com.tangem.domain.pay.repository.KycRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaDataToSignByCustomerWallet
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
class DefaultKycRepository @AssistedInject constructor(
|
||||
@Assisted userWalletId: UserWalletId,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
private val visaAuthRepository: VisaAuthRepository,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
) : KycRepository {
|
||||
|
||||
private val visaErrorAdapter = VisaErrorResponseJsonAdapter(moshi)
|
||||
|
||||
override suspend fun getKycStartInfo(): Either<UniversalError, KycStartInfo> = withContext(dispatcherProvider.io) {
|
||||
val authTokenForSpecificWallet = "get from userWalletId"
|
||||
|
||||
request {
|
||||
tangemPayApi.getKycAccess(
|
||||
authHeader = authTokenForSpecificWallet,
|
||||
).getOrThrow().result
|
||||
override suspend fun getKycStartInfo(address: String, cardId: String): Either<UniversalError, KycStartInfo> {
|
||||
var authHeader = ""
|
||||
visaAuthRepository.getCustomerWalletAuthChallenge(address).getOrNull()?.let { result ->
|
||||
tangemSdkManager.visaCustomerWalletApprove(
|
||||
VisaDataForApprove(
|
||||
customerWalletCardId = cardId,
|
||||
targetAddress = address,
|
||||
dataToSign = VisaDataToSignByCustomerWallet(hashToSign = result.challenge),
|
||||
),
|
||||
).map { signResult ->
|
||||
visaAuthRepository.getTokenWithCustomerWallet(
|
||||
sessionId = result.session.sessionId,
|
||||
signature = signResult.signature,
|
||||
nonce = signResult.dataToSign.hashToSign,
|
||||
).getOrNull()?.let { authHeader = it }
|
||||
}
|
||||
}
|
||||
return request {
|
||||
authHeader.ifEmpty { error("Cannot get auth header for KYC") }
|
||||
tangemPayApi.getKycAccess(authHeader = authHeader).getOrThrow().result
|
||||
}.map {
|
||||
KycStartInfo(
|
||||
token = it.token,
|
||||
|
|
@ -65,6 +78,6 @@ class DefaultKycRepository @AssistedInject constructor(
|
|||
|
||||
@AssistedFactory
|
||||
interface Factory : KycRepository.Factory {
|
||||
override fun create(userWalletId: UserWalletId): DefaultKycRepository
|
||||
override fun create(): DefaultKycRepository
|
||||
}
|
||||
}
|
||||
|
|
@ -131,16 +131,18 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor(
|
|||
val authTokens =
|
||||
checkNotNull(visaAuthTokenStorage.get(visaCardId.cardId)) { "Visa auth tokens are not stored" }
|
||||
|
||||
visaApi.activateByCustomerWallet(
|
||||
authHeader = authTokens.getAuthHeader(),
|
||||
body = ActivationByCustomerWalletRequest(
|
||||
orderId = signedData.dataToSign.request.orderId,
|
||||
customerWallet = ActivationByCustomerWalletRequest.CustomerWallet(
|
||||
deployAcceptanceSignature = signedData.signature,
|
||||
customerWalletAddress = signedData.customerWalletAddress,
|
||||
signedData.dataToSign.request?.orderId?.let { orderId ->
|
||||
visaApi.activateByCustomerWallet(
|
||||
authHeader = authTokens.getAuthHeader(),
|
||||
body = ActivationByCustomerWalletRequest(
|
||||
orderId = orderId,
|
||||
customerWallet = ActivationByCustomerWalletRequest.CustomerWallet(
|
||||
deployAcceptanceSignature = signedData.signature,
|
||||
customerWalletAddress = signedData.customerWalletAddress,
|
||||
),
|
||||
),
|
||||
),
|
||||
).getOrThrow()
|
||||
).getOrThrow()
|
||||
} ?: error("Order Id cannot be null")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,39 @@ internal class DefaultVisaAuthRepository @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getCustomerWalletAuthChallenge(
|
||||
customerWalletAddress: String,
|
||||
): Either<VisaApiError, VisaAuthChallenge.Wallet> = withContext(dispatchers.io) {
|
||||
request {
|
||||
visaAuthApi.generateNonceByCustomerWallet(
|
||||
GenerateNonceByCustomerWalletRequest(customerWalletAddress = customerWalletAddress),
|
||||
).getOrThrow()
|
||||
}.map { response ->
|
||||
VisaAuthChallenge.Wallet(
|
||||
challenge = response.result.nonce,
|
||||
session = VisaAuthSession(response.result.sessionId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getTokenWithCustomerWallet(
|
||||
sessionId: String,
|
||||
signature: String,
|
||||
nonce: String,
|
||||
): Either<VisaApiError, String> = withContext(dispatchers.io) {
|
||||
request {
|
||||
visaAuthApi.getTokenByCustomerWallet(
|
||||
GetTokenByCustomerWalletRequest(
|
||||
sessionId = sessionId,
|
||||
signature = signature,
|
||||
messageFormat = "Tangem Pay wants to sign in with your account. Nonce: $nonce",
|
||||
),
|
||||
).getOrThrow()
|
||||
}.map { response ->
|
||||
"Bearer ${response.result.accessToken}"
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAccessTokens(
|
||||
signedChallenge: VisaAuthSignedChallenge,
|
||||
): Either<VisaApiError, VisaAuthTokens> = withContext(dispatchers.io) {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import kotlinx.serialization.Serializable
|
|||
|
||||
@Serializable
|
||||
data class VisaDataToSignByCustomerWallet(
|
||||
val request: VisaCustomerWalletDataToSignRequest,
|
||||
val hashToSign: String,
|
||||
val request: VisaCustomerWalletDataToSignRequest? = null,
|
||||
)
|
||||
|
||||
fun VisaDataToSignByCustomerWallet.sign(signature: String, customerWalletAddress: String) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.visa.model
|
||||
|
||||
data class VisaSignedChallengeByCustomerWallet(
|
||||
val challenge: String,
|
||||
val signature: String,
|
||||
)
|
||||
|
|
@ -3,13 +3,12 @@ package com.tangem.domain.pay.repository
|
|||
import arrow.core.Either
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.domain.pay.KycStartInfo
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
interface KycRepository {
|
||||
|
||||
suspend fun getKycStartInfo(): Either<UniversalError, KycStartInfo>
|
||||
suspend fun getKycStartInfo(address: String, cardId: String): Either<UniversalError, KycStartInfo>
|
||||
|
||||
interface Factory {
|
||||
fun create(userWalletId: UserWalletId): KycRepository
|
||||
fun create(): KycRepository
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,16 @@ interface VisaAuthRepository {
|
|||
cardWalletAddress: String,
|
||||
): Either<VisaApiError, VisaAuthChallenge.Wallet>
|
||||
|
||||
suspend fun getCustomerWalletAuthChallenge(
|
||||
customerWalletAddress: String,
|
||||
): Either<VisaApiError, VisaAuthChallenge.Wallet>
|
||||
|
||||
suspend fun getTokenWithCustomerWallet(
|
||||
sessionId: String,
|
||||
signature: String,
|
||||
nonce: String,
|
||||
): Either<VisaApiError, String>
|
||||
|
||||
suspend fun getAccessTokens(signedChallenge: VisaAuthSignedChallenge): Either<VisaApiError, VisaAuthTokens>
|
||||
|
||||
suspend fun refreshAccessTokens(refreshToken: VisaAuthTokens.RefreshToken): Either<VisaApiError, VisaAuthTokens>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,14 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
|
||||
interface KycComponent {
|
||||
|
||||
fun launch()
|
||||
fun launch(params: Params)
|
||||
|
||||
interface Factory {
|
||||
fun create(appComponentContext: AppComponentContext): KycComponent
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val targetAddress: String,
|
||||
val cardId: String,
|
||||
)
|
||||
}
|
||||
|
|
@ -13,8 +13,7 @@ android {
|
|||
|
||||
dependencies {
|
||||
/** Api */
|
||||
//TODO disable for release because of the permissions
|
||||
// implementation(projects.features.kyc.api)
|
||||
implementation(projects.features.kyc.api)
|
||||
|
||||
/** Domain */
|
||||
implementation(projects.domain.visa)
|
||||
|
|
|
|||
|
|
@ -1,57 +1,41 @@
|
|||
package com.tangem.features.kyc
|
||||
|
||||
import com.sumsub.sns.core.SNSMobileSDK
|
||||
import com.sumsub.sns.core.data.listener.SNSCompleteHandler
|
||||
import com.sumsub.sns.core.data.listener.TokenExpirationHandler
|
||||
import com.sumsub.sns.core.data.model.SNSCompletionResult
|
||||
import com.sumsub.sns.core.data.model.SNSInitConfig
|
||||
import com.sumsub.sns.core.data.model.SNSSDKState
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.domain.pay.repository.KycRepository
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.features.kyc.theme.TangemSNSTheme
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.features.kyc.theme.TangemSNSIconHandler
|
||||
import com.tangem.features.kyc.theme.TangemSNSTheme
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.Locale
|
||||
|
||||
class DefaultKycComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
private val kycRepositoryFactory: KycRepository.Factory,
|
||||
) : KycComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val kycRepository = kycRepositoryFactory.create(UserWalletId("0FFFFF"))
|
||||
private val model: DefaultKycModel = getOrCreateModel()
|
||||
|
||||
override fun launch() {
|
||||
override fun launch(params: KycComponent.Params) {
|
||||
componentScope.launch {
|
||||
val startInfo = kycRepository.getKycStartInfo().getOrNull() ?: return@launch
|
||||
|
||||
val tokenExpirationHandler = object : TokenExpirationHandler {
|
||||
override fun onTokenExpired(): String? {
|
||||
val newToken = runBlocking { kycRepository.getKycStartInfo().getOrNull()?.token }
|
||||
return newToken
|
||||
model.uiState.collect {
|
||||
it?.let { startInfo ->
|
||||
val tokenExpirationHandler = object : TokenExpirationHandler {
|
||||
override fun onTokenExpired() = ""
|
||||
}
|
||||
val snsSdk = SNSMobileSDK.Builder(activity)
|
||||
.withAccessToken(accessToken = startInfo.token, onTokenExpiration = tokenExpirationHandler)
|
||||
.withTheme(TangemSNSTheme.theme(activity))
|
||||
.withIconHandler(TangemSNSIconHandler())
|
||||
.withLocale(Locale("en"))
|
||||
.build()
|
||||
snsSdk.launch()
|
||||
}
|
||||
}
|
||||
|
||||
val snsSdk = SNSMobileSDK.Builder(activity)
|
||||
.withAccessToken(accessToken = startInfo.token, onTokenExpiration = tokenExpirationHandler)
|
||||
.withConf(SNSInitConfig(strings = mapOf()))
|
||||
.withTheme(TangemSNSTheme.theme(activity))
|
||||
.withIconHandler(TangemSNSIconHandler())
|
||||
.withLocale(Locale("en"))
|
||||
.withCompleteHandler(
|
||||
object : SNSCompleteHandler {
|
||||
override fun onComplete(result: SNSCompletionResult, state: SNSSDKState) {
|
||||
}
|
||||
},
|
||||
)
|
||||
.build()
|
||||
|
||||
snsSdk.launch()
|
||||
}
|
||||
model.getKycToken(params)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.features.kyc
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.domain.pay.KycStartInfo
|
||||
import com.tangem.domain.pay.repository.KycRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
class DefaultKycModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
kycRepositoryFactory: KycRepository.Factory,
|
||||
) : Model() {
|
||||
|
||||
private val kycRepository = kycRepositoryFactory.create()
|
||||
|
||||
private val _uiState: MutableStateFlow<KycStartInfo?> = MutableStateFlow(null)
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
||||
fun getKycToken(params: KycComponent.Params) {
|
||||
modelScope.launch {
|
||||
kycRepository.getKycStartInfo(address = params.targetAddress, cardId = params.cardId).getOrNull()
|
||||
?.let { _uiState.emit(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
package com.tangem.features.kyc.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.kyc.DefaultKycComponent
|
||||
import com.tangem.features.kyc.DefaultKycModel
|
||||
import com.tangem.features.kyc.KycComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
|
|
@ -13,4 +18,13 @@ internal interface FeatureModule {
|
|||
|
||||
@Binds
|
||||
fun bindComponentFactory(impl: DefaultKycComponent.Factory): KycComponent.Factory
|
||||
}
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface ModelModule {
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(DefaultKycModel::class)
|
||||
fun provideModel(model: DefaultKycModel): Model
|
||||
}
|
||||
|
|
@ -113,6 +113,7 @@ dependencies {
|
|||
implementation(projects.features.biometry.api)
|
||||
implementation(projects.features.nft.api)
|
||||
implementation(projects.features.sendV2.api)
|
||||
implementation(projects.features.kyc.api)
|
||||
|
||||
/** Common modules */
|
||||
implementation(projects.common)
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@ import com.tangem.crypto.hdWallet.DerivationPath
|
|||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.visa.model.VisaActivationInput
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaSignedDataByCustomerWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
|
|
|
|||
|
|
@ -260,8 +260,8 @@ include(":features:walletconnect:impl")
|
|||
include(":features:hot-wallet:api")
|
||||
include(":features:hot-wallet:impl")
|
||||
|
||||
include(":features:kyc:api")
|
||||
//TODO disable for release because of the permissions
|
||||
// include(":features:kyc:api")
|
||||
// include(":features:kyc:impl")
|
||||
|
||||
include(":features:create-wallet-selection:api")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue