Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-23 20:21:48 +05:00
parent 043602ebd6
commit dd362fb32c
21 changed files with 133 additions and 184 deletions

View file

@ -12,7 +12,6 @@ import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.yield.supply.YieldSupplyTransactionRepository
@ -52,28 +51,23 @@ internal class DefaultYieldSupplyTransactionRepository(
cryptoCurrency = cryptoCurrency,
) ?: error("Calculated yield contract address is null")
val yieldTokenStatus = cryptoCurrencyStatus.value.yieldSupplyStatus ?: getYieldTokenStatus(
walletManager = walletManager,
cryptoCurrency = cryptoCurrency,
)
val maxNetworkFee = maxNetworkFee.convertToSdkAmount(cryptoCurrencyStatus)
return buildEnterTransactions(
walletManager = walletManager,
cryptoCurrency = cryptoCurrency,
cryptoCurrencyStatus = cryptoCurrencyStatus,
existingYieldContractAddress = existingYieldContractAddress,
calculatedYieldContractAddress = calculatedYieldContractAddress,
yieldTokenStatus = yieldTokenStatus,
maxNetworkFee = maxNetworkFee,
)
}
override suspend fun createExitTransaction(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
yieldSupplyStatus: YieldSupplyStatus,
cryptoCurrencyStatus: CryptoCurrencyStatus,
fee: Fee?,
): TransactionData.Uncompiled = withContext(dispatchers.io) {
require(cryptoCurrency is CryptoCurrency.Token)
val cryptoCurrency = cryptoCurrencyStatus.currency as CryptoCurrency.Token
val walletManager = walletManagersFacade.getOrCreateWalletManager(
userWalletId = userWalletId,
@ -90,7 +84,7 @@ internal class DefaultYieldSupplyTransactionRepository(
cryptoCurrency = cryptoCurrency,
callData = callData,
destinationAddress = walletManager.getYieldContract(),
yieldSupplyStatus = yieldSupplyStatus,
amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrencyStatus),
fee = fee,
)
}
@ -98,13 +92,16 @@ internal class DefaultYieldSupplyTransactionRepository(
@Suppress("LongParameterList")
private fun buildEnterTransactions(
walletManager: WalletManager,
cryptoCurrency: CryptoCurrency.Token,
cryptoCurrencyStatus: CryptoCurrencyStatus,
existingYieldContractAddress: String?,
calculatedYieldContractAddress: String,
yieldTokenStatus: YieldSupplyStatus?,
maxNetworkFee: BigDecimal,
maxNetworkFee: Amount,
): MutableList<TransactionData.Uncompiled> {
val enterTransactions = mutableListOf<TransactionData.Uncompiled>()
val cryptoCurrency = cryptoCurrencyStatus.currency as CryptoCurrency.Token
val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
val amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrencyStatus)
when {
existingYieldContractAddress == null || existingYieldContractAddress == EthereumUtils.ZERO_ADDRESS -> {
@ -112,33 +109,34 @@ internal class DefaultYieldSupplyTransactionRepository(
createDeployTransaction(
walletManager = walletManager,
cryptoCurrency = cryptoCurrency,
amount = amount,
maxNetworkFee = maxNetworkFee,
),
)
}
yieldTokenStatus == null -> error("Yield token status is null")
!yieldTokenStatus.isInitialized -> enterTransactions.add(
yieldSupplyStatus == null -> error("Yield token status is null")
!yieldSupplyStatus.isInitialized -> enterTransactions.add(
createInitTokenTransaction(
walletManager = walletManager,
cryptoCurrency = cryptoCurrency,
yieldSupplyStatus = yieldTokenStatus,
yieldContractAddress = calculatedYieldContractAddress,
amount = amount,
maxNetworkFee = maxNetworkFee,
),
)
!yieldTokenStatus.isActive -> enterTransactions.add(
!yieldSupplyStatus.isActive -> enterTransactions.add(
createReactivateTokenTransaction(
walletManager = walletManager,
cryptoCurrency = cryptoCurrency,
yieldSupplyStatus = yieldTokenStatus,
yieldContractAddress = calculatedYieldContractAddress,
amount = amount,
maxNetworkFee = maxNetworkFee,
),
)
else -> Unit
}
if (yieldTokenStatus?.isAllowedToSpend != true) {
if (yieldSupplyStatus?.isAllowedToSpend != true) {
enterTransactions.add(
createTransaction(
walletManager = walletManager,
@ -148,7 +146,7 @@ internal class DefaultYieldSupplyTransactionRepository(
amount = null,
),
destinationAddress = cryptoCurrency.contractAddress,
yieldSupplyStatus = yieldTokenStatus,
amount = amount,
fee = null,
),
)
@ -158,7 +156,7 @@ internal class DefaultYieldSupplyTransactionRepository(
createEnterTransaction(
walletManager = walletManager,
cryptoCurrency = cryptoCurrency,
yieldSupplyStatus = yieldTokenStatus,
amount = amount,
yieldContractAddress = calculatedYieldContractAddress,
),
)
@ -178,8 +176,7 @@ internal class DefaultYieldSupplyTransactionRepository(
derivationPath = cryptoCurrency.network.derivationPath.value,
) ?: error("Wallet manager not found")
walletManager.calculateYieldContract()
}.onFailure(Timber::e)
.getOrNull()
}.onFailure(Timber::e).getOrNull()
}
override suspend fun getYieldContractAddress(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): String? =
@ -192,42 +189,19 @@ internal class DefaultYieldSupplyTransactionRepository(
derivationPath = cryptoCurrency.network.derivationPath.value,
) ?: error("Wallet manager not found")
walletManager.getYieldContract()
}.onFailure(Timber::e)
.getOrNull()
}.onFailure(Timber::e).getOrNull()
}
private suspend fun getYieldTokenStatus(
walletManager: WalletManager,
cryptoCurrency: CryptoCurrency,
): YieldSupplyStatus? = withContext(dispatchers.io) {
require(cryptoCurrency is CryptoCurrency.Token)
runCatching {
val sdkSupplyStatus = walletManager.getYieldSupplyStatus(cryptoCurrency.contractAddress)
val isAllowedToSpend = walletManager.isAllowedToSpend(
Token(
symbol = cryptoCurrency.symbol,
contractAddress = cryptoCurrency.contractAddress,
decimals = cryptoCurrency.decimals,
),
)
YieldSupplyStatus(
isActive = sdkSupplyStatus?.isActive == true,
isInitialized = sdkSupplyStatus?.isInitialized == true,
isAllowedToSpend = isAllowedToSpend,
)
}.onFailure(Timber::e).getOrNull()
}
private fun createDeployTransaction(
walletManager: WalletManager,
cryptoCurrency: CryptoCurrency.Token,
maxNetworkFee: BigDecimal,
amount: Amount,
maxNetworkFee: Amount,
): TransactionData.Uncompiled {
val callData = YieldSupplyContractCallDataProviderFactory.getDeployCallData(
tokenContractAddress = cryptoCurrency.contractAddress,
walletAddress = walletManager.wallet.address,
maxNetworkFee = maxNetworkFee.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = maxNetworkFee,
)
val factoryContractAddress = walletManager.getYieldSupplyContractAddresses()?.factoryContractAddress
@ -238,7 +212,7 @@ internal class DefaultYieldSupplyTransactionRepository(
cryptoCurrency = cryptoCurrency,
callData = callData,
destinationAddress = factoryContractAddress,
yieldSupplyStatus = null,
amount = amount,
fee = null,
)
}
@ -247,12 +221,12 @@ internal class DefaultYieldSupplyTransactionRepository(
walletManager: WalletManager,
cryptoCurrency: CryptoCurrency.Token,
yieldContractAddress: String,
yieldSupplyStatus: YieldSupplyStatus,
maxNetworkFee: BigDecimal,
amount: Amount,
maxNetworkFee: Amount,
): TransactionData.Uncompiled {
val callData = YieldSupplyContractCallDataProviderFactory.getInitTokenCallData(
tokenContractAddress = cryptoCurrency.contractAddress,
maxNetworkFee = maxNetworkFee.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = maxNetworkFee,
)
return createTransaction(
@ -260,7 +234,7 @@ internal class DefaultYieldSupplyTransactionRepository(
cryptoCurrency = cryptoCurrency,
callData = callData,
destinationAddress = yieldContractAddress,
yieldSupplyStatus = yieldSupplyStatus,
amount = amount,
fee = null,
)
}
@ -269,12 +243,12 @@ internal class DefaultYieldSupplyTransactionRepository(
walletManager: WalletManager,
cryptoCurrency: CryptoCurrency.Token,
yieldContractAddress: String,
yieldSupplyStatus: YieldSupplyStatus,
maxNetworkFee: BigDecimal,
amount: Amount,
maxNetworkFee: Amount,
): TransactionData.Uncompiled {
val callData = YieldSupplyContractCallDataProviderFactory.getReactivateTokenCallData(
tokenContractAddress = cryptoCurrency.contractAddress,
maxNetworkFee = maxNetworkFee.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = maxNetworkFee,
)
return createTransaction(
@ -282,7 +256,7 @@ internal class DefaultYieldSupplyTransactionRepository(
cryptoCurrency = cryptoCurrency,
callData = callData,
destinationAddress = yieldContractAddress,
yieldSupplyStatus = yieldSupplyStatus,
amount = amount,
fee = null,
)
}
@ -290,7 +264,7 @@ internal class DefaultYieldSupplyTransactionRepository(
private fun createEnterTransaction(
walletManager: WalletManager,
cryptoCurrency: CryptoCurrency.Token,
yieldSupplyStatus: YieldSupplyStatus?,
amount: Amount,
yieldContractAddress: String,
): TransactionData.Uncompiled {
val callData = YieldSupplyContractCallDataProviderFactory.getEnterCallData(
@ -302,7 +276,7 @@ internal class DefaultYieldSupplyTransactionRepository(
cryptoCurrency = cryptoCurrency,
callData = callData,
destinationAddress = yieldContractAddress,
yieldSupplyStatus = yieldSupplyStatus,
amount = amount,
fee = null,
)
}
@ -313,7 +287,7 @@ internal class DefaultYieldSupplyTransactionRepository(
cryptoCurrency: CryptoCurrency,
callData: SmartContractCallData,
destinationAddress: String,
yieldSupplyStatus: YieldSupplyStatus?,
amount: Amount,
fee: Fee?,
): TransactionData.Uncompiled {
requireNotNull(cryptoCurrency as? CryptoCurrency.Token)
@ -324,8 +298,6 @@ internal class DefaultYieldSupplyTransactionRepository(
blockchain = blockchain,
)
val amount = getYieldSupplyAmount(cryptoCurrency, yieldSupplyStatus)
return if (fee != null) {
walletManager.createTransaction(
amount = amount,
@ -365,19 +337,4 @@ internal class DefaultYieldSupplyTransactionRepository(
else -> error("Data extras not supported for $blockchain")
}
}
private fun getYieldSupplyAmount(cryptoCurrency: CryptoCurrency.Token, yieldSupplyStatus: YieldSupplyStatus?) =
BigDecimal.ZERO.convertToSdkAmount(
cryptoCurrency = cryptoCurrency,
amountType = AmountType.TokenYieldSupply(
token = Token(
symbol = cryptoCurrency.symbol,
contractAddress = cryptoCurrency.contractAddress,
decimals = cryptoCurrency.decimals,
),
isActive = yieldSupplyStatus?.isActive ?: false,
isInitialized = yieldSupplyStatus?.isInitialized ?: false,
isAllowedToSpend = yieldSupplyStatus?.isAllowedToSpend ?: false,
),
)
}

View file

@ -88,7 +88,7 @@ class DefaultYieldSupplyTransactionRepositoryTest {
val firstExpectedCallData = YieldSupplyContractCallDataProviderFactory.getDeployCallData(
walletAddress = walletManager.wallet.address,
tokenContractAddress = mockedContractAddress,
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrencyStatus),
)
val firstTransaction = result.first()
@ -141,7 +141,7 @@ class DefaultYieldSupplyTransactionRepositoryTest {
// Check transaction - init token
val firstExpectedCallData = YieldSupplyContractCallDataProviderFactory.getInitTokenCallData(
tokenContractAddress = mockedContractAddress,
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrencyStatus),
)
val firstTransaction = result.first()
@ -194,7 +194,7 @@ class DefaultYieldSupplyTransactionRepositoryTest {
// Check transaction - reactivate token
val firstExpectedCallData = YieldSupplyContractCallDataProviderFactory.getReactivateTokenCallData(
tokenContractAddress = mockedContractAddress,
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrencyStatus),
)
val firstTransaction = result.first()
@ -247,7 +247,7 @@ class DefaultYieldSupplyTransactionRepositoryTest {
// Check transaction - reactivate token
val firstExpectedCallData = YieldSupplyContractCallDataProviderFactory.getReactivateTokenCallData(
tokenContractAddress = mockedContractAddress,
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = BigDecimal.TEN.convertToSdkAmount(cryptoCurrencyStatus),
)
val firstTransaction = result.first()

View file

@ -3,30 +3,37 @@ package com.tangem.domain.utils
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Token
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import java.math.BigDecimal
import com.tangem.blockchain.common.Amount as SdkAmount
/** Converts `BigDecimal` [cryptoCurrency] to [SdkAmount] */
fun BigDecimal.convertToSdkAmount(
cryptoCurrency: CryptoCurrency,
amountType: AmountType = getAmountTypeFromCryptoCurrency(cryptoCurrency),
): SdkAmount = SdkAmount(
currencySymbol = cryptoCurrency.symbol,
value = this,
decimals = cryptoCurrency.decimals,
type = amountType,
)
/**
* Converts [CryptoCurrency] to [AmountType] based on its type
*/
private fun getAmountTypeFromCryptoCurrency(cryptoCurrency: CryptoCurrency) = when (cryptoCurrency) {
is CryptoCurrency.Coin -> AmountType.Coin
is CryptoCurrency.Token -> AmountType.Token(
token = Token(
symbol = cryptoCurrency.symbol,
contractAddress = cryptoCurrency.contractAddress,
decimals = cryptoCurrency.decimals,
),
/** Converts `BigDecimal` [cryptoCurrencyStatus] to [SdkAmount] */
fun BigDecimal.convertToSdkAmount(cryptoCurrencyStatus: CryptoCurrencyStatus): SdkAmount {
val cryptoCurrency = cryptoCurrencyStatus.currency
val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
return SdkAmount(
currencySymbol = cryptoCurrency.symbol,
value = this,
decimals = cryptoCurrency.decimals,
type = when (cryptoCurrency) {
is CryptoCurrency.Coin -> AmountType.Coin
is CryptoCurrency.Token -> {
val token = Token(
symbol = cryptoCurrency.symbol,
contractAddress = cryptoCurrency.contractAddress,
decimals = cryptoCurrency.decimals,
)
if (yieldSupplyStatus == null) {
AmountType.Token(token = token)
} else {
AmountType.TokenYieldSupply(
token = token,
isActive = yieldSupplyStatus.isActive,
isInitialized = yieldSupplyStatus.isInitialized,
isAllowedToSpend = yieldSupplyStatus.isAllowedToSpend,
)
}
}
},
)
}

View file

@ -2,10 +2,10 @@ package com.tangem.domain.transaction.usecase
import arrow.core.Either
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.transaction.TransactionRepository
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.domain.models.wallet.UserWalletId
import java.math.BigDecimal
/**
@ -17,7 +17,7 @@ class CreateApprovalTransactionUseCase(
@Suppress("LongParameterList")
suspend operator fun invoke(
cryptoCurrency: CryptoCurrency.Token,
cryptoCurrencyStatus: CryptoCurrencyStatus,
userWalletId: UserWalletId,
amount: BigDecimal?,
fee: Fee?,
@ -25,31 +25,31 @@ class CreateApprovalTransactionUseCase(
spenderAddress: String,
) = Either.catch {
transactionRepository.createApprovalTransaction(
amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrency),
approvalAmount = amount?.convertToSdkAmount(cryptoCurrency),
amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrencyStatus),
approvalAmount = amount?.convertToSdkAmount(cryptoCurrencyStatus),
contractAddress = contractAddress,
spenderAddress = spenderAddress,
userWalletId = userWalletId,
network = cryptoCurrency.network,
network = cryptoCurrencyStatus.currency.network,
fee = fee,
)
}
@Suppress("LongParameterList")
suspend operator fun invoke(
cryptoCurrency: CryptoCurrency.Token,
cryptoCurrencyStatus: CryptoCurrencyStatus,
userWalletId: UserWalletId,
amount: BigDecimal?,
contractAddress: String,
spenderAddress: String,
) = Either.catch {
transactionRepository.createApprovalTransaction(
amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrency),
approvalAmount = amount?.convertToSdkAmount(cryptoCurrency),
amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrencyStatus),
approvalAmount = amount?.convertToSdkAmount(cryptoCurrencyStatus),
contractAddress = contractAddress,
spenderAddress = spenderAddress,
userWalletId = userWalletId,
network = cryptoCurrency.network,
network = cryptoCurrencyStatus.currency.network,
fee = null,
)
}

View file

@ -3,18 +3,17 @@ package com.tangem.domain.transaction.usecase
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.blockchain.extensions.Result
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.demo.DemoTransactionSender
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.wallet.UserWallet
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.error.mapToFeeError
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.models.wallet.UserWallet
import java.math.BigDecimal
/**
@ -27,13 +26,13 @@ class EstimateFeeUseCase(
suspend operator fun invoke(
amount: BigDecimal,
userWallet: UserWallet,
cryptoCurrency: CryptoCurrency,
cryptoCurrencyStatus: CryptoCurrencyStatus,
): Either<GetFeeError, TransactionFee> {
val amountData = convertCryptoCurrencyToAmount(cryptoCurrency, amount)
val amountData = amount.convertToSdkAmount(cryptoCurrencyStatus)
val result = if (userWallet is UserWallet.Cold &&
demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)
) {
demoTransactionSender(userWallet, cryptoCurrency).estimateFee(
demoTransactionSender(userWallet, cryptoCurrencyStatus.currency).estimateFee(
amount = amountData,
destination = "",
)
@ -41,7 +40,7 @@ class EstimateFeeUseCase(
walletManagersFacade.estimateFee(
amount = amountData,
userWalletId = userWallet.walletId,
network = cryptoCurrency.network,
network = cryptoCurrencyStatus.currency.network,
)
}
@ -62,20 +61,4 @@ class EstimateFeeUseCase(
?: error("WalletManager is null"),
)
}
private fun convertCryptoCurrencyToAmount(cryptoCurrency: CryptoCurrency, amount: BigDecimal) = Amount(
currencySymbol = cryptoCurrency.symbol,
value = amount,
decimals = cryptoCurrency.decimals,
type = when (cryptoCurrency) {
is CryptoCurrency.Coin -> AmountType.Coin
is CryptoCurrency.Token -> AmountType.Token(
token = Token(
symbol = cryptoCurrency.symbol,
contractAddress = cryptoCurrency.contractAddress,
decimals = cryptoCurrency.decimals,
),
)
},
)
}

View file

@ -5,7 +5,6 @@ import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
import java.math.BigDecimal
interface YieldSupplyTransactionRepository {
@ -18,8 +17,7 @@ interface YieldSupplyTransactionRepository {
suspend fun createExitTransaction(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
yieldSupplyStatus: YieldSupplyStatus,
cryptoCurrencyStatus: CryptoCurrencyStatus,
fee: Fee?,
): TransactionData.Uncompiled

View file

@ -16,13 +16,9 @@ class YieldSupplyStopEarningUseCase(
cryptoCurrencyStatus: CryptoCurrencyStatus,
fee: Fee?,
): Either<Throwable, TransactionData.Uncompiled> = Either.catch {
val yieldTokenStatus = cryptoCurrencyStatus.value.yieldSupplyStatus ?: error("")
val cryptoCurrency = cryptoCurrencyStatus.currency
yieldSupplyTransactionRepository.createExitTransaction(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
yieldSupplyStatus = yieldTokenStatus,
cryptoCurrencyStatus = cryptoCurrencyStatus,
fee = null,
)
}

View file

@ -11,6 +11,7 @@ import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.blockchain.yieldsupply.YieldSupplyContractCallDataProviderFactory
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.transaction.FeeRepository
import com.tangem.domain.transaction.error.FeeErrorResolver
@ -35,6 +36,10 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
private val cryptoCurrency: CryptoCurrency = mockk(relaxed = true) {
every { decimals } returns 18
}
private val cryptoCurrencyStatus = mockk<CryptoCurrencyStatus>(relaxed = true) {
every { currency } returns cryptoCurrency
every { value.yieldSupplyStatus } returns null
}
private fun ethLegacyFee(
gasPrice: BigInteger = BigInteger.valueOf(100_000_000_000L),
@ -42,7 +47,7 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
) = Fee.Ethereum.Legacy(
gasPrice = gasPrice,
gasLimit = gasLimit,
amount = BigDecimal.ONE.convertToSdkAmount(cryptoCurrency),
amount = BigDecimal.ONE.convertToSdkAmount(cryptoCurrencyStatus),
)
private fun ethEip1559Fee(
@ -52,12 +57,12 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
maxFeePerGas = maxFeePerGas,
priorityFee = BigInteger.ONE,
gasLimit = gasLimit,
amount = BigDecimal.ONE.convertToSdkAmount(cryptoCurrency),
amount = BigDecimal.ONE.convertToSdkAmount(cryptoCurrencyStatus),
)
private fun uncompiled(fee: Fee, extras: TransactionExtras) = TransactionData.Uncompiled(
fee = fee,
amount = BigDecimal.ONE.convertToSdkAmount(cryptoCurrency),
amount = BigDecimal.ONE.convertToSdkAmount(cryptoCurrencyStatus),
contractAddress = null,
sourceAddress = "0x1234567890123456789012345678901234567890",
destinationAddress = "0x1234567890123456789012345678901234567890",
@ -214,7 +219,7 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
YieldSupplyContractCallDataProviderFactory.getDeployCallData(
walletAddress = "0x1234567890123456789012345678901234567890",
tokenContractAddress = "0x1234567890123456789012345678901234567890",
maxNetworkFee = BigDecimal.ONE.convertToSdkAmount(cryptoCurrency),
maxNetworkFee = BigDecimal.ONE.convertToSdkAmount(cryptoCurrencyStatus),
),
),
)

View file

@ -317,7 +317,7 @@ internal class SendConfirmModel @Inject constructor(
null
}
val amount = receivingAmount?.convertToSdkAmount(cryptoCurrency)
val amount = receivingAmount?.convertToSdkAmount(cryptoCurrencyStatus)
saveBlockchainErrorUseCase(
error = BlockchainErrorInfo(
@ -331,7 +331,7 @@ internal class SendConfirmModel @Inject constructor(
""
},
amount = amount?.value?.stripZeroPlainString() ?: "unknown",
fee = feeValue?.convertToSdkAmount(cryptoCurrency)
fee = feeValue?.convertToSdkAmount(cryptoCurrencyStatus)
?.value?.stripZeroPlainString() ?: "unknown",
),
)
@ -424,7 +424,7 @@ internal class SendConfirmModel @Inject constructor(
modelScope.launch {
createTransferTransactionUseCase(
amount = receivingAmount.convertToSdkAmount(cryptoCurrency),
amount = receivingAmount.convertToSdkAmount(cryptoCurrencyStatus),
fee = fee,
memo = memo,
nonce = nonce,

View file

@ -260,10 +260,11 @@ internal class SendModel @Inject constructor(
suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
val predefinedValues = predefinedValues
val cryptoCurrencyStatus = cryptoCurrencyStatusFlow.value
val transferTransaction = if (predefinedValues is PredefinedValues.Content.Deeplink) {
val predefinedAmount = predefinedValues.amount.parseBigDecimalOrNull()?.convertToSdkAmount(cryptoCurrency)
val predefinedAmount = predefinedValues.amount.parseBigDecimalOrNull()
createTransferTransactionUseCase(
amount = predefinedAmount ?: error("Invalid amount"),
amount = predefinedAmount?.convertToSdkAmount(cryptoCurrencyStatus) ?: error("Invalid amount"),
memo = predefinedValues.memo,
destination = predefinedValues.address,
userWalletId = userWallet.walletId,
@ -277,7 +278,7 @@ internal class SendModel @Inject constructor(
val enteredAmount = amountUM.amountTextField.cryptoAmount.value ?: error("Invalid amount")
createTransferTransactionUseCase(
amount = enteredAmount.convertToSdkAmount(cryptoCurrency),
amount = enteredAmount.convertToSdkAmount(cryptoCurrencyStatus),
memo = enteredMemo,
destination = enteredDestinationAddress,
userWalletId = userWallet.walletId,

View file

@ -287,7 +287,7 @@ internal class NotificationsModel @Inject constructor(
) {
val validationError = validateTransactionUseCase(
userWalletId = userWalletId,
amount = enteredAmount.convertToSdkAmount(currency),
amount = enteredAmount.convertToSdkAmount(cryptoCurrencyStatus),
fee = fee,
memo = memo,
destination = destinationAddress,

View file

@ -651,7 +651,7 @@ internal class StakingModel @Inject constructor(
contractAddress = tokenCryptoCurrency.contractAddress,
spenderAddress = approval.spenderAddress,
fee = fee,
cryptoCurrency = tokenCryptoCurrency,
cryptoCurrencyStatus = cryptoCurrencyStatus,
userWalletId = userWalletId,
).fold(
ifLeft = { error ->

View file

@ -189,7 +189,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
val tokenCurrency = cryptoCurrencyStatus.currency as? CryptoCurrency.Token
?: return onApprovalFeeError(GetFeeError.UnknownError)
val approvalTransactionData = createApprovalTransactionUseCase(
cryptoCurrency = tokenCurrency,
cryptoCurrencyStatus = cryptoCurrencyStatus,
userWalletId = userWallet.walletId,
amount = amount,
contractAddress = tokenCurrency.contractAddress,

View file

@ -158,7 +158,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
getConstructedStakingTransactionUseCase(
networkId = cryptoCurrencyStatus.currency.network.rawId,
fee = fee,
amount = amount.convertToSdkAmount(cryptoCurrencyStatus.currency),
amount = amount.convertToSdkAmount(cryptoCurrencyStatus),
transactionId = transaction.id,
).fold(
ifRight = { (constructedTransaction, transactionData) ->

View file

@ -227,7 +227,7 @@ internal class SendWithSwapConfirmModel @Inject constructor(
estimateFeeUseCase(
amount = amountValue,
userWallet = params.userWallet,
cryptoCurrency = primaryCurrencyStatus.currency,
cryptoCurrencyStatus = primaryCurrencyStatus,
).map {
it.patchTransactionFeeForSwap(INCREASE_GAS_LIMIT_FOR_CEX)
}

View file

@ -131,7 +131,7 @@ internal class SwapTransactionSender @AssistedInject constructor(
}
val txData = createTransferTransactionUseCase(
amount = fromAmount.convertToSdkAmount(fromStatus.currency),
amount = fromAmount.convertToSdkAmount(fromStatus),
fee = fee,
memo = swapTransaction.txExtraId,
destination = swapTransaction.txTo,

View file

@ -307,7 +307,7 @@ private fun SendWithSwapSuccessContent_Preview() {
fees = TransactionFee.Single(
normal = Fee.Common(
BigDecimal.ONE.convertToSdkAmount(
SwapAmountContentPreview.cryptoCurrencyStatus.currency,
SwapAmountContentPreview.cryptoCurrencyStatus,
),
),
),
@ -315,7 +315,7 @@ private fun SendWithSwapSuccessContent_Preview() {
selectedFeeItem = FeeItem.Market(
Fee.Common(
BigDecimal.ONE.convertToSdkAmount(
SwapAmountContentPreview.cryptoCurrencyStatus.currency,
SwapAmountContentPreview.cryptoCurrencyStatus,
),
),
),

View file

@ -1,6 +1,6 @@
package com.tangem.feature.swap.domain.models.domain
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.feature.swap.domain.models.ui.RequestApproveStateData
import com.tangem.feature.swap.domain.models.ui.TxFee
@ -9,14 +9,14 @@ import com.tangem.feature.swap.domain.models.ui.TxFee
*
* @param approveData tx data to give approve, it loaded from 1inch in findBestQuote if needed
* @param forTokenContractAddress token contract address for which needs permission
* @param fromToken which token will be swapping
* @param fromTokenStatus which token will be swapping
* @param approveType unlimited or tx amount approve
* @param txFee fee for tx
*/
data class PermissionOptions(
val approveData: RequestApproveStateData,
val forTokenContractAddress: String,
val fromToken: CryptoCurrency,
val fromTokenStatus: CryptoCurrencyStatus,
val spenderAddress: String,
val approveType: SwapApproveType,
val txFee: TxFee,

View file

@ -1,5 +1,6 @@
package com.tangem.feature.swap.domain
import android.util.Base64
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.blockchain.common.Amount
@ -11,6 +12,7 @@ import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
@ -52,8 +54,6 @@ import timber.log.Timber
import java.math.BigDecimal
import java.math.BigInteger
import java.math.RoundingMode
import android.util.Base64
import com.tangem.blockchainsdk.utils.toNetworkId
@Suppress("LargeClass", "LongParameterList")
internal class SwapInteractorImpl @AssistedInject constructor(
@ -227,7 +227,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
val approveTransaction = createApprovalTransactionUseCase(
fee = permissionOptions.txFee.fee,
userWalletId = userWalletId,
cryptoCurrency = permissionOptions.fromToken as CryptoCurrency.Token,
cryptoCurrencyStatus = permissionOptions.fromTokenStatus,
amount = amount?.value,
contractAddress = permissionOptions.forTokenContractAddress,
spenderAddress = permissionOptions.spenderAddress,
@ -239,7 +239,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
val result = sendTransactionUseCase(
txData = approveTransaction,
userWallet = userWallet,
network = permissionOptions.fromToken.network,
network = permissionOptions.fromTokenStatus.currency.network,
)
return result.fold(
ifRight = { hash ->
@ -546,7 +546,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
)
val result = validateTransactionUseCase(
amount = amount.value.convertToSdkAmount(currency),
amount = amount.value.convertToSdkAmount(fromToken),
fee = fee,
memo = null,
destination = getTokenAddress(fromToken.currency),
@ -842,7 +842,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
}
val txData = createTransferTransactionUseCase(
amount = amount.value.convertToSdkAmount(currencyToSend.currency),
amount = amount.value.convertToSdkAmount(currencyToSend),
fee = txFee.fee,
memo = exchangeDataCex.txExtraId,
destination = exchangeDataCex.txTo,
@ -1022,7 +1022,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
val txFeeResult = getUnhandledFee(
amount = amount.value,
userWallet = userWallet,
cryptoCurrency = fromToken,
cryptoCurrencyStatus = fromTokenStatus,
)
val txFee = if (provider.type == ExchangeProviderType.CEX) {
@ -1520,12 +1520,12 @@ internal class SwapInteractorImpl @AssistedInject constructor(
private suspend fun getUnhandledFee(
amount: BigDecimal,
userWallet: UserWallet,
cryptoCurrency: CryptoCurrency,
cryptoCurrencyStatus: CryptoCurrencyStatus,
): Either<GetFeeError, TransactionFee> {
return estimateFeeUseCase(
amount = amount,
userWallet = userWallet,
cryptoCurrency = cryptoCurrency,
cryptoCurrencyStatus = cryptoCurrencyStatus,
)
}
@ -1560,7 +1560,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
// setting up amount for approve with given amount for swap [SwapApproveType.Limited]
val callData = SmartContractCallDataProviderFactory.getApprovalCallData(
spenderAddress = requireNotNull(spenderAddress) { "Spender address is null" },
amount = swapAmount.value.convertToSdkAmount(fromToken),
amount = swapAmount.value.convertToSdkAmount(fromTokenStatus),
blockchain = fromToken.network.toBlockchain(),
)
val feeData = try {

View file

@ -700,9 +700,11 @@ internal class SwapModel @Inject constructor(
private fun givePermissionsToSwap() {
modelScope.launch(dispatchers.main) {
runCatching {
val fromToken = requireNotNull(dataState.fromCryptoCurrency?.currency) {
"dataState.fromCurrency might not be null"
val fromCryptoCurrency = requireNotNull(dataState.fromCryptoCurrency) {
"dataState.fromCryptoCurrency might not be null"
}
val fromToken = fromCryptoCurrency.currency
val approveDataModel = requireNotNull(dataState.approveDataModel) {
"dataState.approveDataModel.spenderAddress shouldn't be null"
}
@ -725,7 +727,7 @@ internal class SwapModel @Inject constructor(
permissionOptions = PermissionOptions(
approveData = approveDataModel,
forTokenContractAddress = (fromToken as? CryptoCurrency.Token)?.contractAddress.orEmpty(),
fromToken = fromToken,
fromTokenStatus = fromCryptoCurrency,
approveType = approveType,
txFee = feeForPermission,
spenderAddress = approveDataModel.spenderAddress,

View file

@ -144,7 +144,7 @@ internal class YieldSupplyApproveModel @Inject constructor(
).getOrNull() ?: return
val approvalTransitionData = createApprovalTransactionUseCase(
cryptoCurrency = cryptoCurrency,
cryptoCurrencyStatus = cryptoCurrencyStatus,
userWalletId = userWallet.walletId,
contractAddress = cryptoCurrency.contractAddress,
spenderAddress = contractAddress,