diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt b/data/visa/src/debug/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt index 89752a8b76..a817781b53 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt +++ b/data/visa/src/debug/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt @@ -7,6 +7,7 @@ import arrow.fx.coroutines.parZip import com.tangem.blockchain.common.address.Address import com.tangem.blockchain.common.address.AddressType import com.tangem.common.card.EllipticCurve +import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.visa.utils.VisaConfig @@ -58,7 +59,6 @@ internal class DefaultVisaRepository( override suspend fun getVisaCurrency(userWalletId: UserWalletId, isRefresh: Boolean): VisaCurrency { val address = makeAddress(userWalletId) - // val address = "0x40d8194b7168723ece51fa34d16825c60ba03dfa" // for testing fetchVisaCurrencyIfExpired(address, isRefresh) @@ -69,7 +69,7 @@ internal class DefaultVisaRepository( private suspend fun fetchVisaCurrencyIfExpired(address: String, isRefresh: Boolean) { cacheRegistry.invokeOnExpire( - key = getBalancesAndLimitsKey(address), + key = getVisaCurrencyKey(address), skipCache = isRefresh, block = { fetchVisaCurrency(address) }, ) @@ -78,12 +78,12 @@ internal class DefaultVisaRepository( private suspend fun fetchVisaCurrency(address: String) { parZip( dispatchers.io, - { visaContractInfoProvider.getBalancesAndLimits(address) }, + { visaContractInfoProvider.getContractInfo(address) }, { getFiatRate() }, - { balancesAndLimits, fiatRate -> + { contractInfo, fiatRate -> fetchedCurrencies.update { value -> value.apply { - put(address, currencyFactory.create(balancesAndLimits, fiatRate)) + put(address, currencyFactory.create(contractInfo, fiatRate)) } } }, @@ -96,8 +96,7 @@ internal class DefaultVisaRepository( isRefresh: Boolean, ): Flow> { val userWallet = findVisaUserWallet(userWalletId) - val cardPubKey = getCardPubKey(userWallet).toHexString() - // val cardPubKey = "02C2BBA0DA1E066EA968C1EB129499F6DEBC5FD82D70D61DCAF691CDB69AF5D8B9" // for testing + val cardPubKey = getCardPubKey(userWallet) val pager = Pager( config = PagingConfig( pageSize = pageSize, @@ -124,8 +123,7 @@ internal class DefaultVisaRepository( override suspend fun getTxDetails(userWalletId: UserWalletId, txId: String): VisaTxDetails { return withContext(dispatchers.io) { val userWallet = findVisaUserWallet(userWalletId) - val cardPubKey = getCardPubKey(userWallet).toHexString() - // val cardPubKey = "02C2BBA0DA1E066EA968C1EB129499F6DEBC5FD82D70D61DCAF691CDB69AF5D8B9" // for testing + val cardPubKey = getCardPubKey(userWallet) val transaction = fetchedHistoryItems.value[cardPubKey]?.firstOrNull { it.transactionId.toString() == txId } @@ -139,6 +137,8 @@ internal class DefaultVisaRepository( } private suspend fun makeAddress(userWalletId: UserWalletId): String { + if (IS_DEMO_MODE_ENABLED) return DEMO_ADDRESS + val userWallet = findVisaUserWallet(userWalletId) val walletAddresses = makeWalletAddresses(userWallet) val walletAddress = walletAddresses.firstOrNull { it.type == AddressType.Default } @@ -161,16 +161,18 @@ internal class DefaultVisaRepository( private fun makeWalletAddresses(userWallet: UserWallet): Set
{ val walletBlockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain() - return walletBlockchain.makeAddresses(getCardPubKey(userWallet)) + return walletBlockchain.makeAddresses(getCardPubKey(userWallet).hexToBytes()) } - private fun getCardPubKey(userWallet: UserWallet): ByteArray { + private fun getCardPubKey(userWallet: UserWallet): String { + if (IS_DEMO_MODE_ENABLED) return DEMO_PUBLIC_KEY + val cardWallet = userWallet.scanResponse.card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } requireNotNull(cardWallet) { "Secp256k1 card wallet not found" } - return cardWallet.publicKey + return cardWallet.publicKey.toHexString() } private suspend fun findVisaUserWallet(userWalletId: UserWalletId): UserWallet { @@ -184,7 +186,15 @@ internal class DefaultVisaRepository( return userWallet } - private fun getBalancesAndLimitsKey(address: String): String { - return "visa_balances_and_limits_$address" + private fun getVisaCurrencyKey(address: String): String { + return "visa_currency_$address" + } + + private companion object { + // Must be `false` in production + const val IS_DEMO_MODE_ENABLED = false + + const val DEMO_ADDRESS = "0x40d8194b7168723ece51fa34d16825c60ba03dfa" + const val DEMO_PUBLIC_KEY = "02C2BBA0DA1E066EA968C1EB129499F6DEBC5FD82D70D61DCAF691CDB69AF5D8B9" } } \ No newline at end of file diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaConfig.kt b/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaConfig.kt index e450a769cc..6b3e3f3f8b 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaConfig.kt +++ b/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaConfig.kt @@ -6,9 +6,7 @@ internal object VisaConfig { const val NETWORK_NAME = "Polygon PoS" - const val TOKEN_SYMBOL = "USDT" const val TOKEN_ID = "tether" - const val TOKEN_DECIMALS = 8 val fiatCurrency = AppCurrency( code = "EUR", diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt b/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt index 8f3e95d73a..3c9f55e37f 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt +++ b/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt @@ -1,7 +1,7 @@ package com.tangem.data.visa.utils import com.tangem.domain.visa.model.VisaCurrency -import com.tangem.lib.visa.model.VisaBalancesAndLimits +import com.tangem.lib.visa.model.VisaContractInfo import org.joda.time.DateTime import org.joda.time.DateTimeZone import org.joda.time.Instant @@ -10,22 +10,22 @@ import java.math.BigInteger internal class VisaCurrencyFactory { - fun create(balancesAndLimits: VisaBalancesAndLimits, fiatRate: BigDecimal?): VisaCurrency { + fun create(contractInfo: VisaContractInfo, fiatRate: BigDecimal?): VisaCurrency { val now = Instant.now() - val currentLimit = if (balancesAndLimits.limitsChangeDate > now) { - balancesAndLimits.oldLimits + val currentLimit = if (contractInfo.limitsChangeDate > now) { + contractInfo.oldLimits } else { - balancesAndLimits.newLimits + contractInfo.newLimits } val remainingOtpLimit = getRemainingOtp(currentLimit, now) return VisaCurrency( - symbol = VisaConfig.TOKEN_SYMBOL, + symbol = contractInfo.token.symbol, networkName = VisaConfig.NETWORK_NAME, - decimals = VisaConfig.TOKEN_DECIMALS, + decimals = contractInfo.token.decimals, fiatRate = fiatRate, fiatCurrency = VisaConfig.fiatCurrency, - balances = with(balancesAndLimits) { + balances = with(contractInfo) { VisaCurrency.Balances( total = balances.total, verified = balances.verified, @@ -44,7 +44,7 @@ internal class VisaCurrencyFactory { ) } - private fun getRemainingOtp(currentLimit: VisaBalancesAndLimits.Limits, now: Instant): BigDecimal { + private fun getRemainingOtp(currentLimit: VisaContractInfo.Limits, now: Instant): BigDecimal { if (currentLimit.expirationDate >= now) { return currentLimit.spendLimit.limit - currentLimit.spendLimit.spent } @@ -52,7 +52,7 @@ internal class VisaCurrencyFactory { return currentLimit.spendLimit.limit } - private fun getRemainingNoOtp(currentLimit: VisaBalancesAndLimits.Limits, now: Instant): BigDecimal { + private fun getRemainingNoOtp(currentLimit: VisaContractInfo.Limits, now: Instant): BigDecimal { if (currentLimit.expirationDate >= now) { return currentLimit.noOtpLimit.limit - currentLimit.noOtpLimit.spent } @@ -60,7 +60,7 @@ internal class VisaCurrencyFactory { return currentLimit.noOtpLimit.limit } - private fun getLimitsExpirationDate(currentLimits: VisaBalancesAndLimits.Limits, now: Instant): DateTime { + private fun getLimitsExpirationDate(currentLimits: VisaContractInfo.Limits, now: Instant): DateTime { val expirationDate = if (currentLimits.expirationDate >= now) { currentLimits.expirationDate.toDateTime() } else { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/VisaDepositButton.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/VisaDepositButton.kt index 30bb253d24..395e9499a4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/VisaDepositButton.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/VisaDepositButton.kt @@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.visa import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.ui.Modifier -import com.tangem.core.ui.components.SecondaryButtonIconStart +import com.tangem.core.ui.components.PrimaryButtonIconStart import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.wallet.state.model.DepositButtonState @@ -10,7 +10,7 @@ private const val DEPOSIT_BUTTON_CONTENT_TYPE = "DepositButton" internal fun LazyListScope.depositButton(state: DepositButtonState, modifier: Modifier = Modifier) { item(key = DEPOSIT_BUTTON_CONTENT_TYPE, contentType = DEPOSIT_BUTTON_CONTENT_TYPE) { - SecondaryButtonIconStart( + PrimaryButtonIconStart( modifier = modifier, text = "Deposit", iconResId = R.drawable.ic_arrow_down_24, diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt index 21989a9ee6..312f708435 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt +++ b/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt @@ -1,9 +1,8 @@ package com.tangem.lib.visa import arrow.fx.coroutines.parZip -import com.tangem.lib.visa.model.VisaBalancesAndLimits -import com.tangem.lib.visa.model.VisaBalancesAndLimits.Balances -import com.tangem.lib.visa.model.VisaBalancesAndLimits.Limits +import com.tangem.lib.visa.model.VisaContractInfo +import com.tangem.lib.visa.model.VisaContractInfo.* import com.tangem.lib.visa.utils.toBigDecimal import com.tangem.lib.visa.utils.toInstant import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -21,7 +20,7 @@ internal class DefaultVisaContractInfoProvider( private val dispatchers: CoroutineDispatcherProvider, ) : VisaContractInfoProvider { - override suspend fun getBalancesAndLimits(walletAddress: String): VisaBalancesAndLimits { + override suspend fun getContractInfo(walletAddress: String): VisaContractInfo { return parZip( dispatchers.io, { loadPaymentAccount(walletAddress) }, @@ -64,15 +63,35 @@ internal class DefaultVisaContractInfoProvider( private suspend fun fetchBalancesAndLimits( paymentAccount: TangemPaymentAccount, paymentToken: PaymentTokenInfo, - ): VisaBalancesAndLimits = parZip( + ): VisaContractInfo = parZip( dispatchers.io, + { fetchToken(paymentAccount) }, { fetchBalances(paymentAccount, paymentToken) }, { fetchLimits(paymentAccount, paymentToken) }, - { balances, (oldLimit, newLimit, changeDate) -> - VisaBalancesAndLimits(balances, oldLimit, newLimit, changeDate) + { token, balances, (oldLimit, newLimit, changeDate) -> + VisaContractInfo(token, balances, oldLimit, newLimit, changeDate) }, ) + private suspend fun fetchToken(paymentAccount: TangemPaymentAccount): Token { + val paymentTokenContractAddress = paymentAccount.paymentToken().send() + val paymentTokenContract = ERC20.load(paymentTokenContractAddress, web3j, transactionManager, gasProvider) + + return parZip( + dispatchers.io, + { paymentTokenContract.name().send() }, + { paymentTokenContract.symbol().send() }, + { paymentTokenContract.decimals().send() }, + ) { name, symbol, decimals -> + Token( + name = name, + symbol = symbol, + decimals = decimals.toInt(), + address = paymentTokenContractAddress, + ) + } + } + private suspend fun fetchBalances(paymentAccount: TangemPaymentAccount, paymentToken: PaymentTokenInfo): Balances { return parZip( dispatchers.io, diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt index 7829c34135..7ae3b7e0dc 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt +++ b/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt @@ -2,7 +2,7 @@ package com.tangem.lib.visa import com.ihsanbal.logging.Level import com.ihsanbal.logging.LoggingInterceptor -import com.tangem.lib.visa.model.VisaBalancesAndLimits +import com.tangem.lib.visa.model.VisaContractInfo import com.tangem.lib.visa.utils.VisaConfig import com.tangem.lib.visa.utils.VisaConfig.NETWORK_LOGS_TAG import com.tangem.lib.visa.utils.toHexString @@ -21,7 +21,7 @@ import java.util.concurrent.TimeUnit interface VisaContractInfoProvider { - suspend fun getBalancesAndLimits(walletAddress: String): VisaBalancesAndLimits + suspend fun getContractInfo(walletAddress: String): VisaContractInfo class Builder( private val isNetworkLoggingEnabled: Boolean, diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaBalancesAndLimits.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaContractInfo.kt similarity index 83% rename from libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaBalancesAndLimits.kt rename to libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaContractInfo.kt index 50145e05da..e2e6f98d58 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaBalancesAndLimits.kt +++ b/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaContractInfo.kt @@ -4,13 +4,21 @@ import org.joda.time.Instant import java.math.BigDecimal import java.math.BigInteger -data class VisaBalancesAndLimits( +data class VisaContractInfo( + val token: Token, val balances: Balances, val oldLimits: Limits, val newLimits: Limits, val limitsChangeDate: Instant, ) { + data class Token( + val name: String, + val symbol: String, + val decimals: Int, + val address: String, + ) + data class Balances( val total: BigDecimal, val verified: BigDecimal,