Updated on 2026-08-14

This commit is contained in:
Tangem 2024-05-29 17:33:28 +08:00
parent cf7d5814d6
commit 10ba20b045
30 changed files with 358 additions and 264 deletions

View file

@ -4,7 +4,7 @@ import com.tangem.TangemSdkLogger
import com.tangem.blockchainsdk.BlockchainSDKFactory
import com.tangem.core.analytics.filter.OneTimeEventFilter
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.datasource.asset.reader.AssetReader
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.datasource.local.token.UserTokensStore
@ -47,7 +47,7 @@ interface ApplicationEntryPoint {
fun getAppStateHolder(): AppStateHolder
fun getAssetReader(): AssetReader
fun getAssetLoader(): AssetLoader
fun getFeatureTogglesManager(): FeatureTogglesManager

View file

@ -18,7 +18,7 @@ import com.tangem.core.analytics.filter.OneTimeEventFilter
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
import com.tangem.datasource.asset.reader.AssetReader
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.config.FeaturesLocalLoader
import com.tangem.datasource.config.models.Config
@ -92,8 +92,8 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
private val configManager: ConfigManager
get() = entryPoint.getConfigManager()
private val assetReader: AssetReader
get() = entryPoint.getAssetReader()
private val assetLoader: AssetLoader
get() = entryPoint.getAssetLoader()
private val featureTogglesManager: FeatureTogglesManager
get() = entryPoint.getFeatureTogglesManager()
@ -217,10 +217,12 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
// [REDACTED_JIRA]
runBlocking {
featureTogglesManager.init()
initConfigManager(
loader = FeaturesLocalLoader(assetLoader, BuildConfig.ENVIRONMENT),
onComplete = ::initWithConfigDependency,
)
}
val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT)
initConfigManager(configLoader, ::initWithConfigDependency)
initWarningMessagesManager()
loadNativeLibraries()
@ -290,7 +292,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
System.loadLibrary("TrustWalletCore")
}
private fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) {
private suspend fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) {
configManager.load(loader) { config ->
store.dispatch(GlobalAction.SetConfigManager(configManager))
onComplete(config)

View file

@ -1,9 +1,7 @@
package com.tangem.tap.di.domain
import com.squareup.moshi.Moshi
import com.tangem.blockchainsdk.BlockchainSDKFactory
import com.tangem.datasource.asset.reader.AssetReader
import com.tangem.datasource.di.SdkMoshi
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.datasource.local.walletmanager.WalletManagersStore
import com.tangem.domain.walletmanager.DefaultWalletManagersFacade
@ -23,15 +21,13 @@ internal object WalletManagersFacadeModule {
fun provideWalletManagersFacade(
walletManagersStore: WalletManagersStore,
userWalletsStore: UserWalletsStore,
assetReader: AssetReader,
@SdkMoshi moshi: Moshi,
assetLoader: AssetLoader,
blockchainSDKFactory: BlockchainSDKFactory,
): WalletManagersFacade {
return DefaultWalletManagersFacade(
walletManagersStore = walletManagersStore,
userWalletsStore = userWalletsStore,
assetReader = assetReader,
moshi = moshi,
assetLoader = assetLoader,
blockchainSDKFactory = blockchainSDKFactory,
)
}

View file

@ -1,40 +1,36 @@
package com.tangem.tap.domain.twins
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Types
import com.tangem.Message
import com.tangem.blockchain.extensions.Result
import com.tangem.common.CompletionResult
import com.tangem.common.KeyPair
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toHexString
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.asset.reader.AssetReader
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import kotlinx.coroutines.flow.MutableStateFlow
class TwinCardsManager(
card: CardDTO,
assetReader: AssetReader,
) {
class TwinCardsManager(card: CardDTO) {
private val firstCardId: String = card.cardId
private val publicKey: String = card.issuer.publicKey.toHexString()
private var currentCardPublicKey: String? = null
private var secondCardPublicKey: String? = null
private val issuerKeyPair: KeyPair = getIssuerKeys(assetReader, card.issuer.publicKey.toHexString())
private val issuerKeyPairFlow = MutableStateFlow<KeyPair?>(value = null)
suspend fun createFirstWallet(message: Message): CompletionResult<CreateWalletResponse> {
val response = tangemSdkManager.createFirstTwinWallet(
cardId = firstCardId,
initialMessage = message,
)
when (response) {
is CompletionResult.Success -> currentCardPublicKey = response.data.wallet.publicKey.toHexString()
is CompletionResult.Failure -> {}
val response = tangemSdkManager.createFirstTwinWallet(cardId = firstCardId, initialMessage = message)
if (response is CompletionResult.Success) {
currentCardPublicKey = response.data.wallet.publicKey.toHexString()
}
return response
}
@ -46,58 +42,51 @@ class TwinCardsManager(
val response = tangemSdkManager.createSecondTwinWallet(
firstPublicKey = currentCardPublicKey!!,
firstCardId = firstCardId,
issuerKeys = issuerKeyPair,
issuerKeys = getIssuerKeys(),
preparingMessage = preparingMessage,
creatingWalletMessage = creatingWalletMessage,
initialMessage = initialMessage,
)
when (response) {
is CompletionResult.Success -> {
secondCardPublicKey = response.data.wallet.publicKey.toHexString()
}
is CompletionResult.Failure -> {}
if (response is CompletionResult.Success) {
secondCardPublicKey = response.data.wallet.publicKey.toHexString()
}
return response
}
suspend fun complete(message: Message): Result<ScanResponse> {
val response = tangemSdkManager.finalizeTwin(
secondCardPublicKey = secondCardPublicKey!!.hexToBytes(),
issuerKeyPair = issuerKeyPair,
issuerKeyPair = getIssuerKeys(),
cardId = firstCardId,
initialMessage = message,
)
return when (response) {
is CompletionResult.Success -> Result.Success(response.data)
is CompletionResult.Failure -> Result.fromTangemSdkError(response.error)
}
}
companion object {
private fun getIssuerKeys(reader: AssetReader, publicKey: String): KeyPair {
val issuer = getIssuers(reader).first { it.publicKey == publicKey }
return KeyPair(
publicKey = issuer.publicKey.hexToBytes(),
privateKey = issuer.privateKey.hexToBytes(),
)
}
private suspend fun getIssuerKeys(): KeyPair {
issuerKeyPairFlow.value?.let { return it }
private fun getAdapter(): JsonAdapter<List<Issuer>> {
return MoshiConverter.sdkMoshi.adapter(
Types.newParameterizedType(List::class.java, Issuer::class.java),
)
}
val assetLoader = store.inject(DaggerGraphState::assetLoader)
val issuer = assetLoader.loadList<Issuer>(fileName = ISSUERS_FILE_NAME)
.first { it.publicKey == publicKey }
@Deprecated(message = "Use AssetReader instead")
private fun getIssuers(reader: AssetReader): List<Issuer> {
val file = reader.readJson(fileName = "tangem-app-config/issuers")
return getAdapter().fromJson(file)!!
return KeyPair(
publicKey = issuer.publicKey.hexToBytes(),
privateKey = issuer.privateKey.hexToBytes(),
).also {
issuerKeyPairFlow.value = it
}
}
private companion object {
const val ISSUERS_FILE_NAME = "tangem-app-config/issuers"
}
}
private class Issuer(
val privateKey: String,
val publicKey: String,
)
private class Issuer(val privateKey: String, val publicKey: String)

View file

@ -3,7 +3,6 @@ package com.tangem.tap.features.onboarding.products.twins.redux
import com.tangem.Message
import com.tangem.blockchain.common.WalletManager
import com.tangem.common.extensions.VoidCallback
import com.tangem.datasource.asset.reader.AssetReader
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.twins.TwinCardsManager
@ -27,7 +26,7 @@ sealed class TwinCardsAction : Action {
}
sealed class Wallet : TwinCardsAction() {
data class LaunchFirstStep(val initialMessage: Message, val reader: AssetReader) : TwinCardsAction()
data class LaunchFirstStep(val initialMessage: Message) : TwinCardsAction()
data class LaunchSecondStep(
val initialMessage: Message,
val preparingMessage: Message,

View file

@ -165,10 +165,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
}
}
is TwinCardsAction.Wallet.LaunchFirstStep -> {
val manager = TwinCardsManager(
card = getScanResponse().card,
assetReader = action.reader,
)
val manager = TwinCardsManager(card = getScanResponse().card)
store.dispatch(TwinCardsAction.CardsManager.Set(manager))
scope.launch {

View file

@ -15,7 +15,6 @@ import com.tangem.common.extensions.VoidCallback
import com.tangem.core.analytics.Analytics
import com.tangem.core.navigation.ShareElement
import com.tangem.core.ui.extensions.setStatusBarColor
import com.tangem.datasource.asset.reader.AssetReader
import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.Artwork
@ -35,15 +34,11 @@ import com.tangem.tap.store
import com.tangem.wallet.R
import com.tangem.wallet.databinding.LayoutOnboardingContainerTopBinding
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@Suppress("LargeClass")
@AndroidEntryPoint
internal class OnboardingTwinsFragment : BaseOnboardingFragment<TwinCardsState>() {
@Inject
lateinit var assetReader: AssetReader
private val mainBinding by lazy { binding.vMain }
private var previousStep: TwinCardsStep = TwinCardsStep.None
@ -260,7 +255,6 @@ internal class OnboardingTwinsFragment : BaseOnboardingFragment<TwinCardsState>(
store.dispatch(
TwinCardsAction.Wallet.LaunchFirstStep(
initialMessage = Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)),
reader = assetReader,
),
)
}

View file

@ -4,6 +4,7 @@ import com.tangem.TangemSdkLogger
import com.tangem.blockchainsdk.BlockchainSDKFactory
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.navigation.email.EmailSender
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
@ -77,6 +78,7 @@ data class DaggerGraphState(
val blockchainSDKFactory: BlockchainSDKFactory? = null,
val emailSender: EmailSender? = null,
val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase? = null,
val assetLoader: AssetLoader? = null,
val detailsFeatureToggles: DetailsFeatureToggles? = null,
val detailsEntryPoint: DetailsEntryPoint? = null,
) : StateType