Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-12 10:20:23 +03:00
parent 4f88a5ddf9
commit ebb562b2a0
21 changed files with 81 additions and 41 deletions

View file

@ -282,11 +282,13 @@ internal object TokensDomainModule {
currenciesRepository: CurrenciesRepository, currenciesRepository: CurrenciesRepository,
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
dispatchers: CoroutineDispatcherProvider, dispatchers: CoroutineDispatcherProvider,
currencyChecksRepository: CurrencyChecksRepository,
): GetBalanceNotEnoughForFeeWarningUseCase { ): GetBalanceNotEnoughForFeeWarningUseCase {
return GetBalanceNotEnoughForFeeWarningUseCase( return GetBalanceNotEnoughForFeeWarningUseCase(
currenciesRepository = currenciesRepository, currenciesRepository = currenciesRepository,
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier, multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
dispatchers = dispatchers, dispatchers = dispatchers,
currencyChecksRepository = currencyChecksRepository,
) )
} }

View file

@ -10,6 +10,7 @@ import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.transaction.FeeRepository import com.tangem.domain.transaction.FeeRepository
import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.transaction.GaslessTransactionRepository
import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.transaction.TransactionRepository
@ -277,11 +278,13 @@ internal object TransactionDomainModule {
gaslessTransactionRepository: GaslessTransactionRepository, gaslessTransactionRepository: GaslessTransactionRepository,
currenciesRepository: CurrenciesRepository, currenciesRepository: CurrenciesRepository,
getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
currencyChecksRepository: CurrencyChecksRepository,
): GetAvailableFeeTokensUseCase { ): GetAvailableFeeTokensUseCase {
return GetAvailableFeeTokensUseCase( return GetAvailableFeeTokensUseCase(
gaslessTransactionRepository = gaslessTransactionRepository, gaslessTransactionRepository = gaslessTransactionRepository,
currenciesRepository = currenciesRepository, currenciesRepository = currenciesRepository,
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
currencyChecksRepository = currencyChecksRepository,
) )
} }
@ -293,6 +296,7 @@ internal object TransactionDomainModule {
currenciesRepository: CurrenciesRepository, currenciesRepository: CurrenciesRepository,
getFeeUseCase: GetFeeUseCase, getFeeUseCase: GetFeeUseCase,
getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
currencyChecksRepository: CurrencyChecksRepository,
): GetFeeForGaslessUseCase { ): GetFeeForGaslessUseCase {
return GetFeeForGaslessUseCase( return GetFeeForGaslessUseCase(
walletManagersFacade = walletManagersFacade, walletManagersFacade = walletManagersFacade,
@ -301,6 +305,7 @@ internal object TransactionDomainModule {
currenciesRepository = currenciesRepository, currenciesRepository = currenciesRepository,
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
getFeeUseCase = getFeeUseCase, getFeeUseCase = getFeeUseCase,
currencyChecksRepository = currencyChecksRepository,
) )
} }
@ -311,6 +316,7 @@ internal object TransactionDomainModule {
gaslessTransactionRepository: GaslessTransactionRepository, gaslessTransactionRepository: GaslessTransactionRepository,
currenciesRepository: CurrenciesRepository, currenciesRepository: CurrenciesRepository,
getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
currencyChecksRepository: CurrencyChecksRepository,
): GetFeeForTokenUseCase { ): GetFeeForTokenUseCase {
return GetFeeForTokenUseCase( return GetFeeForTokenUseCase(
gaslessTransactionRepository = gaslessTransactionRepository, gaslessTransactionRepository = gaslessTransactionRepository,
@ -318,15 +324,16 @@ internal object TransactionDomainModule {
demoConfig = DemoConfig, demoConfig = DemoConfig,
currenciesRepository = currenciesRepository, currenciesRepository = currenciesRepository,
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
currencyChecksRepository = currencyChecksRepository,
) )
} }
@Provides @Provides
@Singleton @Singleton
fun provideIsGaslessFeeSupportedForNetwork( fun provideIsGaslessFeeSupportedForNetwork(
gaslessTransactionRepository: GaslessTransactionRepository, currencyChecksRepository: CurrencyChecksRepository,
): IsGaslessFeeSupportedForNetwork { ): IsGaslessFeeSupportedForNetwork {
return IsGaslessFeeSupportedForNetwork(gaslessTransactionRepository) return IsGaslessFeeSupportedForNetwork(currencyChecksRepository)
} }
@Provides @Provides
@ -354,6 +361,7 @@ internal object TransactionDomainModule {
gaslessTransactionRepository: GaslessTransactionRepository, gaslessTransactionRepository: GaslessTransactionRepository,
currenciesRepository: CurrenciesRepository, currenciesRepository: CurrenciesRepository,
getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
currencyChecksRepository: CurrencyChecksRepository,
): EstimateFeeForTokenUseCase { ): EstimateFeeForTokenUseCase {
return EstimateFeeForTokenUseCase( return EstimateFeeForTokenUseCase(
gaslessTransactionRepository = gaslessTransactionRepository, gaslessTransactionRepository = gaslessTransactionRepository,
@ -361,6 +369,7 @@ internal object TransactionDomainModule {
demoConfig = DemoConfig, demoConfig = DemoConfig,
currenciesRepository = currenciesRepository, currenciesRepository = currenciesRepository,
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
currencyChecksRepository = currencyChecksRepository,
) )
} }
@ -372,6 +381,7 @@ internal object TransactionDomainModule {
currenciesRepository: CurrenciesRepository, currenciesRepository: CurrenciesRepository,
getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
estimateFeeUseCase: EstimateFeeUseCase, estimateFeeUseCase: EstimateFeeUseCase,
currencyChecksRepository: CurrencyChecksRepository,
): EstimateFeeForGaslessTxUseCase { ): EstimateFeeForGaslessTxUseCase {
return EstimateFeeForGaslessTxUseCase( return EstimateFeeForGaslessTxUseCase(
gaslessTransactionRepository = gaslessTransactionRepository, gaslessTransactionRepository = gaslessTransactionRepository,
@ -380,6 +390,7 @@ internal object TransactionDomainModule {
currenciesRepository = currenciesRepository, currenciesRepository = currenciesRepository,
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase, getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
estimateFeeUseCase = estimateFeeUseCase, estimateFeeUseCase = estimateFeeUseCase,
currencyChecksRepository = currencyChecksRepository,
) )
} }
} }

View file

@ -46,6 +46,10 @@ dependencies {
implementation(projects.libs.blockchainSdk) implementation(projects.libs.blockchainSdk)
// endregion // endregion
// region Project - Features API
implementation(projects.features.sendV2.api)
// endregion
// region Tangem SDKs // region Tangem SDKs
implementation(tangemDeps.blockchain) implementation(tangemDeps.blockchain)
implementation(tangemDeps.card.core) implementation(tangemDeps.card.core)

View file

@ -22,6 +22,7 @@ import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository
import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.features.send.v2.api.SendFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@ -72,10 +73,12 @@ internal object TokensDataModule {
fun provideCurrencyChecksRepository( fun provideCurrencyChecksRepository(
walletManagersFacade: WalletManagersFacade, walletManagersFacade: WalletManagersFacade,
coroutineDispatcherProvider: CoroutineDispatcherProvider, coroutineDispatcherProvider: CoroutineDispatcherProvider,
sendFeatureToggles: SendFeatureToggles,
): CurrencyChecksRepository { ): CurrencyChecksRepository {
return DefaultCurrencyChecksRepository( return DefaultCurrencyChecksRepository(
walletManagersFacade = walletManagersFacade, walletManagersFacade = walletManagersFacade,
coroutineDispatchers = coroutineDispatcherProvider, coroutineDispatchers = coroutineDispatcherProvider,
sendFeatureToggles = sendFeatureToggles,
) )
} }

View file

@ -1,10 +1,8 @@
package com.tangem.data.tokens.repository package com.tangem.data.tokens.repository
import com.tangem.blockchain.blockchains.ethereum.eip1559.isGaslessTxSupported
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
import com.tangem.blockchain.common.FeeResourceAmountProvider import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.MinimumSendAmountProvider
import com.tangem.blockchain.common.ReserveAmountProvider
import com.tangem.blockchain.common.UtxoAmountLimitProvider
import com.tangem.data.tokens.converters.UtxoConverter import com.tangem.data.tokens.converters.UtxoConverter
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
@ -17,6 +15,7 @@ import com.tangem.domain.tokens.model.blockchains.UtxoAmountLimit
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.tokens.repository.CurrencyChecksRepository import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.features.send.v2.api.SendFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.isZero import com.tangem.utils.extensions.isZero
import com.tangem.utils.extensions.orZero import com.tangem.utils.extensions.orZero
@ -26,6 +25,7 @@ import java.math.BigDecimal
internal class DefaultCurrencyChecksRepository( internal class DefaultCurrencyChecksRepository(
private val walletManagersFacade: WalletManagersFacade, private val walletManagersFacade: WalletManagersFacade,
private val coroutineDispatchers: CoroutineDispatcherProvider, private val coroutineDispatchers: CoroutineDispatcherProvider,
private val sendFeatureToggles: SendFeatureToggles,
) : CurrencyChecksRepository { ) : CurrencyChecksRepository {
override suspend fun getExistentialDeposit(userWalletId: UserWalletId, network: Network): BigDecimal? { override suspend fun getExistentialDeposit(userWalletId: UserWalletId, network: Network): BigDecimal? {
@ -66,6 +66,12 @@ internal class DefaultCurrencyChecksRepository(
} }
} }
override fun isNetworkSupportedForGaslessTx(network: Network): Boolean {
if (!sendFeatureToggles.isGaslessTransactionsEnabled) return false
val blockchain = Blockchain.fromId(network.rawId)
return blockchain.isGaslessTxSupported
}
override suspend fun getFeeResourceAmount(userWalletId: UserWalletId, network: Network): CurrencyAmount? { override suspend fun getFeeResourceAmount(userWalletId: UserWalletId, network: Network): CurrencyAmount? {
val manager = walletManagersFacade.getOrCreateWalletManager( val manager = walletManagersFacade.getOrCreateWalletManager(
userWalletId = userWalletId, userWalletId = userWalletId,

View file

@ -30,11 +30,6 @@ class DefaultGaslessTransactionRepository(
private val gaslessTransactionRequestBuilder = GaslessTransactionRequestBuilder() private val gaslessTransactionRequestBuilder = GaslessTransactionRequestBuilder()
private val signedTransactionResultConverter = GaslessSignedTransactionResultConverter() private val signedTransactionResultConverter = GaslessSignedTransactionResultConverter()
override fun isNetworkSupported(network: Network): Boolean {
val blockchain = Blockchain.fromId(network.rawId)
return SUPPORTED_BLOCKCHAINS.contains(blockchain)
}
override suspend fun getSupportedTokens(network: Network): Set<CryptoCurrency> { override suspend fun getSupportedTokens(network: Network): Set<CryptoCurrency> {
return withContext(coroutineDispatcherProvider.io) { return withContext(coroutineDispatcherProvider.io) {
val storedTokens = supportedTokensState.value[network.id] val storedTokens = supportedTokensState.value[network.id]
@ -118,14 +113,5 @@ class DefaultGaslessTransactionRepository(
const val TOKEN_RECEIVER_ADDRESS = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" const val TOKEN_RECEIVER_ADDRESS = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
val BASE_GAS_FOR_TRANSACTION: BigInteger = BigInteger("100000") val BASE_GAS_FOR_TRANSACTION: BigInteger = BigInteger("100000")
val SUPPORTED_BLOCKCHAINS = arrayOf(
Blockchain.Ethereum,
Blockchain.BSC,
Blockchain.Base,
Blockchain.Polygon,
Blockchain.Arbitrum,
Blockchain.XDC,
Blockchain.Optimism,
)
} }
} }

View file

@ -15,11 +15,6 @@ class MockedGaslessTransactionRepository(
private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory, private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory,
) : GaslessTransactionRepository { ) : GaslessTransactionRepository {
override fun isNetworkSupported(network: Network): Boolean {
val blockchain = Blockchain.fromId(network.rawId)
return SUPPORTED_BLOCKCHAINS.contains(blockchain)
}
override suspend fun getSupportedTokens(network: Network): Set<CryptoCurrency> { override suspend fun getSupportedTokens(network: Network): Set<CryptoCurrency> {
val usdcPolygon = responseCryptoCurrenciesFactory.createToken( val usdcPolygon = responseCryptoCurrenciesFactory.createToken(
blockchain = Blockchain.Polygon, blockchain = Blockchain.Polygon,

View file

@ -7,6 +7,7 @@ import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.model.FeePaidCurrency import com.tangem.domain.tokens.model.FeePaidCurrency
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.math.BigDecimal import java.math.BigDecimal
@ -27,6 +28,7 @@ class GetBalanceNotEnoughForFeeWarningUseCase(
private val currenciesRepository: CurrenciesRepository, private val currenciesRepository: CurrenciesRepository,
private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
private val dispatchers: CoroutineDispatcherProvider, private val dispatchers: CoroutineDispatcherProvider,
private val currencyChecksRepository: CurrencyChecksRepository,
) { ) {
suspend operator fun invoke( suspend operator fun invoke(
fee: BigDecimal, fee: BigDecimal,
@ -41,9 +43,15 @@ class GetBalanceNotEnoughForFeeWarningUseCase(
val isFeePaidByCoin = tokenStatus.currency is CryptoCurrency.Token val isFeePaidByCoin = tokenStatus.currency is CryptoCurrency.Token
val isFeePaidByToken = val isFeePaidByToken =
feePaidCurrency is FeePaidCurrency.Token && tokenStatus.currency.id != feePaidCurrency.tokenId feePaidCurrency is FeePaidCurrency.Token && tokenStatus.currency.id != feePaidCurrency.tokenId
val isNetworkSupportGasless = currencyChecksRepository.isNetworkSupportedForGaslessTx(
coinStatus.currency.network,
)
val warning = when { val warning = when {
feePaidCurrency is FeePaidCurrency.Coin && isFeePaidByCoin && fee > coinBalance -> { feePaidCurrency is FeePaidCurrency.Coin &&
isFeePaidByCoin &&
fee > coinBalance &&
!isNetworkSupportGasless -> {
CryptoCurrencyWarning.BalanceNotEnoughForFee( CryptoCurrencyWarning.BalanceNotEnoughForFee(
tokenCurrency = tokenStatus.currency, tokenCurrency = tokenStatus.currency,
coinCurrency = coinStatus.currency, coinCurrency = coinStatus.currency,

View file

@ -29,6 +29,7 @@ class GetCurrencyWarningsUseCase(
private val currencyChecksRepository: CurrencyChecksRepository, private val currencyChecksRepository: CurrencyChecksRepository,
private val currencyStatusOperations: BaseCurrencyStatusOperations, private val currencyStatusOperations: BaseCurrencyStatusOperations,
private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
) { ) {
suspend operator fun invoke( suspend operator fun invoke(
@ -56,7 +57,7 @@ class GetCurrencyWarningsUseCase(
maybeRentWarning, maybeRentWarning,
maybeEdWarning?.let { getExistentialDepositWarning(currency, it) }, maybeEdWarning?.let { getExistentialDepositWarning(currency, it) },
maybeFeeResource?.let { getFeeResourceWarning(it) }, maybeFeeResource?.let { getFeeResourceWarning(it) },
* coinRelatedWarnings.toTypedArray(), *coinRelatedWarnings.toTypedArray(),
getNetworkUnavailableWarning(currencyStatus), getNetworkUnavailableWarning(currencyStatus),
getNetworkNoAccountWarning(currencyStatus), getNetworkNoAccountWarning(currencyStatus),
getBeaconChainShutdownWarning(rawId = currency.network.id.rawId), getBeaconChainShutdownWarning(rawId = currency.network.id.rawId),
@ -114,11 +115,14 @@ class GetCurrencyWarningsUseCase(
): CryptoCurrencyWarning? { ): CryptoCurrencyWarning? {
val feePaidCurrency = currenciesRepository.getFeePaidCurrency(userWalletId, tokenStatus.currency.network) val feePaidCurrency = currenciesRepository.getFeePaidCurrency(userWalletId, tokenStatus.currency.network)
val isNetworkFeeZero = currenciesRepository.isNetworkFeeZero(userWalletId, tokenStatus.currency.network) val isNetworkFeeZero = currenciesRepository.isNetworkFeeZero(userWalletId, tokenStatus.currency.network)
val isNetworkSupportGasless =
currencyChecksRepository.isNetworkSupportedForGaslessTx(coinStatus.currency.network)
return when { return when {
feePaidCurrency is FeePaidCurrency.Coin && feePaidCurrency is FeePaidCurrency.Coin &&
!tokenStatus.value.amount.isZero() && !tokenStatus.value.amount.isZero() &&
coinStatus.value.amount.isZero() && coinStatus.value.amount.isZero() &&
!isNetworkFeeZero -> { !isNetworkFeeZero &&
!isNetworkSupportGasless -> {
CryptoCurrencyWarning.BalanceNotEnoughForFee( CryptoCurrencyWarning.BalanceNotEnoughForFee(
tokenCurrency = tokenStatus.currency, tokenCurrency = tokenStatus.currency,
coinCurrency = coinStatus.currency, coinCurrency = coinStatus.currency,

View file

@ -61,4 +61,7 @@ interface CurrencyChecksRepository {
currencyStatus: CryptoCurrencyStatus?, currencyStatus: CryptoCurrencyStatus?,
balanceAfterTransaction: BigDecimal, balanceAfterTransaction: BigDecimal,
): CryptoCurrencyWarning.Rent? ): CryptoCurrencyWarning.Rent?
/** Checks if the network supports gasless transactions */
fun isNetworkSupportedForGaslessTx(network: Network): Boolean
} }

View file

@ -9,8 +9,6 @@ import java.math.BigInteger
interface GaslessTransactionRepository { interface GaslessTransactionRepository {
fun isNetworkSupported(network: Network): Boolean
suspend fun getSupportedTokens(network: Network): Set<CryptoCurrency> suspend fun getSupportedTokens(network: Network): Set<CryptoCurrency>
fun getTokenFeeReceiverAddress(): String fun getTokenFeeReceiverAddress(): String

View file

@ -14,6 +14,7 @@ import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.transaction.GaslessTransactionRepository
import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.error.GetFeeError.GaslessError import com.tangem.domain.transaction.error.GetFeeError.GaslessError
@ -23,6 +24,7 @@ import com.tangem.domain.transaction.usecase.EstimateFeeUseCase
import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.walletmanager.WalletManagersFacade
import java.math.BigDecimal import java.math.BigDecimal
@Suppress("LongParameterList")
class EstimateFeeForGaslessTxUseCase( class EstimateFeeForGaslessTxUseCase(
private val walletManagersFacade: WalletManagersFacade, private val walletManagersFacade: WalletManagersFacade,
private val demoConfig: DemoConfig, private val demoConfig: DemoConfig,
@ -30,6 +32,7 @@ class EstimateFeeForGaslessTxUseCase(
private val currenciesRepository: CurrenciesRepository, private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val estimateFeeUseCase: EstimateFeeUseCase, private val estimateFeeUseCase: EstimateFeeUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) { ) {
private val tokenFeeCalculator = TokenFeeCalculator( private val tokenFeeCalculator = TokenFeeCalculator(
@ -53,7 +56,7 @@ class EstimateFeeForGaslessTxUseCase(
derivationPath = network.derivationPath, derivationPath = network.derivationPath,
) )
if (!gaslessTransactionRepository.isNetworkSupported(network)) { if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(network)) {
estimateFeeUseCase.invoke( estimateFeeUseCase.invoke(
userWallet = userWallet, userWallet = userWallet,
amount = amount, amount = amount,

View file

@ -14,6 +14,7 @@ import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.transaction.GaslessTransactionRepository
import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.error.mapToFeeError import com.tangem.domain.transaction.error.mapToFeeError
@ -29,6 +30,7 @@ class EstimateFeeForTokenUseCase(
private val demoConfig: DemoConfig, private val demoConfig: DemoConfig,
private val currenciesRepository: CurrenciesRepository, private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) { ) {
private val tokenFeeCalculator = TokenFeeCalculator( private val tokenFeeCalculator = TokenFeeCalculator(
@ -44,7 +46,7 @@ class EstimateFeeForTokenUseCase(
): Either<GetFeeError, TransactionFeeExtended> { ): Either<GetFeeError, TransactionFeeExtended> {
return either { return either {
val token = tokenCurrencyStatus.currency val token = tokenCurrencyStatus.currency
if (!gaslessTransactionRepository.isNetworkSupported(token.network)) { if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(token.network)) {
raise(GetFeeError.GaslessError.NetworkIsNotSupported) raise(GetFeeError.GaslessError.NetworkIsNotSupported)
} }

View file

@ -10,6 +10,7 @@ import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.transaction.GaslessTransactionRepository
import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.raiseIllegalStateError import com.tangem.domain.transaction.raiseIllegalStateError
@ -19,6 +20,7 @@ class GetAvailableFeeTokensUseCase(
private val gaslessTransactionRepository: GaslessTransactionRepository, private val gaslessTransactionRepository: GaslessTransactionRepository,
private val currenciesRepository: CurrenciesRepository, private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) { ) {
/** /**
@ -40,7 +42,7 @@ class GetAvailableFeeTokensUseCase(
val nativeCurrencyStatus = getNativeCurrencyStatus(userWallet, network, userCurrenciesStatuses) val nativeCurrencyStatus = getNativeCurrencyStatus(userWallet, network, userCurrenciesStatuses)
if (!gaslessTransactionRepository.isNetworkSupported(network)) { if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(network)) {
return@either listOf(nativeCurrencyStatus) return@either listOf(nativeCurrencyStatus)
} }

View file

@ -15,6 +15,7 @@ import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.transaction.GaslessTransactionRepository
import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.error.GetFeeError.GaslessError import com.tangem.domain.transaction.error.GetFeeError.GaslessError
@ -24,6 +25,7 @@ import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.walletmanager.WalletManagersFacade
import java.math.BigDecimal import java.math.BigDecimal
@Suppress("LongParameterList")
class GetFeeForGaslessUseCase( class GetFeeForGaslessUseCase(
private val walletManagersFacade: WalletManagersFacade, private val walletManagersFacade: WalletManagersFacade,
private val demoConfig: DemoConfig, private val demoConfig: DemoConfig,
@ -31,6 +33,7 @@ class GetFeeForGaslessUseCase(
private val currenciesRepository: CurrenciesRepository, private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val getFeeUseCase: GetFeeUseCase, private val getFeeUseCase: GetFeeUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) { ) {
private val tokenFeeCalculator = TokenFeeCalculator( private val tokenFeeCalculator = TokenFeeCalculator(
@ -53,7 +56,7 @@ class GetFeeForGaslessUseCase(
derivationPath = network.derivationPath, derivationPath = network.derivationPath,
) )
if (!gaslessTransactionRepository.isNetworkSupported(network)) { if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(network)) {
getFeeUseCase.invoke(userWallet, network, transactionData).fold( getFeeUseCase.invoke(userWallet, network, transactionData).fold(
ifLeft = { raise(it) }, ifLeft = { raise(it) },
ifRight = { fee -> ifRight = { fee ->

View file

@ -12,6 +12,7 @@ import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.transaction.GaslessTransactionRepository
import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.models.TransactionFeeExtended import com.tangem.domain.transaction.models.TransactionFeeExtended
@ -24,6 +25,7 @@ class GetFeeForTokenUseCase(
private val demoConfig: DemoConfig, private val demoConfig: DemoConfig,
private val currenciesRepository: CurrenciesRepository, private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) { ) {
private val tokenFeeCalculator = TokenFeeCalculator( private val tokenFeeCalculator = TokenFeeCalculator(
@ -38,7 +40,7 @@ class GetFeeForTokenUseCase(
transactionData: TransactionData, transactionData: TransactionData,
): Either<GetFeeError, TransactionFeeExtended> { ): Either<GetFeeError, TransactionFeeExtended> {
return either { return either {
if (!gaslessTransactionRepository.isNetworkSupported(token.network)) { if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(token.network)) {
raise(GetFeeError.GaslessError.NetworkIsNotSupported) raise(GetFeeError.GaslessError.NetworkIsNotSupported)
} }

View file

@ -1,16 +1,16 @@
package com.tangem.domain.transaction.usecase.gasless package com.tangem.domain.transaction.usecase.gasless
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.transaction.GaslessTransactionRepository import com.tangem.domain.tokens.repository.CurrencyChecksRepository
/** /**
* Use case to check if gasless fee is supported for a given network. * Use case to check if gasless fee is supported for a given network.
*/ */
class IsGaslessFeeSupportedForNetwork( class IsGaslessFeeSupportedForNetwork(
private val gaslessTransactionRepository: GaslessTransactionRepository, private val currencyChecksRepository: CurrencyChecksRepository,
) { ) {
operator fun invoke(network: Network): Boolean { operator fun invoke(network: Network): Boolean {
return gaslessTransactionRepository.isNetworkSupported(network) return currencyChecksRepository.isNetworkSupportedForGaslessTx(network)
} }
} }

View file

@ -51,6 +51,7 @@ import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNetwork
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.swap.analytics.StoriesEvents import com.tangem.feature.swap.analytics.StoriesEvents
@ -118,6 +119,7 @@ internal class SwapModel @Inject constructor(
private val accountsFeatureToggles: AccountsFeatureToggles, private val accountsFeatureToggles: AccountsFeatureToggles,
private val getTangemPayCurrencyStatusUseCase: GetTangemPayCurrencyStatusUseCase, private val getTangemPayCurrencyStatusUseCase: GetTangemPayCurrencyStatusUseCase,
private val tangemPayWithdrawUseCase: TangemPayWithdrawUseCase, private val tangemPayWithdrawUseCase: TangemPayWithdrawUseCase,
private val iGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork,
) : Model() { ) : Model() {
private val params = paramsContainer.require<SwapComponent.Params>() private val params = paramsContainer.require<SwapComponent.Params>()
@ -149,6 +151,7 @@ internal class SwapModel @Inject constructor(
isBalanceHiddenProvider = Provider { isBalanceHidden }, isBalanceHiddenProvider = Provider { isBalanceHidden },
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
isAccountsModeProvider = Provider { isAccountsMode }, isAccountsModeProvider = Provider { isAccountsMode },
iGaslessFeeSupportedForNetwork = iGaslessFeeSupportedForNetwork,
) )
private val inputNumberFormatter = private val inputNumberFormatter =

View file

@ -12,6 +12,7 @@ import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNetwork
import com.tangem.feature.swap.domain.models.ExpressDataError import com.tangem.feature.swap.domain.models.ExpressDataError
import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.SwapAmount
import com.tangem.feature.swap.domain.models.domain.IncludeFeeInAmount import com.tangem.feature.swap.domain.models.domain.IncludeFeeInAmount
@ -32,6 +33,7 @@ import java.math.BigDecimal
@Suppress("LargeClass") @Suppress("LargeClass")
internal class SwapNotificationsFactory( internal class SwapNotificationsFactory(
private val actions: UiActions, private val actions: UiActions,
private val iGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork,
) { ) {
fun getInitialErrorStateNotifications(code: Int, onRefreshClick: () -> Unit): ImmutableList<NotificationUM> { fun getInitialErrorStateNotifications(code: Int, onRefreshClick: () -> Unit): ImmutableList<NotificationUM> {
@ -294,7 +296,8 @@ internal class SwapNotificationsFactory(
val shouldShowCoverWarning = quoteModel.preparedSwapConfigState.isBalanceEnough && val shouldShowCoverWarning = quoteModel.preparedSwapConfigState.isBalanceEnough &&
quoteModel.permissionState !is PermissionDataState.PermissionLoading && quoteModel.permissionState !is PermissionDataState.PermissionLoading &&
feeEnoughState.feeCurrency != fromToken feeEnoughState.feeCurrency != fromToken
if (shouldShowCoverWarning) { val isGaslessAvailable = iGaslessFeeSupportedForNetwork(fromToken.network)
if (shouldShowCoverWarning && !isGaslessAvailable) {
add( add(
SwapNotificationUM.Error.UnableToCoverFeeWarning( SwapNotificationUM.Error.UnableToCoverFeeWarning(
fromToken = fromToken, fromToken = fromToken,

View file

@ -25,6 +25,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.models.StoryContent import com.tangem.domain.promo.models.StoryContent
import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNetwork
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
import com.tangem.feature.swap.converters.TokensDataConverter import com.tangem.feature.swap.converters.TokensDataConverter
import com.tangem.feature.swap.converters.TokensDataConverterV2 import com.tangem.feature.swap.converters.TokensDataConverterV2
@ -64,6 +65,7 @@ internal class StateBuilder(
private val isBalanceHiddenProvider: Provider<Boolean>, private val isBalanceHiddenProvider: Provider<Boolean>,
private val appCurrencyProvider: Provider<AppCurrency>, private val appCurrencyProvider: Provider<AppCurrency>,
private val isAccountsModeProvider: Provider<Boolean>, private val isAccountsModeProvider: Provider<Boolean>,
private val iGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork,
) { ) {
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter) private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
@ -76,7 +78,7 @@ internal class StateBuilder(
) )
private val notificationsFactory by lazy(LazyThreadSafetyMode.NONE) { private val notificationsFactory by lazy(LazyThreadSafetyMode.NONE) {
SwapNotificationsFactory(actions) SwapNotificationsFactory(actions, iGaslessFeeSupportedForNetwork)
} }
fun createInitialLoadingState( fun createInitialLoadingState(

View file

@ -5,7 +5,7 @@
# https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/tangem-sdk-android/
# https://github.com/tangem/vico # https://github.com/tangem/vico
tangemBlockchainSdk = "develop-1354" tangemBlockchainSdk = "develop-1355"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-573" tangemCardSdk = "develop-573"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^