Updated on 2026-08-14
This commit is contained in:
parent
592f4cf8e7
commit
5e8c334e3d
9 changed files with 116 additions and 18 deletions
|
|
@ -1219,6 +1219,122 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [REDACTED_TASK_KEY] — Phase 3 unified fee API. Delegates to [DexSwapFeeCalculator] /
|
||||
* [CexSwapFeeCalculator] and wraps the result in a [SwapFee].
|
||||
*
|
||||
* Behavior parity with the legacy `loadFeeForSwapTransaction` overloads is intentional —
|
||||
* the legacy methods stay in place through Phase 4. See `SwapInteractor.loadSwapFee` for
|
||||
* the full contract.
|
||||
*/
|
||||
@Suppress("LongParameterList", "ReturnCount")
|
||||
override suspend fun loadSwapFee(
|
||||
provider: SwapProvider,
|
||||
fromStatus: SwapCurrencyStatus,
|
||||
toStatus: SwapCurrencyStatus,
|
||||
amount: SwapAmount,
|
||||
swapData: SwapDataModel?,
|
||||
selectedFeeToken: CryptoCurrencyStatus?,
|
||||
): Either<GetFeeError, SwapFee> = either {
|
||||
if (amount.value.signum() == 0) {
|
||||
raise(GetFeeError.UnknownError)
|
||||
}
|
||||
return when (provider.type) {
|
||||
ExchangeProviderType.DEX,
|
||||
ExchangeProviderType.DEX_BRIDGE,
|
||||
-> loadDexSwapFee(
|
||||
fromStatus = fromStatus,
|
||||
swapData = swapData,
|
||||
selectedFeeToken = selectedFeeToken,
|
||||
)
|
||||
ExchangeProviderType.CEX -> loadCexSwapFee(
|
||||
fromStatus = fromStatus,
|
||||
amount = amount,
|
||||
selectedFeeToken = selectedFeeToken,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [REDACTED_TASK_KEY] — DEX branch of [loadSwapFee]. Pulls the cached `ExpressTransactionModel.DEX`
|
||||
* out of [swapData] and hands it to [DexSwapFeeCalculator]. Maps [ExpressDataError] →
|
||||
* `Left(GetFeeError.UnknownError)` to keep the unified surface a single error type, matching
|
||||
* what the legacy `loadFeeForSwapTransaction` overload 2 does for DEX failures (line 1027 of
|
||||
* the original code).
|
||||
*/
|
||||
private suspend fun loadDexSwapFee(
|
||||
fromStatus: SwapCurrencyStatus,
|
||||
swapData: SwapDataModel?,
|
||||
selectedFeeToken: CryptoCurrencyStatus?,
|
||||
): Either<GetFeeError, SwapFee> {
|
||||
val transaction = swapData?.transaction as? ExpressTransactionModel.DEX
|
||||
?: return GetFeeError.UnknownError.left()
|
||||
|
||||
return dexSwapFeeCalculator.calculate(
|
||||
fromSwapCurrencyStatus = fromStatus,
|
||||
transaction = transaction,
|
||||
selectedToken = selectedFeeToken,
|
||||
).fold(
|
||||
ifLeft = { GetFeeError.UnknownError.left() },
|
||||
ifRight = { dexFeeResult ->
|
||||
val feeToken = selectedFeeToken
|
||||
?: resolveNativeFeeTokenStatus(fromStatus)
|
||||
?: return@fold GetFeeError.UnknownError.left()
|
||||
SwapFeeFactory.from(
|
||||
transactionFeeResult = dexFeeResult.transactionFee,
|
||||
selectedFeeToken = feeToken,
|
||||
otherNativeFee = dexFeeResult.otherNativeFee,
|
||||
feeBucket = FeeBucket.MARKET,
|
||||
).right()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* [REDACTED_TASK_KEY] — CEX branch of [loadSwapFee]. Native-fallback behaviour is preserved: when
|
||||
* [selectedFeeToken] is null the gasless use case (invoked inside [CexSwapFeeCalculator])
|
||||
* decides native vs token. The resulting `SwapFee.selectedFeeToken` is the explicit choice
|
||||
* if provided, otherwise the native coin status of the from-token's network.
|
||||
*/
|
||||
private suspend fun loadCexSwapFee(
|
||||
fromStatus: SwapCurrencyStatus,
|
||||
amount: SwapAmount,
|
||||
selectedFeeToken: CryptoCurrencyStatus?,
|
||||
): Either<GetFeeError, SwapFee> {
|
||||
return cexSwapFeeCalculator.calculate(
|
||||
userWallet = fromStatus.userWallet,
|
||||
fromSwapCurrencyStatus = fromStatus,
|
||||
amount = amount.value,
|
||||
selectedFeeToken = selectedFeeToken,
|
||||
).fold(
|
||||
ifLeft = { it.left() },
|
||||
ifRight = { cexFeeResult ->
|
||||
val feeToken = selectedFeeToken
|
||||
?: resolveNativeFeeTokenStatus(fromStatus)
|
||||
?: return@fold GetFeeError.UnknownError.left()
|
||||
SwapFeeFactory.from(
|
||||
transactionFeeResult = cexFeeResult.transactionFee,
|
||||
selectedFeeToken = feeToken,
|
||||
otherNativeFee = BigDecimal.ZERO,
|
||||
feeBucket = FeeBucket.MARKET,
|
||||
).right()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* [REDACTED_TASK_KEY] — resolves the native-coin [CryptoCurrencyStatus] for the from-token's network.
|
||||
* Used as the default `selectedFeeToken` of [SwapFee] when the caller did not provide an
|
||||
* explicit choice. Mirrors how `SwapModel.updateFeePaidCryptoCurrencyFor` populates
|
||||
* `dataState.feePaidCryptoCurrency`.
|
||||
*/
|
||||
private suspend fun resolveNativeFeeTokenStatus(fromStatus: SwapCurrencyStatus): CryptoCurrencyStatus? {
|
||||
return getFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
userWalletId = fromStatus.userWalletId,
|
||||
cryptoCurrencyStatus = fromStatus.status,
|
||||
).getOrNull()
|
||||
}
|
||||
|
||||
private suspend fun storeLastCryptoCurrencyId(swapCurrencyStatus: SwapCurrencyStatus) {
|
||||
swapTransactionRepository.storeLastSwappedCryptoCurrencyId(
|
||||
userWalletId = swapCurrencyStatus.userWalletId,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package com.tangem.feature.swap.domain.fee
|
||||
|
||||
import com.tangem.feature.swap.domain.TransactionFeeResult
|
||||
|
||||
/**
|
||||
* Result of calculating the CEX swap transaction fee.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.tangem.domain.transaction.error.GetFeeError
|
|||
import com.tangem.domain.transaction.usecase.EstimateFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.gasless.EstimateFeeForGaslessTxUseCase
|
||||
import com.tangem.domain.transaction.usecase.gasless.EstimateFeeForTokenUseCase
|
||||
import com.tangem.feature.swap.domain.TransactionFeeResult
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.feature.swap.domain.fee
|
||||
|
||||
import com.tangem.feature.swap.domain.TransactionFeeResult
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import com.tangem.domain.transaction.usecase.GetEthSpecificFeeUseCase
|
|||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.gasless.GetFeeForTokenUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.feature.swap.domain.TransactionFeeResult
|
||||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||
import com.tangem.feature.swap.domain.models.domain.ExpressTransactionModel
|
||||
import com.tangem.lib.crypto.BlockchainUtils.SOLANA_TRANSACTION_SIZE_THRESHOLD_BYTES
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import com.tangem.domain.transaction.models.TransactionFeeExtended
|
|||
import com.tangem.domain.transaction.usecase.EstimateFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.gasless.EstimateFeeForGaslessTxUseCase
|
||||
import com.tangem.domain.transaction.usecase.gasless.EstimateFeeForTokenUseCase
|
||||
import com.tangem.feature.swap.domain.TransactionFeeResult
|
||||
import com.tangem.feature.swap.domain.buildSwapCurrencyStatus
|
||||
import io.mockk.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
|||
import com.tangem.feature.swap.domain.fee.PatchEthGasLimitForSwap
|
||||
import com.tangem.domain.transaction.usecase.gasless.GetFeeForTokenUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.feature.swap.domain.TransactionFeeResult
|
||||
import com.tangem.feature.swap.domain.buildSwapCurrencyStatus
|
||||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -129,7 +128,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -155,7 +153,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -181,7 +178,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = true,
|
||||
)
|
||||
|
||||
|
|
@ -207,7 +203,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -237,7 +232,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -265,7 +259,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -296,7 +289,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -322,7 +314,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -351,7 +342,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
@ -378,7 +368,6 @@ internal class SwapNotificationsFactoryFeeWarningsTest {
|
|||
quoteModel = quoteModel,
|
||||
feeCryptoCurrencyStatus = feeStatus,
|
||||
selectedFeeType = FeeType.NORMAL,
|
||||
providerName = "TestProvider",
|
||||
hideFee = false,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue