Updated on 2026-08-14
This commit is contained in:
parent
328271bc26
commit
8b6944e3e4
31 changed files with 1464 additions and 818 deletions
|
|
@ -29,4 +29,6 @@ fun String.toQrCode(sizePx: Int = 256, paddingPx: Int = 0): Bitmap {
|
|||
}
|
||||
}
|
||||
return bmp
|
||||
}
|
||||
}
|
||||
|
||||
fun String.capitalize(): String = replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
|
||||
|
|
@ -59,11 +59,7 @@ object DateTimeFormatters {
|
|||
DateTimeFormat.forPattern("dd.MM.yyyy HH:mm")
|
||||
}
|
||||
|
||||
fun formatTime(formatter: DateTimeFormatter = timeFormatter, time: DateTime): String {
|
||||
return formatter.print(time)
|
||||
}
|
||||
|
||||
fun formatDate(formatter: DateTimeFormatter = dateFormatter, date: DateTime): String {
|
||||
fun formatDate(date: DateTime, formatter: DateTimeFormatter = dateFormatter): String {
|
||||
return formatter.print(date)
|
||||
}
|
||||
}
|
||||
|
|
@ -29,5 +29,5 @@ fun Long.toDateFormat(formatter: DateTimeFormatter = DateTimeFormatters.dateForm
|
|||
* Returns formatted time according to [formatter].
|
||||
*/
|
||||
fun Long.toTimeFormat(formatter: DateTimeFormatter = DateTimeFormatters.timeFormatter): String {
|
||||
return DateTimeFormatters.formatTime(formatter = formatter, time = DateTime(this, DateTimeZone.getDefault()))
|
||||
return DateTimeFormatters.formatDate(date = DateTime(this, DateTimeZone.getDefault()), formatter = formatter)
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ dependencies {
|
|||
implementation(projects.domain.legacy)
|
||||
|
||||
/** Project - Libs */
|
||||
implementation(projects.libs.visa)
|
||||
debugImplementation(projects.libs.visa)
|
||||
|
||||
/** Libs - Other */
|
||||
implementation(deps.kotlin.coroutines)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ internal class DefaultVisaRepository(
|
|||
|
||||
override suspend fun getVisaCurrency(userWalletId: UserWalletId, isRefresh: Boolean): VisaCurrency {
|
||||
val address = makeAddress(userWalletId)
|
||||
// val address = "0x143fe062a538176aa0bf162f13d390208f90898f" // for testing
|
||||
// val address = "0x40d8194b7168723ece51fa34d16825c60ba03dfa" // for testing
|
||||
|
||||
fetchVisaCurrencyIfExpired(address, isRefresh)
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ internal class DefaultVisaRepository(
|
|||
): Flow<PagingData<VisaTxHistoryItem>> {
|
||||
val userWallet = findVisaUserWallet(userWalletId)
|
||||
val cardPubKey = getCardPubKey(userWallet).toHexString()
|
||||
// val cardPubKey = "03DEF02B1FECC8BD3CFD52CE93235194479E1DE931EF0F55DC194967E7CCC3D12C" // for testing
|
||||
// val cardPubKey = "02C2BBA0DA1E066EA968C1EB129499F6DEBC5FD82D70D61DCAF691CDB69AF5D8B9" // for testing
|
||||
val pager = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = pageSize,
|
||||
|
|
@ -125,7 +125,7 @@ internal class DefaultVisaRepository(
|
|||
return withContext(dispatchers.io) {
|
||||
val userWallet = findVisaUserWallet(userWalletId)
|
||||
val cardPubKey = getCardPubKey(userWallet).toHexString()
|
||||
// val cardPubKey = "03DEF02B1FECC8BD3CFD52CE93235194479E1DE931EF0F55DC194967E7CCC3D12C" // for testing
|
||||
// val cardPubKey = "02C2BBA0DA1E066EA968C1EB129499F6DEBC5FD82D70D61DCAF691CDB69AF5D8B9" // for testing
|
||||
val transaction = fetchedHistoryItems.value[cardPubKey]?.firstOrNull {
|
||||
it.transactionId.toString() == txId
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.tangem.data.visa.di
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.visa.BuildConfig
|
||||
import com.tangem.data.visa.DefaultVisaRepository
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import com.tangem.lib.visa.VisaContractInfoProvider
|
||||
import com.tangem.lib.visa.api.VisaApiBuilder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object ImplementedVisaDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@ImplementedVisaRepository
|
||||
fun provideVisaRepository(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
tangemTechApi: TangemTechApi,
|
||||
cacheRegistry: CacheRegistry,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): VisaRepository {
|
||||
val contractInfoProvider = VisaContractInfoProvider.Builder(
|
||||
isNetworkLoggingEnabled = BuildConfig.LOG_ENABLED,
|
||||
dispatchers = dispatchers,
|
||||
).build()
|
||||
val visaApi = VisaApiBuilder(
|
||||
useDevApi = true,
|
||||
isNetworkLoggingEnabled = BuildConfig.LOG_ENABLED,
|
||||
moshi = moshi,
|
||||
).build()
|
||||
|
||||
return DefaultVisaRepository(
|
||||
contractInfoProvider,
|
||||
tangemTechApi,
|
||||
visaApi,
|
||||
cacheRegistry,
|
||||
userWalletsStore,
|
||||
dispatchers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ internal class VisaCurrencyFactory {
|
|||
} else {
|
||||
balancesAndLimits.newLimits
|
||||
}
|
||||
val remainingOtpLimit = getRemainingOtp(currentLimit, now)
|
||||
|
||||
return VisaCurrency(
|
||||
symbol = VisaConfig.TOKEN_SYMBOL,
|
||||
|
|
@ -35,8 +36,8 @@ internal class VisaCurrencyFactory {
|
|||
)
|
||||
},
|
||||
limits = VisaCurrency.Limits(
|
||||
remainingOtp = getRemainingOtp(currentLimit, now),
|
||||
remainingNoOtp = getRemainingNoOtp(currentLimit, now),
|
||||
remainingOtp = remainingOtpLimit,
|
||||
remainingNoOtp = minOf(remainingOtpLimit, getRemainingNoOtp(currentLimit, now)),
|
||||
singleTransaction = currentLimit.singleTransactionLimit,
|
||||
expirationDate = getLimitsExpirationDate(currentLimit, now),
|
||||
),
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.data.visa
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.visa.model.VisaTxDetails
|
||||
import com.tangem.domain.visa.model.VisaTxHistoryItem
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
internal class DummyVisaRepository : VisaRepository {
|
||||
|
||||
override suspend fun getVisaCurrency(userWalletId: UserWalletId, isRefresh: Boolean): VisaCurrency {
|
||||
TODO("Not implemented for this build type")
|
||||
}
|
||||
|
||||
override suspend fun getTxHistory(
|
||||
userWalletId: UserWalletId,
|
||||
pageSize: Int,
|
||||
isRefresh: Boolean,
|
||||
): Flow<PagingData<VisaTxHistoryItem>> {
|
||||
TODO("Not implemented for this build type")
|
||||
}
|
||||
|
||||
override suspend fun getTxDetails(userWalletId: UserWalletId, txId: String): VisaTxDetails {
|
||||
TODO("Not implemented for this build type")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.data.visa.di
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Qualifier
|
||||
internal annotation class ImplementedVisaRepository
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.data.visa.di
|
||||
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import dagger.BindsOptionalOf
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ImplementedVisaRepositoryModule {
|
||||
|
||||
@BindsOptionalOf
|
||||
@ImplementedVisaRepository
|
||||
fun bindImplementedVisaRepository(): VisaRepository
|
||||
}
|
||||
|
|
@ -1,21 +1,14 @@
|
|||
package com.tangem.data.visa.di
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.visa.BuildConfig
|
||||
import com.tangem.data.visa.DefaultVisaRepository
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.data.visa.DummyVisaRepository
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import com.tangem.lib.visa.VisaContractInfoProvider
|
||||
import com.tangem.lib.visa.api.VisaApiBuilder
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import java.util.Optional
|
||||
import javax.inject.Singleton
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
|
|
@ -24,29 +17,8 @@ internal object VisaDataModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideVisaRepository(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
tangemTechApi: TangemTechApi,
|
||||
cacheRegistry: CacheRegistry,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
@ImplementedVisaRepository implementedVisaRepository: Optional<VisaRepository>,
|
||||
): VisaRepository {
|
||||
val contractInfoProvider = VisaContractInfoProvider.Builder(
|
||||
isNetworkLoggingEnabled = BuildConfig.LOG_ENABLED,
|
||||
dispatchers = dispatchers,
|
||||
).build()
|
||||
val visaApi = VisaApiBuilder(
|
||||
useDevApi = true,
|
||||
isNetworkLoggingEnabled = BuildConfig.LOG_ENABLED,
|
||||
moshi = moshi,
|
||||
).build()
|
||||
|
||||
return DefaultVisaRepository(
|
||||
contractInfoProvider,
|
||||
tangemTechApi,
|
||||
visaApi,
|
||||
cacheRegistry,
|
||||
userWalletsStore,
|
||||
dispatchers,
|
||||
)
|
||||
return implementedVisaRepository.getOrNull() ?: DummyVisaRepository()
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ internal data class BalancesAndLimitsBottomSheetConfig(
|
|||
|
||||
data class Limit(
|
||||
val availableBy: String,
|
||||
val inStore: String,
|
||||
val total: String,
|
||||
val other: String,
|
||||
val singleTransaction: String,
|
||||
val onInfoClick: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -48,19 +48,32 @@ internal sealed interface WalletAlertState {
|
|||
override val isWarningConfirmButton: Boolean = true
|
||||
}
|
||||
|
||||
object WrongCardIsScanned : Basic() {
|
||||
data class VisaLimitsInfo(
|
||||
val totalLimit: String,
|
||||
val otherLimit: String,
|
||||
) : Basic() {
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference = stringReference(
|
||||
value = "Limits are needed to control costs, improve security, manage risk. " +
|
||||
"You can spend $totalLimit during the week for card payments in shops and " +
|
||||
"$otherLimit for other transactions, e. g. subscriptions or debts.",
|
||||
)
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
}
|
||||
|
||||
data object WrongCardIsScanned : Basic() {
|
||||
override val title: TextReference = resourceReference(R.string.common_warning)
|
||||
override val message: TextReference = resourceReference(R.string.error_wrong_wallet_tapped)
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
}
|
||||
|
||||
object RescanWallets : Basic() {
|
||||
data object RescanWallets : Basic() {
|
||||
override val title: TextReference = resourceReference(R.string.common_attention)
|
||||
override val message: TextReference = resourceReference(R.string.key_invalidated_warning_description)
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
}
|
||||
|
||||
object VisaBalancesInfo : Basic() {
|
||||
data object VisaBalancesInfo : Basic() {
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference = stringReference(
|
||||
value = "Available balance is actual funds available, considering pending transactions, " +
|
||||
|
|
@ -68,14 +81,4 @@ internal sealed interface WalletAlertState {
|
|||
)
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
}
|
||||
|
||||
object VisaLimitsInfo : Basic() {
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference = stringReference(
|
||||
value = "Limits are needed to control costs, improve security, manage risk. " +
|
||||
"You can spend 1 000 USDT during the week for card payments in shops and " +
|
||||
"100 USDT for other transactions, e. g. subscriptions or debts.",
|
||||
)
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,9 @@ internal class BalancesAndLimitsBottomSheetConverter(
|
|||
decimals = value.decimals,
|
||||
)
|
||||
|
||||
val otpLimit = value.limits.remainingOtp.let(::formatAmount)
|
||||
val noOtpLimit = value.limits.remainingNoOtp.let(::formatAmount)
|
||||
|
||||
return BalancesAndLimitsBottomSheetConfig(
|
||||
balance = BalancesAndLimitsBottomSheetConfig.Balance(
|
||||
totalBalance = value.balances.total.let(::formatAmount),
|
||||
|
|
@ -33,10 +36,10 @@ internal class BalancesAndLimitsBottomSheetConverter(
|
|||
),
|
||||
limit = BalancesAndLimitsBottomSheetConfig.Limit(
|
||||
availableBy = DateTimeFormatters.formatDate(date = value.limits.expirationDate),
|
||||
inStore = value.limits.remainingOtp.let(::formatAmount),
|
||||
other = value.limits.remainingNoOtp.let(::formatAmount),
|
||||
total = otpLimit,
|
||||
other = noOtpLimit,
|
||||
singleTransaction = value.limits.singleTransaction.let(::formatAmount),
|
||||
onInfoClick = this::showLimitInfo,
|
||||
onInfoClick = { showLimitInfo(otpLimit, noOtpLimit) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -45,7 +48,7 @@ internal class BalancesAndLimitsBottomSheetConverter(
|
|||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaBalancesInfo))
|
||||
}
|
||||
|
||||
private fun showLimitInfo() {
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaLimitsInfo))
|
||||
private fun showLimitInfo(totalLimit: String, otherLimit: String) {
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaLimitsInfo(totalLimit, otherLimit)))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
|
||||
|
||||
import com.tangem.core.ui.extensions.capitalize
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
|
|
@ -27,14 +28,14 @@ internal class VisaTxDetailsBottomSheetConverter(
|
|||
private fun createTransaction(details: VisaTxDetails): VisaTxDetailsBottomSheetConfig.Transaction {
|
||||
return VisaTxDetailsBottomSheetConfig.Transaction(
|
||||
id = details.id,
|
||||
type = details.type,
|
||||
status = details.status,
|
||||
type = details.type.capitalize(),
|
||||
status = details.status.capitalize(),
|
||||
blockchainAmount = formatNetworkAmount(details.blockchainAmount),
|
||||
blockchainFee = formatNetworkAmount(details.blockchainFee),
|
||||
transactionAmount = formatFiatAmount(details.transactionAmount, details.fiatCurrency),
|
||||
transactionCurrencyCode = details.transactionCurrencyCode.toString(),
|
||||
merchantName = details.merchantName ?: UNKNOWN,
|
||||
merchantCity = details.merchantCity ?: UNKNOWN,
|
||||
merchantName = details.merchantName?.capitalize() ?: UNKNOWN,
|
||||
merchantCity = details.merchantCity?.capitalize() ?: UNKNOWN,
|
||||
merchantCountryCode = details.merchantCountryCode ?: UNKNOWN,
|
||||
merchantCategoryCode = details.merchantCategoryCode ?: UNKNOWN,
|
||||
)
|
||||
|
|
@ -46,16 +47,16 @@ internal class VisaTxDetailsBottomSheetConverter(
|
|||
|
||||
return VisaTxDetailsBottomSheetConfig.Request(
|
||||
id = request.id,
|
||||
type = request.requestType,
|
||||
status = request.requestStatus,
|
||||
type = request.requestType.capitalize(),
|
||||
status = request.requestStatus.capitalize(),
|
||||
blockchainAmount = formatNetworkAmount(request.blockchainAmount),
|
||||
blockchainFee = formatNetworkAmount(request.blockchainFee),
|
||||
transactionAmount = formatFiatAmount(request.transactionAmount, request.fiatCurrency),
|
||||
currencyCode = request.billingCurrencyCode.toString(),
|
||||
errorCode = request.errorCode,
|
||||
date = DateTimeFormatters.formatDate(DateTimeFormatters.dateTimeFormatter, date = localDate),
|
||||
date = DateTimeFormatters.formatDate(localDate, DateTimeFormatters.dateTimeFormatter),
|
||||
txHash = request.txHash ?: UNKNOWN,
|
||||
txStatus = request.txStatus ?: UNKNOWN,
|
||||
txStatus = request.txStatus?.capitalize() ?: UNKNOWN,
|
||||
onExploreClick = if (exploreUrl != null) {
|
||||
{ clickIntents.onExploreClick(exploreUrl) }
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
|
||||
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionState
|
||||
import com.tangem.core.ui.extensions.capitalize
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
|
|
@ -18,8 +19,8 @@ internal class VisaTxHistoryItemStateConverter(
|
|||
|
||||
override fun convert(value: VisaTxHistoryItem): TransactionState {
|
||||
val localDate = value.date.withZone(DateTimeZone.getDefault())
|
||||
val time = DateTimeFormatters.formatTime(time = localDate)
|
||||
val subtitle = "$time • ${value.status}"
|
||||
val time = DateTimeFormatters.formatDate(localDate, DateTimeFormatters.timeFormatter)
|
||||
val subtitle = "$time • ${value.status.capitalize()}"
|
||||
|
||||
return TransactionState.Content(
|
||||
txHash = value.id,
|
||||
|
|
@ -37,7 +38,7 @@ internal class VisaTxHistoryItemStateConverter(
|
|||
status = TransactionState.Content.Status.Confirmed,
|
||||
direction = TransactionState.Content.Direction.INCOMING,
|
||||
iconRes = R.drawable.ic_arrow_up_24,
|
||||
title = stringReference(value = value.merchantName ?: "Unknown merchant"),
|
||||
title = stringReference(value = value.merchantName?.capitalize() ?: "Unknown merchant"),
|
||||
subtitle = stringReference(subtitle),
|
||||
timestamp = localDate.millis,
|
||||
onClick = { clickIntents.onVisaTransactionClick(value.id) },
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ internal class VisaWalletSubscriber(
|
|||
setLoadedCurrencyState(maybeCurrency)
|
||||
|
||||
val currency = maybeCurrency.getOrElse {
|
||||
Timber.e(it, "Failed to load VISA currency")
|
||||
setFailedTxHistoryState(it)
|
||||
return@flow
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ import androidx.compose.animation.AnimatedContent
|
|||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -60,7 +63,6 @@ private fun BalancesAndLimitsBlock(state: BalancesAndLimitsBlockState, modifier:
|
|||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private inline fun ContentContainer(
|
||||
enabled: Boolean,
|
||||
|
|
@ -147,7 +149,7 @@ private fun AvailableLimit(availableBalance: String, limitDays: Int, modifier: M
|
|||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = "available $limitDays-day limit",
|
||||
text = "available for $limitDays day(s)",
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ private fun LimitsBlock(limits: BalancesAndLimitsBottomSheetConfig.Limit, modifi
|
|||
title = stringReference("Limits"),
|
||||
content = {
|
||||
BlockItem(
|
||||
title = stringReference("In-store (otp)"),
|
||||
value = limits.inStore,
|
||||
title = stringReference("Total"),
|
||||
value = limits.total,
|
||||
)
|
||||
BlockItem(
|
||||
title = stringReference("Other (no-otp)"),
|
||||
|
|
@ -193,7 +193,7 @@ private class BalancesAndLimitsBottomSheetParameterProvider :
|
|||
),
|
||||
limit = BalancesAndLimitsBottomSheetConfig.Limit(
|
||||
availableBy = "Nov, 11 USDT",
|
||||
inStore = "563.00 USDT",
|
||||
total = "563.00 USDT",
|
||||
other = "100.00 USDT",
|
||||
singleTransaction = "100.00 USDT",
|
||||
onInfoClick = {},
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@ package com.tangem.lib.visa;
|
|||
|
||||
import org.web3j.abi.EventEncoder;
|
||||
import org.web3j.abi.TypeReference;
|
||||
import org.web3j.abi.datatypes.Address;
|
||||
import org.web3j.abi.datatypes.Event;
|
||||
import org.web3j.abi.datatypes.Function;
|
||||
import org.web3j.abi.datatypes.Utf8String;
|
||||
import org.web3j.abi.datatypes.*;
|
||||
import org.web3j.abi.datatypes.generated.Uint256;
|
||||
import org.web3j.abi.datatypes.generated.Uint8;
|
||||
import org.web3j.crypto.Credentials;
|
||||
|
|
@ -32,10 +29,10 @@ import io.reactivex.Flowable;
|
|||
* <p>Auto generated code.
|
||||
* <p><strong>Do not modify!</strong>
|
||||
* <p>Please use the <a href="https://docs.web3j.io/command_line.html">web3j command line tools</a>,
|
||||
* or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the
|
||||
* or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the
|
||||
* <a href="https://github.com/web3j/web3j/tree/master/codegen">codegen module</a> to update.
|
||||
*
|
||||
* <p>Generated with web3j version 1.5.0.
|
||||
* <p>Generated with web3j version 1.5.2.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
class ERC20 extends Contract {
|
||||
|
|
@ -113,6 +110,16 @@ class ERC20 extends Contract {
|
|||
return typedResponse;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
return new ERC20(contractAddress, web3j, credentials, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
return new ERC20(contractAddress, web3j, transactionManager, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
public static List<TransferEventResponse> getTransferEvents(TransactionReceipt transactionReceipt) {
|
||||
List<EventValuesWithLog> valueList = staticExtractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt);
|
||||
ArrayList<TransferEventResponse> responses = new ArrayList<TransferEventResponse>(valueList.size());
|
||||
|
|
@ -127,16 +134,6 @@ class ERC20 extends Contract {
|
|||
return responses;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
return new ERC20(contractAddress, web3j, credentials, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
return new ERC20(contractAddress, web3j, transactionManager, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
public static TransferEventResponse getTransferEventFromLog(Log log) {
|
||||
EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSFER_EVENT, log);
|
||||
TransferEventResponse typedResponse = new TransferEventResponse();
|
||||
|
|
@ -147,14 +144,6 @@ class ERC20 extends Contract {
|
|||
return typedResponse;
|
||||
}
|
||||
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
|
||||
return new ERC20(contractAddress, web3j, credentials, contractGasProvider);
|
||||
}
|
||||
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
|
||||
return new ERC20(contractAddress, web3j, transactionManager, contractGasProvider);
|
||||
}
|
||||
|
||||
public Flowable<TransferEventResponse> transferEventFlowable(EthFilter filter) {
|
||||
return web3j.ethLogFlowable(filter).map(log -> getTransferEventFromLog(log));
|
||||
}
|
||||
|
|
@ -165,6 +154,14 @@ class ERC20 extends Contract {
|
|||
return transferEventFlowable(filter);
|
||||
}
|
||||
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
|
||||
return new ERC20(contractAddress, web3j, credentials, contractGasProvider);
|
||||
}
|
||||
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
|
||||
return new ERC20(contractAddress, web3j, transactionManager, contractGasProvider);
|
||||
}
|
||||
|
||||
public Flowable<ApprovalEventResponse> approvalEventFlowable(EthFilter filter) {
|
||||
return web3j.ethLogFlowable(filter).map(log -> getApprovalEventFromLog(log));
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -7,7 +7,6 @@ import com.tangem.lib.visa.model.VisaBalancesAndLimits.Limits
|
|||
import com.tangem.lib.visa.utils.toBigDecimal
|
||||
import com.tangem.lib.visa.utils.toInstant
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.joda.time.Instant
|
||||
import org.web3j.protocol.Web3j
|
||||
import org.web3j.tx.TransactionManager
|
||||
|
|
@ -18,39 +17,40 @@ internal class DefaultVisaContractInfoProvider(
|
|||
private val transactionManager: TransactionManager,
|
||||
private val gasProvider: ContractGasProvider,
|
||||
private val bridgeProcessorAddress: String,
|
||||
private val paymentAccountRegistryAddress: String,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : VisaContractInfoProvider {
|
||||
|
||||
override suspend fun getBalancesAndLimits(walletAddress: String): VisaBalancesAndLimits {
|
||||
return withContext(dispatchers.io) {
|
||||
val tangemBridgeProcessor = TangemBridgeProcessor.load(
|
||||
/* contractAddress = */ bridgeProcessorAddress,
|
||||
/* web3j = */ web3j,
|
||||
/* transactionManager = */ transactionManager,
|
||||
/* contractGasProvider = */ gasProvider,
|
||||
)
|
||||
|
||||
parZip(
|
||||
dispatchers.io,
|
||||
{ loadPaymentAccount(walletAddress, tangemBridgeProcessor) },
|
||||
{ loadPaymentTokenInfo(tangemBridgeProcessor) },
|
||||
{ paymentAccount, paymentToken ->
|
||||
fetchBalancesAndLimits(paymentAccount, paymentToken)
|
||||
},
|
||||
)
|
||||
}
|
||||
return parZip(
|
||||
dispatchers.io,
|
||||
{ loadPaymentAccount(walletAddress) },
|
||||
{ loadPaymentTokenInfo() },
|
||||
{ paymentAccount, paymentToken ->
|
||||
fetchBalancesAndLimits(paymentAccount, paymentToken)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadPaymentAccount(
|
||||
walletAddress: String,
|
||||
tangemBridgeProcessor: TangemBridgeProcessor,
|
||||
): TangemPaymentAccount {
|
||||
val paymentAccountAddress = tangemBridgeProcessor.getPaymentAccount(walletAddress).send()
|
||||
private fun loadPaymentAccount(walletAddress: String): TangemPaymentAccount {
|
||||
val paymentAccountRegistry = TangemPaymentAccountRegistry.load(
|
||||
/* contractAddress = */ paymentAccountRegistryAddress,
|
||||
/* web3j = */ web3j,
|
||||
/* transactionManager = */ transactionManager,
|
||||
/* contractGasProvider = */ gasProvider,
|
||||
)
|
||||
val paymentAccountAddress = paymentAccountRegistry.paymentAccountByCard(walletAddress).send()
|
||||
|
||||
return TangemPaymentAccount.load(paymentAccountAddress, web3j, transactionManager, gasProvider)
|
||||
}
|
||||
|
||||
private fun loadPaymentTokenInfo(tangemBridgeProcessor: TangemBridgeProcessor): PaymentTokenInfo {
|
||||
private fun loadPaymentTokenInfo(): PaymentTokenInfo {
|
||||
val tangemBridgeProcessor = TangemBridgeProcessor.load(
|
||||
/* contractAddress = */ bridgeProcessorAddress,
|
||||
/* web3j = */ web3j,
|
||||
/* transactionManager = */ transactionManager,
|
||||
/* contractGasProvider = */ gasProvider,
|
||||
)
|
||||
val paymentTokenContractAddress = tangemBridgeProcessor.paymentToken().send()
|
||||
val paymentTokenContract = ERC20.load(paymentTokenContractAddress, web3j, transactionManager, gasProvider)
|
||||
val paymentTokenDecimals = paymentTokenContract.decimals().send()
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ interface VisaContractInfoProvider {
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val baseUrl: String = VisaConfig.BASE_RPC_URL,
|
||||
private val bridgeProcessorAddress: String = VisaConfig.BRIDGE_PROCESSOR_CONTRACT_ADDRESS,
|
||||
private val paymentAccountRegistryAddress: String = VisaConfig.PAYMENT_ACCOUNT_REGISTRY_ADDRESS,
|
||||
private val chainId: Long = VisaConfig.CHAIN_ID,
|
||||
private val networkTimeoutSeconds: Long = VisaConfig.NETWORK_TIMEOUT_SECONDS,
|
||||
private val decimals: Int = VisaConfig.DECIMALS,
|
||||
|
|
@ -45,6 +46,7 @@ interface VisaContractInfoProvider {
|
|||
transactionManager = transactionManager,
|
||||
gasProvider = gasProvider,
|
||||
bridgeProcessorAddress = bridgeProcessorAddress,
|
||||
paymentAccountRegistryAddress = paymentAccountRegistryAddress,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ package com.tangem.lib.visa.utils
|
|||
|
||||
internal object VisaConfig {
|
||||
|
||||
const val BASE_RPC_URL = "https://rpc-mumbai.maticvigil.com/"
|
||||
const val BRIDGE_PROCESSOR_CONTRACT_ADDRESS = "0x62119697e78178512bfcc456ae6d1b7dee9fbaa6"
|
||||
const val BASE_RPC_URL = "https://polygon-mumbai.g.alchemy.com/v2/_1qqjXgBC_IikaXChnna8KTcV2eMMIQG/"
|
||||
const val BRIDGE_PROCESSOR_CONTRACT_ADDRESS = "0xe32ecbbc1ec17fa9c160569cd613ad568ca50279"
|
||||
const val PAYMENT_ACCOUNT_REGISTRY_ADDRESS = "0x3f4ae01073d1a9d5a92315fe118e57d1cdec7c44"
|
||||
const val CHAIN_ID = 80_001L
|
||||
const val DECIMALS = 9
|
||||
const val GAS_LIMIT = 500_000_000L
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue