Updated on 2026-08-14
This commit is contained in:
parent
40c611efea
commit
a006a87f9d
27 changed files with 524 additions and 16 deletions
|
|
@ -43,6 +43,10 @@ dependencies {
|
|||
api(tangemDeps.hot.core)
|
||||
implementation(tangemDeps.blockchain)
|
||||
implementation(tangemDeps.card.core)
|
||||
// AndroidSecureStorageV2 for TangemPay secure token storage (see com.tangem.data.pay.store).
|
||||
implementation(tangemDeps.card.android) {
|
||||
exclude(module = "joda-time")
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region DI
|
||||
|
|
|
|||
|
|
@ -306,6 +306,20 @@ internal interface TangemPayDataModule {
|
|||
return GetCashbackSummaryUseCase(cashbackRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideGetCashbackDeactivationDismissedUseCase(
|
||||
cashbackRepository: CashbackRepository,
|
||||
): GetCashbackDeactivationDismissedUseCase {
|
||||
return GetCashbackDeactivationDismissedUseCase(cashbackRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideSetCashbackDeactivationDismissedUseCase(
|
||||
cashbackRepository: CashbackRepository,
|
||||
): SetCashbackDeactivationDismissedUseCase {
|
||||
return SetCashbackDeactivationDismissedUseCase(cashbackRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideCheckOrderConflictUseCase(
|
||||
customerOrderRepository: CustomerOrderRepository,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.data.pay.repository
|
|||
import arrow.core.Either
|
||||
import com.tangem.data.pay.util.CashbackSummaryConverter
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.data.pay.store.TangemPayStorage
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.CashbackSummary
|
||||
import com.tangem.domain.pay.repository.CashbackRepository
|
||||
|
|
@ -12,6 +13,7 @@ import javax.inject.Inject
|
|||
internal class DefaultCashbackRepository @Inject constructor(
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val requestHelper: TangemPayRequestPerformer,
|
||||
private val storage: TangemPayStorage,
|
||||
) : CashbackRepository {
|
||||
|
||||
override suspend fun getCashbackSummary(userWalletId: UserWalletId): Either<VisaApiError, CashbackSummary> {
|
||||
|
|
@ -19,4 +21,14 @@ internal class DefaultCashbackRepository @Inject constructor(
|
|||
tangemPayApi.getCashbackSummary(authHeader = authHeader)
|
||||
}.map(CashbackSummaryConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun isDeactivationBannerDismissed(userWalletId: UserWalletId): Boolean {
|
||||
val customerWalletAddress = requestHelper.getCustomerWalletAddress(userWalletId)
|
||||
return storage.getCashbackDeactivationDismissed(customerWalletAddress)
|
||||
}
|
||||
|
||||
override suspend fun setDeactivationBannerDismissed(userWalletId: UserWalletId) {
|
||||
val customerWalletAddress = requestHelper.getCustomerWalletAddress(userWalletId)
|
||||
storage.storeCashbackDeactivationDismissed(customerWalletAddress = customerWalletAddress, isDismissed = true)
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ import com.tangem.datasource.api.pay.models.request.VirtualAccountOrderRequest
|
|||
import com.tangem.datasource.api.pay.models.response.CustomerMeResponse
|
||||
import com.tangem.datasource.api.pay.models.response.OrderResponse
|
||||
import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.data.pay.store.TangemPayStorage
|
||||
import com.tangem.datasource.local.visa.TangemPayTxHistoryItemsStore
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.account.Account
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import com.tangem.datasource.api.pay.models.request.SetPinRequest
|
|||
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.data.pay.store.TangemPayStorage
|
||||
import com.tangem.domain.models.account.CardDisplayName
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import com.tangem.datasource.api.pay.TangemPayApi
|
|||
import com.tangem.datasource.api.pay.models.request.WithdrawDataRequest
|
||||
import com.tangem.datasource.api.pay.models.request.WithdrawRequest
|
||||
import com.tangem.datasource.api.pay.models.response.WithdrawResponse
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.data.pay.store.TangemPayStorage
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import com.tangem.datasource.api.common.response.ApiResponse
|
|||
import com.tangem.datasource.api.pay.TangemPayAuthApi
|
||||
import com.tangem.datasource.api.pay.models.request.RefreshCustomerWalletAccessTokenRequest
|
||||
import com.tangem.datasource.api.pay.models.response.TangemPayGetTokensResponse
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.data.pay.store.TangemPayStorage
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.domain.visa.model.TangemPayAuthTokens
|
||||
|
|
|
|||
|
|
@ -0,0 +1,317 @@
|
|||
package com.tangem.data.pay.store
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import com.tangem.data.pay.entity.WithdrawStoreData
|
||||
import com.tangem.data.pay.util.WithdrawStateConverter
|
||||
import com.tangem.data.pay.util.WithdrawStoreDataConverter
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectMapSync
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||
import com.tangem.datasource.local.preferences.utils.getSyncOrNull
|
||||
import com.tangem.datasource.local.preferences.utils.store
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.domain.visa.model.TangemPayAuthTokens
|
||||
import com.tangem.sdk.storage.AndroidSecureStorageV2
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val AUTH_TOKENS_DEFAULT_KEY = "tangem_pay_default_key"
|
||||
private const val WITHDRAW_ORDER_ID_KEY = "tangem_pay_withdraw_order_id_key"
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
@Singleton
|
||||
internal class DefaultTangemPayStorage @Inject constructor(
|
||||
@ApplicationContext applicationContext: Context,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
) : TangemPayStorage {
|
||||
|
||||
private val secureStorage by lazy {
|
||||
AndroidSecureStorageV2(
|
||||
appContext = applicationContext,
|
||||
useStrongBox = false,
|
||||
name = "tangem_pay_storage",
|
||||
)
|
||||
}
|
||||
|
||||
private val tokensAdapter by lazy { moshi.adapter(TangemPayAuthTokens::class.java) }
|
||||
private val withdrawStoreDataConverter by lazy { WithdrawStoreDataConverter() }
|
||||
private val withdrawStateConverter by lazy { WithdrawStateConverter() }
|
||||
|
||||
private val listType by lazy {
|
||||
Types.newParameterizedType(List::class.java, WithdrawStoreData::class.java)
|
||||
}
|
||||
private val mapType by lazy {
|
||||
Types.newParameterizedType(Map::class.java, String::class.java, listType)
|
||||
}
|
||||
private val adapter: JsonAdapter<Map<String, List<WithdrawStoreData>>> by lazy {
|
||||
appPreferencesStore.moshi.adapter(mapType)
|
||||
}
|
||||
|
||||
override suspend fun storeCustomerWalletAddress(userWalletId: UserWalletId, customerWalletAddress: String) {
|
||||
appPreferencesStore
|
||||
.store(PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId), customerWalletAddress)
|
||||
}
|
||||
|
||||
override suspend fun getCustomerWalletAddress(userWalletId: UserWalletId): String? {
|
||||
return appPreferencesStore.getSyncOrNull(
|
||||
key = PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId),
|
||||
)
|
||||
.takeIf { !it.isNullOrEmpty() }
|
||||
}
|
||||
|
||||
override suspend fun clearCustomerWalletAddress(userWalletId: UserWalletId) {
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId), "")
|
||||
}
|
||||
|
||||
override suspend fun storeAuthTokens(customerWalletAddress: String, tokens: TangemPayAuthTokens) =
|
||||
withContext(dispatcherProvider.io) {
|
||||
val json = tokensAdapter.toJson(tokens)
|
||||
|
||||
secureStorage.store(
|
||||
json.encodeToByteArray(throwOnInvalidSequence = true),
|
||||
createAuthTokensKey(customerWalletAddress),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getAuthTokens(customerWalletAddress: String): TangemPayAuthTokens? {
|
||||
return withContext(dispatcherProvider.io) {
|
||||
val authTokens = secureStorage.get(createAuthTokensKey(customerWalletAddress))
|
||||
?.decodeToString(throwOnInvalidSequence = true)
|
||||
?.let(tokensAdapter::fromJson)
|
||||
|
||||
authTokens?.let { tokens ->
|
||||
if (tokens.idempotencyKey == null) {
|
||||
val newAuthTokens = tokens.copy(idempotencyKey = UUID.randomUUID().toString())
|
||||
storeAuthTokens(customerWalletAddress, newAuthTokens)
|
||||
newAuthTokens
|
||||
} else {
|
||||
tokens
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clearAuthTokens(customerWalletAddress: String) {
|
||||
withContext(dispatcherProvider.io) {
|
||||
secureStorage.delete(createAuthTokensKey(customerWalletAddress))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeOrderId(customerWalletAddress: String, orderId: String) {
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress), orderId)
|
||||
}
|
||||
|
||||
override suspend fun getOrderId(customerWalletAddress: String): String? {
|
||||
return appPreferencesStore.getSyncOrNull(key = PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress))
|
||||
.takeIf { !it.isNullOrEmpty() }
|
||||
}
|
||||
|
||||
override suspend fun getAddToWalletDone(customerWalletAddress: String): Boolean {
|
||||
return appPreferencesStore.getSyncOrNull(
|
||||
key = PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress),
|
||||
) == true
|
||||
}
|
||||
|
||||
override suspend fun storeAddToWalletDone(customerWalletAddress: String, isDone: Boolean) {
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), isDone)
|
||||
}
|
||||
|
||||
override suspend fun getCashbackDeactivationDismissed(customerWalletAddress: String): Boolean {
|
||||
return appPreferencesStore.getSyncOrNull(
|
||||
key = PreferencesKeys.getTangemPayCashbackDeactivationDismissedKey(customerWalletAddress),
|
||||
) == true
|
||||
}
|
||||
|
||||
override suspend fun storeCashbackDeactivationDismissed(customerWalletAddress: String, isDismissed: Boolean) {
|
||||
appPreferencesStore.store(
|
||||
key = PreferencesKeys.getTangemPayCashbackDeactivationDismissedKey(customerWalletAddress),
|
||||
value = isDismissed,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun clearOrderId(customerWalletAddress: String) {
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress), "")
|
||||
}
|
||||
|
||||
override suspend fun storeVirtualAccountOrderId(customerWalletAddress: String, vaOrderId: String) {
|
||||
appPreferencesStore.store(
|
||||
key = PreferencesKeys.getTangemPayVirtualAccountOrderIdKey(customerWalletAddress),
|
||||
value = vaOrderId,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getVirtualAccountOrderId(customerWalletAddress: String): String? {
|
||||
return appPreferencesStore.getSyncOrNull(
|
||||
key = PreferencesKeys.getTangemPayVirtualAccountOrderIdKey(customerWalletAddress),
|
||||
).takeIf { !it.isNullOrEmpty() }
|
||||
}
|
||||
|
||||
override suspend fun clearVirtualAccountOrderId(customerWalletAddress: String) {
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayVirtualAccountOrderIdKey(customerWalletAddress), "")
|
||||
}
|
||||
|
||||
override suspend fun storeCheckCustomerWalletResult(userWalletId: UserWalletId, isPaeraCustomer: Boolean) {
|
||||
appPreferencesStore.store(
|
||||
PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId),
|
||||
isPaeraCustomer,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun checkCustomerWalletResult(userWalletId: UserWalletId): Boolean? {
|
||||
return appPreferencesStore.getSyncOrNull(PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId))
|
||||
}
|
||||
|
||||
override suspend fun storeActiveWithdrawOrderId(userWalletId: UserWalletId, orderId: String) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val orders = mutablePreferences.getObjectMap<String>(
|
||||
PreferencesKeys.TANGEM_PAY_ACTIVE_WITHDRAW_ORDERS_KEY,
|
||||
)
|
||||
.plus(createWithdrawOrderIdKey(userWalletId) to orderId)
|
||||
mutablePreferences.setObjectMap(
|
||||
key = PreferencesKeys.TANGEM_PAY_ACTIVE_WITHDRAW_ORDERS_KEY,
|
||||
value = orders,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeWithdrawOrder(userWalletId: UserWalletId, data: TangemPayWithdrawState) {
|
||||
appPreferencesStore.editData { prefs ->
|
||||
val walletKey = createWithdrawOrderIdKey(userWalletId)
|
||||
val currentMap = prefs[PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY]
|
||||
?.let(adapter::fromJson)
|
||||
.orEmpty()
|
||||
val newItem = withdrawStoreDataConverter.convert(data)
|
||||
val currentList = currentMap[walletKey].orEmpty()
|
||||
val updatedList = buildList(currentList.size + 1) {
|
||||
for (item in currentList) { if (item.orderId != newItem.orderId) add(item) }
|
||||
add(newItem)
|
||||
}
|
||||
prefs[PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY] =
|
||||
adapter.toJson(currentMap + (walletKey to updatedList))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getActiveWithdrawOrderId(userWalletId: UserWalletId): String? {
|
||||
val orders = appPreferencesStore.getObjectMapSync<String>(
|
||||
PreferencesKeys.TANGEM_PAY_ACTIVE_WITHDRAW_ORDERS_KEY,
|
||||
)
|
||||
return orders[createWithdrawOrderIdKey(userWalletId)]
|
||||
}
|
||||
|
||||
override suspend fun getWithdrawOrders(userWalletId: UserWalletId): List<TangemPayWithdrawState> {
|
||||
val map = appPreferencesStore.data.firstOrNull()
|
||||
?.get(PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY)?.let(adapter::fromJson).orEmpty()
|
||||
return map[createWithdrawOrderIdKey(userWalletId)].orEmpty().map(withdrawStateConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun deleteActiveWithdrawOrder(userWalletId: UserWalletId) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val orders = mutablePreferences.getObjectMap<String>(
|
||||
PreferencesKeys.TANGEM_PAY_ACTIVE_WITHDRAW_ORDERS_KEY,
|
||||
)
|
||||
.minus(createWithdrawOrderIdKey(userWalletId))
|
||||
mutablePreferences.setObjectMap(
|
||||
key = PreferencesKeys.TANGEM_PAY_ACTIVE_WITHDRAW_ORDERS_KEY,
|
||||
value = orders,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteWithdrawOrder(userWalletId: UserWalletId, orderId: String) {
|
||||
appPreferencesStore.editData { prefs ->
|
||||
val walletKey = createWithdrawOrderIdKey(userWalletId)
|
||||
val currentMap = prefs[PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY]?.let(adapter::fromJson)
|
||||
.orEmpty()
|
||||
val currentList = currentMap[walletKey].orEmpty()
|
||||
val updatedList = buildList(currentList.size) {
|
||||
for (item in currentList) {
|
||||
if (item.orderId != orderId) add(item)
|
||||
}
|
||||
}
|
||||
val updatedMap = if (updatedList.isEmpty()) {
|
||||
currentMap - walletKey
|
||||
} else {
|
||||
currentMap + (walletKey to updatedList)
|
||||
}
|
||||
prefs[PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY] = adapter.toJson(updatedMap)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeHideOnboardingBanner(userWalletId: UserWalletId, hide: Boolean) {
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayHideOnboardingKey(userWalletId), hide)
|
||||
}
|
||||
|
||||
override suspend fun getHideMainOnboardingBanner(userWalletId: UserWalletId): Boolean {
|
||||
return appPreferencesStore.getSyncOrNull(
|
||||
key = PreferencesKeys.getTangemPayHideOnboardingKey(userWalletId),
|
||||
) == true
|
||||
}
|
||||
|
||||
override suspend fun storeTangemPayEligibility(eligibility: Set<String>) {
|
||||
withContext(dispatcherProvider.io) {
|
||||
appPreferencesStore.store(
|
||||
key = PreferencesKeys.TANGEM_PAY_ELIGIBILITY_KEY,
|
||||
value = eligibility,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getTangemPayEligibility(): Set<String> {
|
||||
return withContext(dispatcherProvider.io) {
|
||||
appPreferencesStore.getSyncOrDefault(
|
||||
key = PreferencesKeys.TANGEM_PAY_ELIGIBILITY_KEY,
|
||||
default = emptySet(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeIsTangemPayDeactivated(userWalletId: UserWalletId) {
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayDeactivatedKey(userWalletId), true)
|
||||
}
|
||||
|
||||
override suspend fun isTangemPayDeactivated(userWalletId: UserWalletId): Boolean {
|
||||
val key = PreferencesKeys.getTangemPayDeactivatedKey(userWalletId)
|
||||
return appPreferencesStore.getSyncOrNull(key) == true
|
||||
}
|
||||
|
||||
override suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String) {
|
||||
withContext(dispatcherProvider.io) {
|
||||
secureStorage.delete(createAuthTokensKey(customerWalletAddress))
|
||||
}
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId), false)
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId), "")
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress), "")
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), false)
|
||||
appPreferencesStore.store(PreferencesKeys.getTangemPayHideOnboardingKey(userWalletId), false)
|
||||
// Clear the withdraw order hints together with the rest of the cache.
|
||||
deleteActiveWithdrawOrder(userWalletId)
|
||||
clearWithdrawOrders(userWalletId)
|
||||
}
|
||||
|
||||
private suspend fun clearWithdrawOrders(userWalletId: UserWalletId) {
|
||||
appPreferencesStore.editData { prefs ->
|
||||
val walletKey = createWithdrawOrderIdKey(userWalletId)
|
||||
val currentMap = prefs[PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY]?.let(adapter::fromJson)
|
||||
.orEmpty()
|
||||
val updatedMap = currentMap - walletKey
|
||||
prefs[PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY] = adapter.toJson(updatedMap)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAuthTokensKey(address: String): String = "${AUTH_TOKENS_DEFAULT_KEY}_$address"
|
||||
|
||||
private fun createWithdrawOrderIdKey(userWalletId: UserWalletId): String = "${WITHDRAW_ORDER_ID_KEY}_$userWalletId"
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.tangem.data.pay.store
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.domain.visa.model.TangemPayAuthTokens
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
interface TangemPayStorage {
|
||||
|
||||
suspend fun storeCustomerWalletAddress(userWalletId: UserWalletId, customerWalletAddress: String)
|
||||
suspend fun getCustomerWalletAddress(userWalletId: UserWalletId): String?
|
||||
|
||||
suspend fun clearCustomerWalletAddress(userWalletId: UserWalletId)
|
||||
|
||||
suspend fun storeAuthTokens(customerWalletAddress: String, tokens: TangemPayAuthTokens)
|
||||
|
||||
suspend fun getAuthTokens(customerWalletAddress: String): TangemPayAuthTokens?
|
||||
suspend fun clearAuthTokens(customerWalletAddress: String)
|
||||
|
||||
suspend fun storeOrderId(customerWalletAddress: String, orderId: String)
|
||||
|
||||
suspend fun getOrderId(customerWalletAddress: String): String?
|
||||
|
||||
suspend fun clearOrderId(customerWalletAddress: String)
|
||||
|
||||
suspend fun storeVirtualAccountOrderId(customerWalletAddress: String, vaOrderId: String)
|
||||
|
||||
suspend fun getVirtualAccountOrderId(customerWalletAddress: String): String?
|
||||
|
||||
suspend fun clearVirtualAccountOrderId(customerWalletAddress: String)
|
||||
|
||||
suspend fun getAddToWalletDone(customerWalletAddress: String): Boolean
|
||||
|
||||
suspend fun storeAddToWalletDone(customerWalletAddress: String, isDone: Boolean)
|
||||
|
||||
suspend fun getCashbackDeactivationDismissed(customerWalletAddress: String): Boolean
|
||||
|
||||
suspend fun storeCashbackDeactivationDismissed(customerWalletAddress: String, isDismissed: Boolean)
|
||||
suspend fun storeCheckCustomerWalletResult(userWalletId: UserWalletId, isPaeraCustomer: Boolean)
|
||||
suspend fun checkCustomerWalletResult(userWalletId: UserWalletId): Boolean?
|
||||
|
||||
/** Called after creating withdraw order, active order id */
|
||||
suspend fun storeActiveWithdrawOrderId(userWalletId: UserWalletId, orderId: String)
|
||||
|
||||
/** Called after creating withdraw order, saves order data */
|
||||
suspend fun storeWithdrawOrder(userWalletId: UserWalletId, data: TangemPayWithdrawState)
|
||||
|
||||
/** Returns single active order id. Once the order is completed, deletes id from storage.
|
||||
* Only one active order allowed for a wallet */
|
||||
suspend fun getActiveWithdrawOrderId(userWalletId: UserWalletId): String?
|
||||
|
||||
/** Returns all withdraw orders saved.
|
||||
* Once we get tx hash for an order, it gets deleted from this storage */
|
||||
suspend fun getWithdrawOrders(userWalletId: UserWalletId): List<TangemPayWithdrawState>?
|
||||
|
||||
/** Deletes active withdraw order. Called after order is completed */
|
||||
suspend fun deleteActiveWithdrawOrder(userWalletId: UserWalletId)
|
||||
|
||||
/** Deletes withdraw order data. Called after getting its tx hash */
|
||||
suspend fun deleteWithdrawOrder(userWalletId: UserWalletId, orderId: String)
|
||||
|
||||
suspend fun getHideMainOnboardingBanner(userWalletId: UserWalletId): Boolean
|
||||
|
||||
suspend fun storeHideOnboardingBanner(userWalletId: UserWalletId, hide: Boolean)
|
||||
suspend fun storeTangemPayEligibility(eligibility: Set<String>)
|
||||
suspend fun getTangemPayEligibility(): Set<String>
|
||||
|
||||
suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String)
|
||||
|
||||
suspend fun storeIsTangemPayDeactivated(userWalletId: UserWalletId)
|
||||
suspend fun isTangemPayDeactivated(userWalletId: UserWalletId): Boolean
|
||||
}
|
||||
|
|
@ -33,6 +33,12 @@ internal class MockAwareCashbackRepository @Inject constructor(
|
|||
return real.getCashbackSummary(userWalletId)
|
||||
}
|
||||
|
||||
override suspend fun isDeactivationBannerDismissed(userWalletId: UserWalletId): Boolean =
|
||||
real.isDeactivationBannerDismissed(userWalletId)
|
||||
|
||||
override suspend fun setDeactivationBannerDismissed(userWalletId: UserWalletId) =
|
||||
real.setDeactivationBannerDismissed(userWalletId)
|
||||
|
||||
private companion object {
|
||||
val MOCK_SUMMARY = CashbackSummary.Enabled(
|
||||
displayMode = CashbackDisplayMode.FULL,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
package com.tangem.data.pay.store
|
||||
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.domain.visa.model.TangemPayAuthTokens
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val MOCK_CUSTOMER_WALLET_ADDRESS = "0x0000000000000000000000000000000000000002"
|
||||
private const val MOCK_ACCESS_TOKEN = "mock-access-token"
|
||||
private const val MOCK_REFRESH_TOKEN = "mock-refresh-token"
|
||||
private const val MOCK_IDEMPOTENCY_KEY = "mock-idempotency-key"
|
||||
private const val MOCK_TOKEN_EXPIRES_AT = 9_999_999_999L
|
||||
|
||||
/** In MOCK env returns synthetic auth tokens + customer wallet address; otherwise delegates. */
|
||||
@Singleton
|
||||
internal class MockAwareTangemPayStorage @Inject constructor(
|
||||
private val real: DefaultTangemPayStorage,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
) : TangemPayStorage {
|
||||
|
||||
private val isMockMode: Boolean
|
||||
get() = apiConfigsManager
|
||||
.getEnvironmentConfig(ApiConfig.ID.TangemPay)
|
||||
.environment == ApiEnvironment.MOCK
|
||||
|
||||
override suspend fun storeCustomerWalletAddress(userWalletId: UserWalletId, customerWalletAddress: String) {
|
||||
if (isMockMode) return
|
||||
real.storeCustomerWalletAddress(userWalletId, customerWalletAddress)
|
||||
}
|
||||
|
||||
override suspend fun getCustomerWalletAddress(userWalletId: UserWalletId): String? {
|
||||
if (isMockMode) return MOCK_CUSTOMER_WALLET_ADDRESS
|
||||
return real.getCustomerWalletAddress(userWalletId)
|
||||
}
|
||||
|
||||
override suspend fun clearCustomerWalletAddress(userWalletId: UserWalletId) {
|
||||
if (isMockMode) return
|
||||
real.clearCustomerWalletAddress(userWalletId)
|
||||
}
|
||||
|
||||
override suspend fun storeAuthTokens(customerWalletAddress: String, tokens: TangemPayAuthTokens) {
|
||||
if (isMockMode) return
|
||||
real.storeAuthTokens(customerWalletAddress, tokens)
|
||||
}
|
||||
|
||||
override suspend fun getAuthTokens(customerWalletAddress: String): TangemPayAuthTokens? {
|
||||
if (isMockMode) {
|
||||
return TangemPayAuthTokens(
|
||||
accessToken = MOCK_ACCESS_TOKEN,
|
||||
expiresAt = MOCK_TOKEN_EXPIRES_AT,
|
||||
refreshToken = MOCK_REFRESH_TOKEN,
|
||||
refreshExpiresAt = MOCK_TOKEN_EXPIRES_AT,
|
||||
idempotencyKey = MOCK_IDEMPOTENCY_KEY,
|
||||
)
|
||||
}
|
||||
return real.getAuthTokens(customerWalletAddress)
|
||||
}
|
||||
|
||||
override suspend fun clearAuthTokens(customerWalletAddress: String) {
|
||||
if (isMockMode) return
|
||||
real.clearAuthTokens(customerWalletAddress)
|
||||
}
|
||||
|
||||
override suspend fun storeOrderId(customerWalletAddress: String, orderId: String) =
|
||||
real.storeOrderId(customerWalletAddress, orderId)
|
||||
|
||||
override suspend fun getOrderId(customerWalletAddress: String): String? =
|
||||
real.getOrderId(customerWalletAddress)
|
||||
|
||||
override suspend fun getAddToWalletDone(customerWalletAddress: String): Boolean =
|
||||
real.getAddToWalletDone(customerWalletAddress)
|
||||
|
||||
override suspend fun storeAddToWalletDone(customerWalletAddress: String, isDone: Boolean) =
|
||||
real.storeAddToWalletDone(customerWalletAddress, isDone)
|
||||
|
||||
override suspend fun getCashbackDeactivationDismissed(customerWalletAddress: String): Boolean =
|
||||
real.getCashbackDeactivationDismissed(customerWalletAddress)
|
||||
|
||||
override suspend fun storeCashbackDeactivationDismissed(customerWalletAddress: String, isDismissed: Boolean) =
|
||||
real.storeCashbackDeactivationDismissed(customerWalletAddress, isDismissed)
|
||||
|
||||
override suspend fun clearOrderId(customerWalletAddress: String) =
|
||||
real.clearOrderId(customerWalletAddress)
|
||||
|
||||
override suspend fun storeVirtualAccountOrderId(customerWalletAddress: String, vaOrderId: String) =
|
||||
real.storeVirtualAccountOrderId(customerWalletAddress, vaOrderId)
|
||||
|
||||
override suspend fun getVirtualAccountOrderId(customerWalletAddress: String): String? =
|
||||
real.getVirtualAccountOrderId(customerWalletAddress)
|
||||
|
||||
override suspend fun clearVirtualAccountOrderId(customerWalletAddress: String) =
|
||||
real.clearVirtualAccountOrderId(customerWalletAddress)
|
||||
|
||||
override suspend fun storeCheckCustomerWalletResult(userWalletId: UserWalletId, isPaeraCustomer: Boolean) =
|
||||
real.storeCheckCustomerWalletResult(userWalletId, isPaeraCustomer)
|
||||
|
||||
override suspend fun checkCustomerWalletResult(userWalletId: UserWalletId): Boolean? =
|
||||
real.checkCustomerWalletResult(userWalletId)
|
||||
|
||||
override suspend fun storeActiveWithdrawOrderId(userWalletId: UserWalletId, orderId: String) =
|
||||
real.storeActiveWithdrawOrderId(userWalletId, orderId)
|
||||
|
||||
override suspend fun storeWithdrawOrder(userWalletId: UserWalletId, data: TangemPayWithdrawState) =
|
||||
real.storeWithdrawOrder(userWalletId, data)
|
||||
|
||||
override suspend fun getActiveWithdrawOrderId(userWalletId: UserWalletId): String? =
|
||||
real.getActiveWithdrawOrderId(userWalletId)
|
||||
|
||||
override suspend fun getWithdrawOrders(userWalletId: UserWalletId): List<TangemPayWithdrawState>? =
|
||||
real.getWithdrawOrders(userWalletId)
|
||||
|
||||
override suspend fun deleteActiveWithdrawOrder(userWalletId: UserWalletId) =
|
||||
real.deleteActiveWithdrawOrder(userWalletId)
|
||||
|
||||
override suspend fun deleteWithdrawOrder(userWalletId: UserWalletId, orderId: String) =
|
||||
real.deleteWithdrawOrder(userWalletId, orderId)
|
||||
|
||||
override suspend fun storeHideOnboardingBanner(userWalletId: UserWalletId, hide: Boolean) =
|
||||
real.storeHideOnboardingBanner(userWalletId, hide)
|
||||
|
||||
override suspend fun getHideMainOnboardingBanner(userWalletId: UserWalletId): Boolean =
|
||||
real.getHideMainOnboardingBanner(userWalletId)
|
||||
|
||||
override suspend fun storeTangemPayEligibility(eligibility: Set<String>) =
|
||||
real.storeTangemPayEligibility(eligibility)
|
||||
|
||||
override suspend fun getTangemPayEligibility(): Set<String> = real.getTangemPayEligibility()
|
||||
|
||||
override suspend fun storeIsTangemPayDeactivated(userWalletId: UserWalletId) =
|
||||
real.storeIsTangemPayDeactivated(userWalletId)
|
||||
|
||||
override suspend fun isTangemPayDeactivated(userWalletId: UserWalletId): Boolean =
|
||||
real.isTangemPayDeactivated(userWalletId)
|
||||
|
||||
override suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String) =
|
||||
real.clearAll(userWalletId, customerWalletAddress)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.data.pay.store.di
|
||||
|
||||
import com.tangem.data.pay.store.MockAwareTangemPayStorage
|
||||
import com.tangem.data.pay.store.TangemPayStorage
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface TangemPayStorageMockedModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemPayStorage(impl: MockAwareTangemPayStorage): TangemPayStorage
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.data.pay.store.di
|
||||
|
||||
import com.tangem.data.pay.store.DefaultTangemPayStorage
|
||||
import com.tangem.data.pay.store.TangemPayStorage
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface TangemPayStorageProductionModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemPayStorage(impl: DefaultTangemPayStorage): TangemPayStorage
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import com.tangem.datasource.api.pay.TangemPayApi
|
|||
import com.tangem.datasource.api.pay.models.response.WithdrawDataResponse
|
||||
import com.tangem.datasource.api.pay.models.response.WithdrawResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.data.pay.store.TangemPayStorage
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue