Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-12 10:41:39 +04:00
parent 86af90fd92
commit d31d3f8a9b
8 changed files with 82 additions and 172 deletions

View file

@ -1,19 +1,21 @@
package com.tangem.domain.transaction.usecase.gasless
import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.raise.Raise
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCoinStatus
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
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.error.GetFeeError
@ -29,8 +31,7 @@ class EstimateFeeForGaslessTxUseCase(
private val walletManagersFacade: WalletManagersFacade,
private val demoConfig: DemoConfig,
private val gaslessTransactionRepository: GaslessTransactionRepository,
private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val estimateFeeUseCase: EstimateFeeUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) {
@ -50,11 +51,13 @@ class EstimateFeeForGaslessTxUseCase(
catch(
block = {
val network = sendingTokenCurrencyStatus.currency.network
val nativeCurrency = currenciesRepository.getNetworkCoin(
userWalletId = userWallet.walletId,
networkId = network.id,
derivationPath = network.derivationPath,
)
val accountStatusList = singleAccountStatusListSupplier.getSyncOrNull(userWallet.walletId)
?: raiseIllegalStateError("AccountStatusList is null for ${userWallet.walletId}")
val nativeCurrencyStatus = accountStatusList.getCoinStatus(network).getOrElse {
raiseIllegalStateError("No native currency found: ${network.id}")
}
if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(network)) {
estimateFeeUseCase.invoke(
@ -66,7 +69,7 @@ class EstimateFeeForGaslessTxUseCase(
ifRight = { fee ->
return@either TransactionFeeExtended(
transactionFee = fee,
feeTokenId = nativeCurrency.id,
feeTokenId = nativeCurrencyStatus.currency.id,
)
},
)
@ -81,9 +84,9 @@ class EstimateFeeForGaslessTxUseCase(
).bind()
selectFeePaymentStrategy(
userWallet = userWallet,
accountStatusList = accountStatusList,
walletManager = walletManager,
nativeCurrency = nativeCurrency,
nativeCurrencyStatus = nativeCurrencyStatus,
network = network,
initialFee = initialFee,
)
@ -110,25 +113,17 @@ class EstimateFeeForGaslessTxUseCase(
}
private suspend fun Raise<GetFeeError>.selectFeePaymentStrategy(
userWallet: UserWallet,
accountStatusList: AccountStatusList,
walletManager: EthereumWalletManager,
nativeCurrency: CryptoCurrency,
nativeCurrencyStatus: CryptoCurrencyStatus,
network: Network,
initialFee: TransactionFee,
): TransactionFeeExtended {
val feeValue = initialFee.normal.amount.value ?: raise(GetFeeError.UnknownError)
val userCurrenciesStatuses = getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWallet.walletId,
).getOrNull() ?: raiseIllegalStateError("currencies list is null for userWalletId=${userWallet.walletId}")
val networkCurrenciesStatuses = userCurrenciesStatuses.filter {
it.currency.network.id == network.id
}
val nativeCurrencyStatus = networkCurrenciesStatuses.find {
it.currency.id == nativeCurrency.id
} ?: raiseIllegalStateError("native currency not found for network ${network.id}")
val networkCurrenciesStatuses = accountStatusList
.flattenCurrencies()
.filter { it.currency.network.id == network.id }
val nativeBalance = nativeCurrencyStatus.value.amount ?: BigDecimal.ZERO
return if (nativeBalance >= feeValue) {

View file

@ -1,17 +1,18 @@
package com.tangem.domain.transaction.usecase.gasless
import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.raise.Raise
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCoinStatus
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
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.error.GetFeeError
@ -25,8 +26,7 @@ class EstimateFeeForTokenUseCase(
private val gaslessTransactionRepository: GaslessTransactionRepository,
private val walletManagersFacade: WalletManagersFacade,
private val demoConfig: DemoConfig,
private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val currencyChecksRepository: CurrencyChecksRepository,
) {
@ -61,21 +61,12 @@ class EstimateFeeForTokenUseCase(
error = "only Fee.Ethereum supported, but was different",
)
val nativeCurrency = currenciesRepository.getNetworkCoin(
userWalletId = userWallet.walletId,
networkId = token.network.id,
derivationPath = token.network.derivationPath,
)
val accountStatusList = singleAccountStatusListSupplier.getSyncOrNull(userWallet.walletId)
?: raiseIllegalStateError("AccountStatusList is null for ${userWallet.walletId}")
val userCurrenciesStatusesByNetwork = getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWallet.walletId,
).getOrNull()?.filter {
it.currency.network.id == token.network.id
} ?: raiseIllegalStateError("currencies list is null for userWalletId=${userWallet.walletId}")
val nativeCurrencyStatus = userCurrenciesStatusesByNetwork.find {
it.currency.id == nativeCurrency.id
} ?: raiseIllegalStateError("native currency not found for network ${token.network.id}")
val nativeCurrencyStatus = accountStatusList.getCoinStatus(token.network).getOrElse {
raiseIllegalStateError("No native currency found: ${token.network.id}")
}
val walletManager = prepareWalletManager(userWallet, token.network)

View file

@ -1,24 +1,23 @@
package com.tangem.domain.transaction.usecase.gasless
import arrow.core.Either
import arrow.core.raise.Raise
import arrow.core.getOrElse
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCoinStatus
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
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.error.GetFeeError
import com.tangem.domain.transaction.raiseIllegalStateError
class GetAvailableFeeTokensUseCase(
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val gaslessTransactionRepository: GaslessTransactionRepository,
private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) {
@ -34,12 +33,14 @@ class GetAvailableFeeTokensUseCase(
return either {
catch(
block = {
val userCurrenciesStatuses = getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWallet.walletId,
).getOrNull()
?: raiseIllegalStateError("currencies list is null for userWalletId=${userWallet.walletId}")
val accountStatusList = singleAccountStatusListSupplier.getSyncOrNull(userWallet.walletId)
?: raiseIllegalStateError("AccountStatusList is null for ${userWallet.walletId}")
val nativeCurrencyStatus = getNativeCurrencyStatus(userWallet, network, userCurrenciesStatuses)
val userCurrenciesStatuses = accountStatusList.flattenCurrencies()
val nativeCurrencyStatus = accountStatusList.getCoinStatus(network).getOrElse {
raiseIllegalStateError("No native currency found: ${network.id}")
}
if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(network)) {
return@either listOf(nativeCurrencyStatus)
@ -58,21 +59,6 @@ class GetAvailableFeeTokensUseCase(
}
}
private suspend fun Raise<GetFeeError>.getNativeCurrencyStatus(
userWallet: UserWallet,
network: Network,
userCurrenciesStatuses: List<CryptoCurrencyStatus>,
): CryptoCurrencyStatus {
val nativeCurrency = currenciesRepository.getNetworkCoin(
userWalletId = userWallet.walletId,
networkId = network.id,
derivationPath = network.derivationPath,
)
return userCurrenciesStatuses.find {
it.currency.id == nativeCurrency.id
} ?: raiseIllegalStateError("no native currency found")
}
private suspend fun getGaslessTokens(
network: Network,
userCurrenciesStatuses: List<CryptoCurrencyStatus>,

View file

@ -9,13 +9,14 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCoinStatus
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
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.error.GetFeeError
@ -31,8 +32,7 @@ class GetFeeForGaslessUseCase(
private val walletManagersFacade: WalletManagersFacade,
private val demoConfig: DemoConfig,
private val gaslessTransactionRepository: GaslessTransactionRepository,
private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val getFeeUseCase: GetFeeUseCase,
private val currencyChecksRepository: CurrencyChecksRepository,
) {
@ -51,11 +51,12 @@ class GetFeeForGaslessUseCase(
return either {
catch(
block = {
val nativeCurrency = currenciesRepository.getNetworkCoin(
userWalletId = userWallet.walletId,
networkId = network.id,
derivationPath = network.derivationPath,
)
val accountStatusList = singleAccountStatusListSupplier.getSyncOrNull(userWallet.walletId)
?: raiseIllegalStateError("AccountStatusList is null for ${userWallet.walletId}")
val nativeCurrencyStatus = accountStatusList.getCoinStatus(network).getOrElse {
raiseIllegalStateError("No native currency found: ${network.id}")
}
if (!currencyChecksRepository.isNetworkSupportedForGaslessTx(network)) {
getFeeUseCase.invoke(userWallet, network, transactionData).fold(
@ -63,7 +64,7 @@ class GetFeeForGaslessUseCase(
ifRight = { fee ->
return@either TransactionFeeExtended(
transactionFee = fee,
feeTokenId = nativeCurrency.id,
feeTokenId = nativeCurrencyStatus.currency.id,
)
},
)
@ -79,9 +80,9 @@ class GetFeeForGaslessUseCase(
).bind()
selectFeePaymentStrategy(
userWallet = userWallet,
accountStatusList = accountStatusList,
walletManager = walletManager,
nativeCurrency = nativeCurrency,
nativeCurrencyStatus = nativeCurrencyStatus,
network = network,
initialFee = initialFee,
)
@ -108,25 +109,17 @@ class GetFeeForGaslessUseCase(
}
private suspend fun Raise<GetFeeError>.selectFeePaymentStrategy(
userWallet: UserWallet,
accountStatusList: AccountStatusList,
walletManager: EthereumWalletManager,
nativeCurrency: CryptoCurrency,
nativeCurrencyStatus: CryptoCurrencyStatus,
network: Network,
initialFee: TransactionFee,
): TransactionFeeExtended {
val feeValue = initialFee.normal.amount.value ?: raise(GetFeeError.UnknownError)
val userCurrenciesStatuses = getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWallet.walletId,
).getOrNull() ?: raiseIllegalStateError("currencies list is null for userWalletId=${userWallet.walletId}")
val networkCurrenciesStatuses = userCurrenciesStatuses.filter {
it.currency.network.id == network.id
}
val nativeCurrencyStatus = networkCurrenciesStatuses.find {
it.currency.id == nativeCurrency.id
} ?: raiseIllegalStateError("native currency not found for network ${network.id}")
val networkCurrenciesStatuses = accountStatusList
.flattenCurrencies()
.filter { it.currency.network.id == network.id }
val nativeBalance = nativeCurrencyStatus.value.amount ?: BigDecimal.ZERO
val nativeCoinSelectedResult =

View file

@ -1,18 +1,20 @@
package com.tangem.domain.transaction.usecase.gasless
import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.raise.Raise
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCoinStatus
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCryptoCurrencyStatus
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
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.error.GetFeeError
@ -25,8 +27,7 @@ class GetFeeForTokenUseCase(
private val gaslessTransactionRepository: GaslessTransactionRepository,
private val walletManagersFacade: WalletManagersFacade,
private val demoConfig: DemoConfig,
private val currenciesRepository: CurrenciesRepository,
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val currencyChecksRepository: CurrencyChecksRepository,
) {
@ -62,25 +63,16 @@ class GetFeeForTokenUseCase(
error = "only Fee.Ethereum supported, but was different",
)
val nativeCurrency = currenciesRepository.getNetworkCoin(
userWalletId = userWallet.walletId,
networkId = token.network.id,
derivationPath = token.network.derivationPath,
)
val accountStatusList = singleAccountStatusListSupplier.getSyncOrNull(userWallet.walletId)
?: raiseIllegalStateError("AccountStatusList is null for ${userWallet.walletId}")
val userCurrenciesStatusesByNetwork = getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWallet.walletId,
).getOrNull()?.filter {
it.currency.network.id == token.network.id
} ?: raiseIllegalStateError("currencies list is null for userWalletId=${userWallet.walletId}")
val nativeCurrencyStatus = accountStatusList.getCoinStatus(token.network).getOrElse {
raiseIllegalStateError("Native currency not found for network ${token.network.id}")
}
val nativeCurrencyStatus = userCurrenciesStatusesByNetwork.find {
it.currency.id == nativeCurrency.id
} ?: raiseIllegalStateError("native currency not found for network ${token.network.id}")
val tokenCurrencyStatus = userCurrenciesStatusesByNetwork.find {
it.currency.id == token.id
} ?: raiseIllegalStateError("token currency not found for network ${token.network.id}")
val tokenCurrencyStatus = accountStatusList.getCryptoCurrencyStatus(currency = token).getOrElse {
raiseIllegalStateError("Token currency not found for network ${token.network.id}")
}
tokenFeeCalculator.calculateTokenFee(
walletManager = walletManager,