Updated on 2026-08-14
This commit is contained in:
parent
8b75e37e30
commit
a9bca131c3
386 changed files with 1369 additions and 1347 deletions
|
|
@ -54,7 +54,6 @@ dependencies {
|
|||
implementation(deps.arrow.core)
|
||||
implementation(deps.arrow.fx)
|
||||
implementation(deps.jodatime)
|
||||
implementation(deps.timber)
|
||||
implementation(deps.androidx.paging.runtime)
|
||||
implementation(deps.moshi.kotlin)
|
||||
ksp(deps.moshi.kotlin.codegen)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import com.tangem.data.pay.util.TangemPayErrorConverter
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.TangemPayCryptoCurrencyFactory
|
||||
import timber.log.Timber
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val TAG = "TangemPay: DefaultTangemPayCryptoCurrencyFactory"
|
||||
|
|
@ -53,7 +53,7 @@ internal class DefaultTangemPayCryptoCurrencyFactory @Inject constructor(
|
|||
decimals = TOKEN_DECIMALS,
|
||||
)
|
||||
}.mapLeft { exception ->
|
||||
Timber.tag(TAG).e(exception)
|
||||
TangemLogger.withTag(TAG).e("Error", exception)
|
||||
errorConverter.convert(exception)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import com.tangem.domain.visa.error.VisaApiError
|
|||
import com.tangem.security.DeviceSecurityInfoProvider
|
||||
import com.tangem.security.isSecurityExposed
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import timber.log.Timber
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val TAG = "PaymentAccountStatusFetcher"
|
||||
|
|
@ -31,12 +31,14 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
|
||||
override suspend fun invoke(params: PaymentAccountStatusFetcher.Params): Either<Throwable, Unit> =
|
||||
eitherOn(dispatchers.default) {
|
||||
Timber.tag(TAG).i("fetch: ${params.userWalletId.stringValue}")
|
||||
TangemLogger.withTag(TAG).i("fetch: ${params.userWalletId.stringValue}")
|
||||
|
||||
if (deviceSecurity.isSecurityExposed()) {
|
||||
Timber.tag(TAG).i("fetch security info: rooted: ${deviceSecurity.isRooted}")
|
||||
Timber.tag(TAG).i("fetch security info: xposed: ${deviceSecurity.isXposed}")
|
||||
Timber.tag(TAG).i("fetch security info: bootloader unlocked: ${deviceSecurity.isBootloaderUnlocked}")
|
||||
TangemLogger.withTag(TAG).i("fetch security info: rooted: ${deviceSecurity.isRooted}")
|
||||
TangemLogger.withTag(TAG).i("fetch security info: xposed: ${deviceSecurity.isXposed}")
|
||||
TangemLogger.withTag(
|
||||
TAG,
|
||||
).i("fetch security info: bootloader unlocked: ${deviceSecurity.isBootloaderUnlocked}")
|
||||
|
||||
return@eitherOn paymentAccountStatusesStore.store(
|
||||
userWalletId = params.userWalletId,
|
||||
|
|
@ -47,7 +49,9 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
val status = onboardingRepository.hasTangemPayInWallet(userWalletId = params.userWalletId)
|
||||
.fold(
|
||||
ifLeft = { error ->
|
||||
Timber.tag(TAG).e("Failed check wallet ${params.userWalletId}: ${error.javaClass.simpleName}")
|
||||
TangemLogger.withTag(
|
||||
TAG,
|
||||
).e("Failed check wallet ${params.userWalletId}: ${error.javaClass.simpleName}")
|
||||
when (error) {
|
||||
is VisaApiError.NotPaeraCustomer -> PaymentAccountStatus.NotCreated
|
||||
else -> PaymentAccountStatus.Error.Unavailable(source = StatusSource.ACTUAL)
|
||||
|
|
@ -57,7 +61,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
proceedHasTangemPayResult(userWalletId = params.userWalletId, hasTangemPay = hasTangemPay)
|
||||
},
|
||||
)
|
||||
Timber.tag(TAG).i("invoke status ${params.userWalletId}: $status")
|
||||
TangemLogger.withTag(TAG).i("invoke status ${params.userWalletId}: $status")
|
||||
paymentAccountStatusesStore.store(userWalletId = params.userWalletId, status = status)
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +69,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
userWalletId: UserWalletId,
|
||||
hasTangemPay: Boolean,
|
||||
): PaymentAccountStatus {
|
||||
Timber.tag(TAG).i("proceedHasTangemPayResult for $userWalletId hasTangemPay: $hasTangemPay")
|
||||
TangemLogger.withTag(TAG).i("proceedHasTangemPayResult for $userWalletId hasTangemPay: $hasTangemPay")
|
||||
return if (hasTangemPay) {
|
||||
fetchTangemPayAccountStatus(userWalletId = userWalletId)
|
||||
} else {
|
||||
|
|
@ -98,15 +102,15 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
private suspend fun proceedWithoutOrder(userWalletId: UserWalletId): PaymentAccountStatus {
|
||||
return onboardingRepository.getCustomerInfo(userWalletId).fold(
|
||||
ifLeft = { error ->
|
||||
Timber.tag(TAG).e("proceedWithoutOrder $userWalletId error: $error")
|
||||
TangemLogger.withTag(TAG).e("proceedWithoutOrder $userWalletId error: $error")
|
||||
error.mapToPaymentAccountStatus()
|
||||
},
|
||||
ifRight = { customerInfo ->
|
||||
Timber.tag(TAG).i("proceedWithoutOrder data customerInfo $userWalletId")
|
||||
TangemLogger.withTag(TAG).i("proceedWithoutOrder data customerInfo $userWalletId")
|
||||
val status = customerInfo.mapToPaymentAccountStatus()
|
||||
if (customerInfo.productInstance == null) {
|
||||
onboardingRepository.createOrder(userWalletId)
|
||||
.onLeft { Timber.tag(TAG).e("createOrder failed: $it") }
|
||||
.onLeft { TangemLogger.withTag(TAG).e("createOrder failed: $it") }
|
||||
}
|
||||
status
|
||||
},
|
||||
|
|
@ -116,11 +120,11 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
private suspend fun proceedWithOrderId(userWalletId: UserWalletId, orderId: String): PaymentAccountStatus {
|
||||
return customerOrderRepository.getOrderData(userWalletId, orderId = orderId).fold(
|
||||
ifLeft = { error ->
|
||||
Timber.tag(TAG).e("proceedWithOrderId $userWalletId orderId: $orderId error: $error")
|
||||
TangemLogger.withTag(TAG).e("proceedWithOrderId $userWalletId orderId: $orderId error: $error")
|
||||
error.mapToPaymentAccountStatus()
|
||||
},
|
||||
ifRight = { orderData ->
|
||||
Timber.tag(TAG).i("proceedWithOrderId $userWalletId: $orderId status: ${orderData.status}")
|
||||
TangemLogger.withTag(TAG).i("proceedWithOrderId $userWalletId: $orderId status: ${orderData.status}")
|
||||
when (orderData.status) {
|
||||
// Kyc is passed and user waits for order creation -> no need to get customer info
|
||||
OrderStatus.NEW,
|
||||
|
|
|
|||
|
|
@ -19,18 +19,21 @@ import com.tangem.datasource.api.pay.models.response.FreezeUnfreezeCardResponse
|
|||
import com.tangem.datasource.api.pay.models.response.OrderResponse.Result.Status
|
||||
import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.SetPinResult
|
||||
import com.tangem.domain.pay.model.TangemPayCardBalance
|
||||
import com.tangem.domain.pay.model.TangemPayCardDetails
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import kotlinx.coroutines.*
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
|
|
@ -296,7 +299,7 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
cardFrozenStateStore.store(cardId, finalState)
|
||||
}
|
||||
}.onLeft { error ->
|
||||
Timber.e("error ${error.errorCode}")
|
||||
TangemLogger.e("error ${error.errorCode}")
|
||||
// stop retrying after 3 errors
|
||||
if (retryCount > MAX_POLLING_RETRIES) {
|
||||
pollingJobs.remove(key = orderId)
|
||||
|
|
@ -305,7 +308,7 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
retryCount++
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
TangemLogger.e("Error", e)
|
||||
storePollingMutex.withLock {
|
||||
pollingJobs.remove(orderId)
|
||||
}
|
||||
|
|
@ -338,7 +341,7 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
}
|
||||
|
||||
private fun <T> catchException(throwable: Throwable): Either<UniversalError, T> {
|
||||
Timber.tag(TAG).e(throwable)
|
||||
TangemLogger.withTag(TAG).e("Error", throwable)
|
||||
return errorConverter.convert(throwable).left()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ import com.tangem.feature.swap.domain.api.SwapRepository
|
|||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.extensions.addHexPrefix
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.util.Currency
|
||||
|
|
@ -176,14 +176,14 @@ internal class DefaultTangemPayWithdrawRepository @Inject constructor(
|
|||
}
|
||||
}
|
||||
if (attemptCount >= MAX_POLLING_ATTEMPTS) {
|
||||
Timber.tag(TAG).e("Polling stopped after $attemptCount unsuccessful attempts")
|
||||
TangemLogger.withTag(TAG).e("Polling stopped after $attemptCount unsuccessful attempts")
|
||||
tangemPayStorage.deleteWithdrawOrder(userWalletId = userWallet.walletId, orderId = orderId)
|
||||
pollingMutex.withLock { pollingJobs.remove(key) }
|
||||
}
|
||||
} catch (exception: CancellationException) {
|
||||
throw exception
|
||||
} catch (exception: Exception) {
|
||||
Timber.tag(TAG).e(exception)
|
||||
TangemLogger.withTag(TAG).e("Error", exception)
|
||||
tangemPayStorage.deleteWithdrawOrder(userWalletId = userWallet.walletId, orderId = orderId)
|
||||
pollingMutex.withLock { pollingJobs.remove(key) }
|
||||
}
|
||||
|
|
@ -240,7 +240,7 @@ internal class DefaultTangemPayWithdrawRepository @Inject constructor(
|
|||
} catch (exception: CancellationException) {
|
||||
throw exception
|
||||
} catch (exception: Exception) {
|
||||
Timber.tag(TAG).e(exception)
|
||||
TangemLogger.withTag(TAG).e("Error", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ import com.tangem.domain.visa.error.VisaApiError
|
|||
import com.tangem.domain.visa.model.TangemPayAuthTokens
|
||||
import com.tangem.domain.visa.model.getAuthHeader
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
|
@ -69,7 +69,7 @@ internal class TangemPayRequestPerformer @Inject constructor(
|
|||
}
|
||||
},
|
||||
catch = { errorConverter.convert(it).left() },
|
||||
).onLeft { visaApiError -> Timber.tag(TAG).e(visaApiError.toString()) }
|
||||
).onLeft { visaApiError -> TangemLogger.withTag(TAG).e(visaApiError.toString()) }
|
||||
}
|
||||
|
||||
suspend fun getCustomerWalletAddress(userWalletId: UserWalletId): String {
|
||||
|
|
@ -129,7 +129,7 @@ internal class TangemPayRequestPerformer @Inject constructor(
|
|||
idempotencyKey = UUID.randomUUID().toString(),
|
||||
)
|
||||
}.mapLeft { error ->
|
||||
Timber.tag(TAG).e("Can not refresh auth tokens: $error")
|
||||
TangemLogger.withTag(TAG).e("Can not refresh auth tokens: $error")
|
||||
if (error is VisaApiError.ServerUnavailable) error else VisaApiError.RefreshTokenExpired
|
||||
}.onRight { tokens ->
|
||||
tangemPayStorage.storeAuthTokens(customerWalletAddress = customerWalletAddress, tokens = tokens)
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ import androidx.datastore.core.DataStore
|
|||
import com.tangem.data.pay.converter.PaymentAccountStatusDMConverter
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.datasource.local.visa.entity.PaymentAccountStatusDM
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.PaymentAccountStatus
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal typealias WalletIdWithPaymentStatus = Map<String, PaymentAccountStatus>
|
||||
internal typealias WalletIdWithPaymentStatusDM = Map<String, PaymentAccountStatusDM>
|
||||
|
|
@ -39,7 +39,7 @@ internal class PaymentAccountStatusesStore(
|
|||
},
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error while loading cached payment account statuses")
|
||||
TangemLogger.e("Error while loading cached payment account statuses", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import com.tangem.utils.converter.Converter
|
|||
import com.tangem.utils.extensions.isPositive
|
||||
import com.tangem.utils.extensions.isZero
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.DateTimeZone
|
||||
import timber.log.Timber
|
||||
import java.util.Currency
|
||||
|
||||
internal class TangemPayTxHistoryItemConverter(moshi: Moshi) :
|
||||
|
|
@ -26,7 +26,7 @@ internal class TangemPayTxHistoryItemConverter(moshi: Moshi) :
|
|||
?: value.fee?.let { convertFee(id = value.id, fee = it) }
|
||||
?: value.collateral?.let { convertCollateral(id = value.id, collateral = it) }
|
||||
?: run {
|
||||
Timber.wtf("unknown type of transaction: $value")
|
||||
TangemLogger.e("unknown type of transaction: $value")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ internal class TangemPayTxHistoryItemConverter(moshi: Moshi) :
|
|||
collateral: TangemPayTxHistoryResponse.Collateral,
|
||||
): TangemPayTxHistoryItem.Collateral? {
|
||||
val date = collateral.postedAt ?: return run {
|
||||
Timber.e("Collateral transaction postedAt is null: $collateral")
|
||||
TangemLogger.e("Collateral transaction postedAt is null: $collateral")
|
||||
return@run null
|
||||
}
|
||||
return TangemPayTxHistoryItem.Collateral(
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import com.tangem.datasource.api.visa.models.response.VisaTxHistoryResponse
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.visa.model.VisaTxHistoryItem
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
internal class VisaTxHistoryPagingSource(
|
||||
params: Params,
|
||||
|
|
@ -56,7 +56,7 @@ internal class VisaTxHistoryPagingSource(
|
|||
|
||||
LoadResult.Page(items, prevOffset, nextOffset)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to load the transaction history for the requested offset: $offsetToLoad")
|
||||
TangemLogger.e("Unable to load the transaction history for the requested offset: $offsetToLoad", e)
|
||||
LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue