Updated on 2026-08-14
This commit is contained in:
parent
ee722c5f46
commit
67a245a19c
18 changed files with 296 additions and 60 deletions
|
|
@ -111,6 +111,7 @@ dependencies {
|
|||
implementation(project(":common"))
|
||||
implementation(project(":core:ui"))
|
||||
implementation(project(":libs:crypto"))
|
||||
implementation(project(":libs:auth"))
|
||||
|
||||
/** Features */
|
||||
implementation(project(":features:referral:presentation"))
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.tangem.tap.common.shop.GooglePayService.Companion.LOAD_PAYMENT_DATA_R
|
|||
import com.tangem.tap.common.shop.googlepay.GooglePayUtil.createPaymentsClient
|
||||
import com.tangem.tap.domain.TangemSdkManager
|
||||
import com.tangem.tap.features.shop.redux.ShopAction
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.ActivityMainBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -33,6 +34,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
lateinit var tangemSdk: TangemSdk
|
||||
|
|
@ -51,6 +53,9 @@ val mainScope = CoroutineScope(mainCoroutineContext)
|
|||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbackHolder {
|
||||
|
||||
@Inject
|
||||
lateinit var appStateHolder: AppStateHolder
|
||||
|
||||
private var snackbar: Snackbar? = null
|
||||
private val dialogManager = DialogManager()
|
||||
private val intentHandler = IntentHandler()
|
||||
|
|
@ -66,6 +71,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
tangemSdk = TangemSdk.init(this, TangemSdkManager.config)
|
||||
tangemSdkManager = TangemSdkManager(tangemSdk, this)
|
||||
appStateHolder.tangemSdkManager = tangemSdkManager
|
||||
backupService = BackupService.init(tangemSdk, this)
|
||||
|
||||
store.dispatch(
|
||||
|
|
|
|||
|
|
@ -41,18 +41,16 @@ import com.tangem.tap.domain.walletconnect.WalletConnectRepository
|
|||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.tap.persistence.CardBalanceStateAdapter
|
||||
import com.tangem.tap.persistence.PreferencesStorage
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import com.zendesk.logger.Logger
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import org.rekotlin.Store
|
||||
import timber.log.Timber
|
||||
import zendesk.chat.Chat
|
||||
import javax.inject.Inject
|
||||
|
||||
val store = Store(
|
||||
reducer = ::appReducer,
|
||||
middleware = AppState.getMiddleware(),
|
||||
state = AppState(),
|
||||
)
|
||||
lateinit var store: Store<AppState>
|
||||
|
||||
lateinit var foregroundActivityObserver: ForegroundActivityObserver
|
||||
lateinit var preferencesStorage: PreferencesStorage
|
||||
|
|
@ -64,9 +62,21 @@ lateinit var userTokensRepository: UserTokensRepository
|
|||
@HiltAndroidApp
|
||||
class TapApplication : Application(), ImageLoaderFactory {
|
||||
|
||||
@Inject
|
||||
lateinit var appStateHolder: AppStateHolder
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
store = Store(
|
||||
reducer = { action, state ->
|
||||
appReducer(action, state, appStateHolder)
|
||||
},
|
||||
middleware = AppState.getMiddleware(),
|
||||
state = AppState(),
|
||||
)
|
||||
appStateHolder.mainStore = store
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
|
|
@ -91,6 +101,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
context = this,
|
||||
tangemTechService = store.state.domainNetworks.tangemTechService,
|
||||
)
|
||||
appStateHolder.userTokensRepository = userTokensRepository
|
||||
}
|
||||
|
||||
private fun initMoshiConverter() {
|
||||
|
|
|
|||
|
|
@ -14,20 +14,21 @@ import com.tangem.tap.features.send.redux.reducers.SendScreenReducer
|
|||
import com.tangem.tap.features.shop.redux.ShopReducer
|
||||
import com.tangem.tap.features.tokens.redux.TokensReducer
|
||||
import com.tangem.tap.features.wallet.redux.reducers.WalletReducer
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import org.rekotlin.Action
|
||||
|
||||
fun appReducer(action: Action, state: AppState?): AppState {
|
||||
fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder): AppState {
|
||||
requireNotNull(state)
|
||||
if (action is AppAction.RestoreState) return action.state
|
||||
|
||||
return AppState(
|
||||
navigationState = NavigationReducer.reduce(action, state),
|
||||
globalState = globalReducer(action, state),
|
||||
globalState = globalReducer(action, state, appStateHolder),
|
||||
homeState = HomeReducer.reduce(action, state),
|
||||
onboardingNoteState = OnboardingNoteReducer.reduce(action, state),
|
||||
onboardingWalletState = OnboardingWalletReducer.reduce(action, state),
|
||||
onboardingOtherCardsState = OnboardingOtherCardsReducer.reduce(action, state),
|
||||
walletState = WalletReducer.reduce(action, state),
|
||||
walletState = WalletReducer.reduce(action, state, appStateHolder),
|
||||
twinCardsState = TwinCardsReducer.reduce(action, state),
|
||||
sendState = SendScreenReducer.reduce(action, state.sendState),
|
||||
detailsState = DetailsReducer.reduce(action, state),
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ import com.tangem.domain.redux.global.DomainGlobalAction
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.onboarding.OnboardingManager
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import org.rekotlin.Action
|
||||
|
||||
fun globalReducer(action: Action, state: AppState): GlobalState {
|
||||
fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolder): GlobalState {
|
||||
|
||||
if (action !is GlobalAction) return state.globalState
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
globalState.copy(scanCardFailsCounter = 0)
|
||||
}
|
||||
is GlobalAction.SaveScanNoteResponse -> {
|
||||
appStateHolder.scanResponse = action.scanResponse
|
||||
domainStore.dispatch(DomainGlobalAction.SaveScanNoteResponse(action.scanResponse))
|
||||
globalState.copy(scanResponse = action.scanResponse)
|
||||
}
|
||||
|
|
@ -70,7 +72,9 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
}
|
||||
is GlobalAction.SetIfCardVerifiedOnline ->
|
||||
globalState.copy(cardVerifiedOnline = action.verified)
|
||||
is GlobalAction.FetchUserCountry.Success -> globalState.copy(userCountryCode = action.countryCode)
|
||||
is GlobalAction.FetchUserCountry.Success -> globalState.copy(
|
||||
userCountryCode = action.countryCode,
|
||||
)
|
||||
else -> globalState
|
||||
}
|
||||
}
|
||||
|
|
@ -30,17 +30,19 @@ import com.tangem.tap.features.wallet.redux.WalletState
|
|||
import com.tangem.tap.features.wallet.redux.WalletStore
|
||||
import com.tangem.tap.features.wallet.ui.BalanceStatus
|
||||
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import org.rekotlin.Action
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
class WalletReducer {
|
||||
companion object {
|
||||
fun reduce(action: Action, state: AppState): WalletState = internalReduce(action, state)
|
||||
fun reduce(action: Action, state: AppState, appStateHolder: AppStateHolder): WalletState =
|
||||
internalReduce(action, state, appStateHolder)
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, state: AppState): WalletState {
|
||||
private fun internalReduce(action: Action, state: AppState, appStateHolder: AppStateHolder): WalletState {
|
||||
|
||||
val multiWalletReducer = MultiWalletReducer()
|
||||
val onWalletLoadedReducer = OnWalletLoadedReducer()
|
||||
|
|
@ -65,17 +67,17 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
blockchainNetwork = BlockchainNetwork(
|
||||
Blockchain.Unknown,
|
||||
null,
|
||||
emptyList()
|
||||
emptyList(),
|
||||
),
|
||||
walletsData = listOf(
|
||||
WalletData(
|
||||
currencyData = BalanceWidgetData(BalanceStatus.EmptyCard),
|
||||
mainButton = WalletMainButton.CreateWalletButton(true),
|
||||
currency = Currency.Blockchain(Blockchain.Unknown, null)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
currency = Currency.Blockchain(Blockchain.Unknown, null),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is WalletAction.LoadData.Failure -> {
|
||||
|
|
@ -87,18 +89,18 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
walletsData = store.walletsData.map {
|
||||
it.copy(
|
||||
currencyData = it.currencyData.copy(
|
||||
status = BalanceStatus.Unreachable
|
||||
)
|
||||
status = BalanceStatus.Unreachable,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
newState = newState.copy(
|
||||
state = ProgressState.Error,
|
||||
error = ErrorType.NoInternetConnection,
|
||||
wallets = wallets
|
||||
wallets = wallets,
|
||||
)
|
||||
}
|
||||
is TapError.UnknownBlockchain -> {
|
||||
|
|
@ -110,16 +112,16 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
blockchainNetwork = BlockchainNetwork(
|
||||
Blockchain.Unknown,
|
||||
null,
|
||||
emptyList()
|
||||
emptyList(),
|
||||
),
|
||||
walletsData = listOf(
|
||||
WalletData(
|
||||
currencyData = BalanceWidgetData(BalanceStatus.UnknownBlockchain),
|
||||
currency = Currency.Blockchain(Blockchain.Unknown, null)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
currency = Currency.Blockchain(Blockchain.Unknown, null),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
else -> { /* no-op */
|
||||
|
|
@ -190,7 +192,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
is WalletAction.LoadWallet.Success -> newState = onWalletLoadedReducer.reduce(
|
||||
wallet = action.wallet,
|
||||
blockchainNetwork = action.blockchain,
|
||||
walletState = newState
|
||||
walletState = newState,
|
||||
)
|
||||
is WalletAction.LoadWallet.NoAccount -> {
|
||||
val amount = BigDecimal.ZERO
|
||||
|
|
@ -209,10 +211,10 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
),
|
||||
fiatAmount = fiatAmount,
|
||||
fiatAmountFormatted = fiatAmount.toFormattedFiatValue(
|
||||
fiatCurrencyName = state.globalState.appCurrency.symbol
|
||||
fiatCurrencyName = state.globalState.appCurrency.symbol,
|
||||
),
|
||||
amountToCreateAccount = action.amountToCreateAccount,
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
val updatedWalletStore = newState.getWalletStore(action.blockchain)
|
||||
|
|
@ -232,7 +234,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
val newWalletData = walletData?.copy(
|
||||
currencyData = walletData.currencyData.copy(
|
||||
status = BalanceStatus.Unreachable,
|
||||
errorMessage = message
|
||||
errorMessage = message,
|
||||
),
|
||||
)
|
||||
val tokenWallets = action.wallet.getTokens()
|
||||
|
|
@ -244,8 +246,8 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
.map {
|
||||
it.copy(
|
||||
currencyData = it.currencyData.copy(
|
||||
status = BalanceStatus.Unreachable, errorMessage = message
|
||||
)
|
||||
status = BalanceStatus.Unreachable, errorMessage = message,
|
||||
),
|
||||
)
|
||||
}
|
||||
val updatedWallets = walletStore!!.updateWallets(listOfNotNull(newWalletData) + tokenWallets).walletsData
|
||||
|
|
@ -296,9 +298,9 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
selectedWalletData?.copy(
|
||||
walletAddresses = WalletAddresses(
|
||||
address,
|
||||
walletAddresses.list
|
||||
)
|
||||
)
|
||||
walletAddresses.list,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is WalletAction.SetWalletRent -> {
|
||||
|
|
@ -320,6 +322,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
appStateHolder.walletState = newState
|
||||
return newState
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +348,7 @@ fun Wallet.createAddressesData(): List<AddressData> {
|
|||
it.value,
|
||||
it.type,
|
||||
getShareUri(it.value),
|
||||
getExploreUrl(it.value)
|
||||
getExploreUrl(it.value),
|
||||
)
|
||||
if (it.type == blockchain.defaultAddressType()) {
|
||||
listOfAddressData.add(0, addressData)
|
||||
|
|
@ -358,27 +361,26 @@ fun Wallet.createAddressesData(): List<AddressData> {
|
|||
|
||||
private fun handleCheckSignedHashesActions(
|
||||
action: WalletAction.Warnings,
|
||||
state: WalletState
|
||||
state: WalletState,
|
||||
): WalletState {
|
||||
return when (action) {
|
||||
WalletAction.Warnings.CheckHashesCount.ConfirmHashesCount -> state.copy(hashesCountVerified = true)
|
||||
WalletAction.Warnings.CheckHashesCount.NeedToCheckHashesCountOnline -> state.copy(
|
||||
hashesCountVerified = false
|
||||
hashesCountVerified = false,
|
||||
)
|
||||
is WalletAction.Warnings.Set -> state.copy(mainWarningsList = action.warningList)
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setNewFiatRate(
|
||||
fiatRates: Map<Currency, BigDecimal?>,
|
||||
appCurrency: FiatCurrency,
|
||||
state: WalletState
|
||||
state: WalletState,
|
||||
): WalletState {
|
||||
val rateFormatter: (BigDecimal) -> String = { rate: BigDecimal ->
|
||||
rate.toFiatRateString(
|
||||
fiatCurrencyName = appCurrency.symbol
|
||||
fiatCurrencyName = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -387,7 +389,7 @@ private fun setNewFiatRate(
|
|||
fiatRates = fiatRates.mapNotNullValues { it.value },
|
||||
rateFormatter = rateFormatter,
|
||||
appCurrency = appCurrency,
|
||||
state = state
|
||||
state = state,
|
||||
)
|
||||
} else {
|
||||
setSingleWalletFiatRates(
|
||||
|
|
@ -403,7 +405,7 @@ private fun setMultiWalletFiatRate(
|
|||
fiatRates: Map<Currency, BigDecimal>,
|
||||
rateFormatter: (BigDecimal) -> String,
|
||||
appCurrency: FiatCurrency,
|
||||
state: WalletState
|
||||
state: WalletState,
|
||||
): WalletState {
|
||||
val newWalletsData = fiatRates.mapNotNull { (currency, rate) ->
|
||||
val walletStore = state.getWalletStore(currency) ?: return@mapNotNull null
|
||||
|
|
@ -488,10 +490,9 @@ private fun setSingleWalletFiatRate(
|
|||
val walletData = state.primaryWallet.copy(
|
||||
currencyData = state.primaryWallet.currencyData.copy(fiatAmountFormatted = fiatAmount),
|
||||
fiatRate = rate,
|
||||
fiatRateString = rateFormatted
|
||||
fiatRateString = rateFormatted,
|
||||
)
|
||||
return state.updateWalletData(walletData)
|
||||
|
||||
} else if (currency is Currency.Token && currency.token == token) {
|
||||
Timber.e("Working with token fiat rate")
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.network.auth
|
||||
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.lib.auth.AuthProvider
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
|
||||
class AuthProviderImpl(private val appStateHolder: AppStateHolder) : AuthProvider {
|
||||
|
||||
override fun getAuthToken(): String {
|
||||
return appStateHolder.scanResponse?.card?.cardPublicKey?.toHexString() ?: ""
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.tap.network.auth.di
|
||||
|
||||
import com.tangem.lib.auth.AuthProvider
|
||||
import com.tangem.tap.network.auth.AuthProviderImpl
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class AuthModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthProvider(appStateHolder: AppStateHolder): AuthProvider {
|
||||
return AuthProviderImpl(appStateHolder)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,8 @@ package com.tangem.tap.proxy
|
|||
import com.tangem.common.card.Card
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.TangemSdkManager
|
||||
import com.tangem.tap.domain.tokens.UserTokensRepository
|
||||
import com.tangem.tap.features.tokens.redux.TokensMiddleware
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import org.rekotlin.Store
|
||||
|
||||
|
|
@ -14,11 +14,11 @@ import org.rekotlin.Store
|
|||
*/
|
||||
class AppStateHolder {
|
||||
|
||||
val scanResponse: ScanResponse? = null
|
||||
val walletState: WalletState? = null
|
||||
val userTokensRepository: UserTokensRepository? = null
|
||||
val mainStore: Store<AppState>? = null
|
||||
val tokesMiddleware: TokensMiddleware? = null
|
||||
var scanResponse: ScanResponse? = null
|
||||
var walletState: WalletState? = null
|
||||
var userTokensRepository: UserTokensRepository? = null
|
||||
var mainStore: Store<AppState>? = null
|
||||
var tangemSdkManager: TangemSdkManager? = null
|
||||
|
||||
fun getActualCard(): Card? {
|
||||
return scanResponse?.card
|
||||
|
|
|
|||
|
|
@ -2,12 +2,27 @@ package com.tangem.tap.proxy
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.lib.crypto.DerivationManager
|
||||
import com.tangem.lib.crypto.models.Currency
|
||||
import com.tangem.lib.crypto.models.NonNativeToken
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
|
||||
import com.tangem.tap.scope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class DerivationManagerImpl(
|
||||
|
|
@ -15,7 +30,6 @@ class DerivationManagerImpl(
|
|||
) : DerivationManager {
|
||||
|
||||
override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine<Boolean> { continuation ->
|
||||
val tokesMiddleware = requireNotNull(appStateHolder.tokesMiddleware) { "tokesMiddleware is null" }
|
||||
val blockchain = Blockchain.fromNetworkId(currency.networkId)
|
||||
val card = appStateHolder.getActualCard()
|
||||
if (blockchain != null && card != null) {
|
||||
|
|
@ -31,9 +45,10 @@ class DerivationManagerImpl(
|
|||
blockchainNetwork,
|
||||
appToken,
|
||||
)
|
||||
if (appStateHolder.scanResponse != null) {
|
||||
tokesMiddleware.deriveMissingBlockchains(
|
||||
scanResponse = appStateHolder.scanResponse,
|
||||
val scanResponse = appStateHolder.scanResponse
|
||||
if (scanResponse != null) {
|
||||
deriveMissingBlockchains(
|
||||
scanResponse = scanResponse,
|
||||
listOf(appCurrency),
|
||||
) {
|
||||
continuation.resumeWith(Result.success(true))
|
||||
|
|
@ -57,4 +72,99 @@ class DerivationManagerImpl(
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun deriveMissingBlockchains(
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<com.tangem.tap.features.wallet.models.Currency>,
|
||||
onSuccess: (ScanResponse) -> Unit,
|
||||
) {
|
||||
val derivationDataList = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
|
||||
)
|
||||
val derivations = derivationDataList.associate { it.derivations }
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
return
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
val result = appStateHolder.tangemSdkManager?.derivePublicKeys(
|
||||
scanResponse.card.cardId,
|
||||
derivations,
|
||||
)
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
val newDerivedKeys = result.data.entries
|
||||
val oldDerivedKeys = scanResponse.derivedKeys
|
||||
|
||||
val walletKeys = (newDerivedKeys.keys + oldDerivedKeys.keys).toSet()
|
||||
|
||||
val updatedDerivedKeys = walletKeys.associateWith { walletKey ->
|
||||
val oldDerivations = ExtendedPublicKeysMap(oldDerivedKeys[walletKey] ?: emptyMap())
|
||||
val newDerivations = newDerivedKeys[walletKey] ?: ExtendedPublicKeysMap(emptyMap())
|
||||
ExtendedPublicKeysMap(oldDerivations + newDerivations)
|
||||
}
|
||||
val updatedScanResponse = scanResponse.copy(
|
||||
derivedKeys = updatedDerivedKeys,
|
||||
)
|
||||
appStateHolder.mainStore?.dispatchOnMain(GlobalAction.SaveScanNoteResponse(updatedScanResponse))
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
onSuccess(updatedScanResponse)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
appStateHolder.mainStore?.dispatchDebugErrorNotification(
|
||||
TapError.CustomError(
|
||||
"Error adding " +
|
||||
"tokens",
|
||||
),
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
throw IllegalStateException("result result is null")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDerivations(
|
||||
curve: EllipticCurve,
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<com.tangem.tap.features.wallet.models.Currency>,
|
||||
): DerivationData? {
|
||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
||||
|
||||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.card.derivationStyle)
|
||||
}
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
it.blockchain.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull { it.derivationPath }.map { DerivationPath(it) }
|
||||
|
||||
val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct()
|
||||
if (bothCandidates.isEmpty()) return null
|
||||
|
||||
val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
|
||||
val alreadyDerivedKeys: ExtendedPublicKeysMap =
|
||||
scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
|
||||
val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList()
|
||||
|
||||
val toDerive = bothCandidates.filterNot { alreadyDerivedPaths.contains(it) }
|
||||
if (toDerive.isEmpty()) return null
|
||||
|
||||
return DerivationData(
|
||||
derivations = mapKeyOfWalletPublicKey to toDerive,
|
||||
alreadyDerivedKeys = alreadyDerivedKeys,
|
||||
mapKeyOfWalletPublicKey = mapKeyOfWalletPublicKey,
|
||||
)
|
||||
}
|
||||
|
||||
private class DerivationData(
|
||||
val derivations: Pair<ByteArrayKey, List<DerivationPath>>,
|
||||
val alreadyDerivedKeys: ExtendedPublicKeysMap,
|
||||
val mapKeyOfWalletPublicKey: ByteArrayKey,
|
||||
)
|
||||
}
|
||||
|
|
@ -25,6 +25,9 @@ android {
|
|||
|
||||
dependencies {
|
||||
|
||||
/** Project */
|
||||
implementation(project(":libs:auth"))
|
||||
|
||||
/** DI */
|
||||
implementation(Library.hilt)
|
||||
kapt(Library.hiltKapt)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.datasource.api
|
||||
|
||||
import com.tangem.lib.auth.AuthProvider
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
class AuthHeaderInterceptor(
|
||||
private val authProvider: AuthProvider,
|
||||
) : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request().newBuilder().apply {
|
||||
addHeader(
|
||||
HEADER_CARD_KEY, authProvider.getAuthToken(),
|
||||
)
|
||||
}.build()
|
||||
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HEADER_CARD_KEY = "card_public_key"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.tangem.datasource.api.AuthHeaderInterceptor
|
||||
import com.tangem.datasource.api.referral.ReferralApi
|
||||
import com.tangem.lib.auth.AuthProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -30,15 +32,16 @@ class NetworkModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(): OkHttpClient {
|
||||
fun provideOkHttpClient(authProvider: AuthProvider): OkHttpClient {
|
||||
return OkHttpClient.Builder()
|
||||
.addInterceptor(
|
||||
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC),
|
||||
)
|
||||
.addInterceptor(AuthHeaderInterceptor(authProvider))
|
||||
.build()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PROD_REFERRAL_BASE_URL = ""
|
||||
const val PROD_REFERRAL_BASE_URL = "https://api.tangem-tech.com/v1/"
|
||||
}
|
||||
}
|
||||
1
libs/auth/.gitignore
vendored
Normal file
1
libs/auth/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
23
libs/auth/build.gradle.kts
Normal file
23
libs/auth/build.gradle.kts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
defaultConfig {
|
||||
compileSdk = AppConfig.compileSdkVersion
|
||||
minSdk = AppConfig.minSdkVersion
|
||||
targetSdk = AppConfig.targetSdkVersion
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
isCoreLibraryDesugaringEnabled = false
|
||||
}
|
||||
}
|
||||
2
libs/auth/src/main/AndroidManifest.xml
Normal file
2
libs/auth/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.tangem.lib.auth" />
|
||||
12
libs/auth/src/main/java/com/tangem/lib/auth/AuthProvider.kt
Normal file
12
libs/auth/src/main/java/com/tangem/lib/auth/AuthProvider.kt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.lib.auth
|
||||
|
||||
/**
|
||||
* Provides auth for tangemTech API
|
||||
*/
|
||||
interface AuthProvider {
|
||||
|
||||
/**
|
||||
* Returns authToken for tangem tech api
|
||||
*/
|
||||
fun getAuthToken(): String
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ include(":core:ui")
|
|||
|
||||
// region Libs modules
|
||||
include(":libs:crypto")
|
||||
include(":libs:auth")
|
||||
// endregion Libs modules
|
||||
|
||||
// region Feature modules
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue