Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-27 11:27:48 +04:00
parent d1c13037e0
commit 6626b53394
8 changed files with 85 additions and 53 deletions

View file

@ -3,7 +3,7 @@ package com.tangem.data.walletconnect.network.ethereum
import arrow.core.left
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.tokenmethods.ApprovalERC20TokenCallData
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Amount as BlockchainAmount
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.extensions.formatHex
@ -15,7 +15,9 @@ import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
import com.tangem.data.walletconnect.utils.BlockAidVerificationDelegate
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.tokens.model.Amount
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.walletconnect.model.WcApprovedAmount
import com.tangem.domain.walletconnect.model.WcEthMethod
import com.tangem.domain.walletconnect.usecase.method.*
import dagger.assisted.Assisted
@ -35,7 +37,7 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor(
WcApproval,
WcMutableFee {
private var approvalAmount: Amount? = null
private var approvalAmount: WcApprovedAmount? = null
private var dAppFee = WcEthTxHelper.getDAppFee(
network = context.network,
txParams = method.transaction,
@ -53,13 +55,19 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor(
val amount = WcEthTxHelper.getApprovedAmount(method.transaction.data, result)
?: return@map BlockAidTransactionCheck.Result.Plain(result)
val tokenInfo = amount.tokenInfo
if (!amount.isUnlimited) {
this@WcEthSendTransactionUseCase.approvalAmount = Amount(
currencySymbol = tokenInfo.symbol,
decimals = tokenInfo.decimals,
value = amount.approvedAmount,
)
}
this@WcEthSendTransactionUseCase.approvalAmount = WcApprovedAmount(
amount = if (!amount.isUnlimited) {
Amount(
currencySymbol = tokenInfo.symbol,
decimals = tokenInfo.decimals,
value = amount.approvedAmount,
)
} else {
null
},
logoUrl = tokenInfo.logoUrl,
chainId = tokenInfo.chainId,
)
BlockAidTransactionCheck.Result.Approval(
result = result,
approval = this,
@ -90,7 +98,9 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor(
val extras = uncompiled.extras as EthereumTransactionExtras
val callData = ApprovalERC20TokenCallData(
spenderAddress = uncompiled.sourceAddress,
amount = action.amount,
amount = action.amount?.amount?.let {
BlockchainAmount(currencySymbol = it.currencySymbol, decimals = it.decimals, value = it.value)
},
)
approvalAmount = action.amount
dAppFee = null
@ -119,11 +129,11 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor(
emitAll(delegate.invoke(transactionData))
}
override fun getAmount(): Amount? {
override fun getAmount(): WcApprovedAmount? {
return approvalAmount
}
override fun updateAmount(amount: Amount?) {
override fun updateAmount(amount: WcApprovedAmount?) {
middleAction(WcEthTxAction.UpdateApprovalAmount(amount))
}

View file

@ -3,7 +3,7 @@ package com.tangem.data.walletconnect.network.ethereum
import arrow.core.left
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.tokenmethods.ApprovalERC20TokenCallData
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Amount as BlockchainAmount
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.extensions.formatHex
@ -15,13 +15,11 @@ import com.tangem.data.walletconnect.sign.SignCollector
import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
import com.tangem.data.walletconnect.sign.WcMethodUseCaseContext
import com.tangem.data.walletconnect.utils.BlockAidVerificationDelegate
import com.tangem.domain.tokens.model.Amount
import com.tangem.domain.transaction.usecase.PrepareForSendUseCase
import com.tangem.domain.walletconnect.model.WcApprovedAmount
import com.tangem.domain.walletconnect.model.WcEthMethod
import com.tangem.domain.walletconnect.usecase.method.BlockAidTransactionCheck
import com.tangem.domain.walletconnect.usecase.method.WcApproval
import com.tangem.domain.walletconnect.usecase.method.WcMutableFee
import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase
import com.tangem.domain.walletconnect.usecase.method.*
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -43,7 +41,7 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor(
WcApproval,
WcMutableFee {
private var approvalAmount: Amount? = null
private var approvalAmount: WcApprovedAmount? = null
private var dAppFee = WcEthTxHelper.getDAppFee(
network = context.network,
txParams = method.transaction,
@ -61,10 +59,14 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor(
?: return@map BlockAidTransactionCheck.Result.Plain(result)
val tokenInfo = amount.tokenInfo
if (!amount.isUnlimited) {
approvalAmount = Amount(
currencySymbol = tokenInfo.symbol,
decimals = tokenInfo.decimals,
value = amount.approvedAmount,
approvalAmount = WcApprovedAmount(
amount = Amount(
currencySymbol = tokenInfo.symbol,
decimals = tokenInfo.decimals,
value = amount.approvedAmount,
),
logoUrl = tokenInfo.logoUrl,
chainId = tokenInfo.chainId,
)
}
BlockAidTransactionCheck.Result.Approval(
@ -98,7 +100,9 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor(
val extras = uncompiled.extras as EthereumTransactionExtras
val callData = ApprovalERC20TokenCallData(
spenderAddress = uncompiled.sourceAddress,
amount = action.amount,
amount = action.amount?.amount?.let {
BlockchainAmount(currencySymbol = it.currencySymbol, decimals = it.decimals, value = it.value)
},
)
approvalAmount = action.amount
dAppFee = null
@ -127,11 +131,11 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor(
return dAppFee
}
override fun getAmount(): Amount? {
override fun getAmount(): WcApprovedAmount? {
return approvalAmount
}
override fun updateAmount(amount: Amount?) {
override fun updateAmount(amount: WcApprovedAmount?) {
middleAction(WcEthTxAction.UpdateApprovalAmount(amount))
}

View file

@ -16,6 +16,7 @@ import com.tangem.blockchain.extensions.hexToBigDecimal
import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.common.extensions.hexToBytes
import com.tangem.domain.models.network.Network
import com.tangem.domain.walletconnect.model.WcApprovedAmount
import com.tangem.domain.walletconnect.model.WcEthTransactionParams
import java.math.BigDecimal
@ -81,5 +82,5 @@ internal object WcEthTxHelper {
sealed interface WcEthTxAction {
data class UpdateFee(val fee: Fee) : WcEthTxAction
data class UpdateApprovalAmount(val amount: Amount?) : WcEthTxAction
data class UpdateApprovalAmount(val amount: WcApprovedAmount?) : WcEthTxAction
}

View file

@ -0,0 +1,9 @@
package com.tangem.domain.walletconnect.model
import com.tangem.domain.tokens.model.Amount
data class WcApprovedAmount(
val amount: Amount?,
val chainId: Int?,
val logoUrl: String?,
)

View file

@ -1,8 +1,8 @@
package com.tangem.domain.walletconnect.usecase.method
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.walletconnect.model.WcApprovedAmount
/**
* Base UseCase for wc methods with single TransactionData
@ -40,10 +40,10 @@ interface WcMutableFee {
/**
* Wc Approval Method
* If [Amount] is null it means unlimited
* If [WcApprovedAmount.amount] is null it means unlimited
* [updateAmount] triggered a new [TransactionData] emit
*/
interface WcApproval {
fun getAmount(): Amount?
fun updateAmount(amount: Amount?)
fun getAmount(): WcApprovedAmount?
fun updateAmount(amount: WcApprovedAmount?)
}

View file

@ -105,11 +105,11 @@ internal class WcSendTransactionModel @Inject constructor(
this@WcSendTransactionModel.signState = signState
val isSecurityCheckContent = securityCheck is Lce.Content
var isApprovalMethod = isSecurityCheckContent &&
val isApprovalMethod = isSecurityCheckContent &&
securityCheck.content is BlockAidTransactionCheck.Result.Approval
wcApproval = useCase as? WcApproval
sign = { useCase.sign() }
buildUiState(securityCheck, useCase, signState)
buildUiState(securityCheck, useCase, signState, isApprovalMethod)
}
}
else -> unknownMethodRunnable()
@ -144,10 +144,14 @@ internal class WcSendTransactionModel @Inject constructor(
securityCheck: Lce<Throwable, BlockAidTransactionCheck.Result>,
useCase: WcSignUseCase<*>,
signState: WcSignState<*>,
isApproval: Boolean,
) {
val blockAidState = when (securityCheck) {
is Lce.Content -> blockAidUiConverter.convert(
WcSendAndReceiveBlockAidUiConverter.Input(securityCheck.content.result, wcApproval?.getAmount()),
WcSendAndReceiveBlockAidUiConverter.Input(
securityCheck.content.result,
if (isApproval) wcApproval?.getAmount() else null,
),
)
is Lce.Error -> WcSendReceiveTransactionCheckResultsUM(isLoading = false)
is Lce.Loading -> WcSendReceiveTransactionCheckResultsUM(isLoading = true)
@ -188,9 +192,9 @@ internal class WcSendTransactionModel @Inject constructor(
}
fun onClickDoneCustomAllowance(value: BigDecimal, isUnlimited: Boolean) {
val maxValue = if (isUnlimited) Double.MAX_VALUE.toBigDecimal() else value
val newValue = if (isUnlimited) null else value
wcApproval?.getAmount()?.let { currentAmount ->
wcApproval?.updateAmount(currentAmount.copy(maxValue = maxValue))
wcApproval?.updateAmount(currentAmount.copy(amount = currentAmount.amount?.copy(value = newValue)))
}
}

View file

@ -5,10 +5,10 @@ import com.domain.blockaid.models.transaction.SimulationResult
import com.domain.blockaid.models.transaction.ValidationResult
import com.domain.blockaid.models.transaction.simultation.AmountInfo
import com.domain.blockaid.models.transaction.simultation.SimulationData
import com.tangem.blockchain.common.Amount
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.walletconnect.model.WcApprovedAmount
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimatedWalletChangeUM
import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimatedWalletChangesUM
@ -86,7 +86,7 @@ internal class WcSendAndReceiveBlockAidUiConverter @Inject constructor(
when (data) {
is SimulationData.SendAndReceive -> null
is SimulationData.Approve -> value.approvedAmount?.let {
data.approvedAmounts.map { spendAllowanceUMConverter.convert(it) }.firstOrNull()
spendAllowanceUMConverter.convert(it)
}
}
},
@ -95,7 +95,7 @@ internal class WcSendAndReceiveBlockAidUiConverter @Inject constructor(
data class Input(
val result: CheckTransactionResult,
val approvedAmount: Amount?,
val approvedAmount: WcApprovedAmount?,
)
}

View file

@ -1,25 +1,29 @@
package com.tangem.features.walletconnect.transaction.ui.blockaid
import com.domain.blockaid.models.transaction.simultation.ApprovedAmount
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.domain.walletconnect.model.WcApprovedAmount
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.approve.WcSpendAllowanceUM
import com.tangem.utils.converter.Converter
import javax.inject.Inject
internal class WcSpendAllowanceUMConverter @Inject constructor() : Converter<ApprovedAmount, WcSpendAllowanceUM> {
internal class WcSpendAllowanceUMConverter @Inject constructor() : Converter<WcApprovedAmount, WcSpendAllowanceUM> {
override fun convert(value: ApprovedAmount) = WcSpendAllowanceUM(
amountValue = value.approvedAmount,
amountText = if (value.isUnlimited) {
TextReference.Res(R.string.wc_common_unlimited)
} else {
TextReference.Str(value.approvedAmount.amountText())
},
isUnlimited = value.isUnlimited,
tokenSymbol = value.tokenInfo.symbol,
tokenImageUrl = value.tokenInfo.logoUrl,
networkIconRes = value.tokenInfo.chainId?.toString()?.let { getActiveIconRes(it) },
)
override fun convert(value: WcApprovedAmount): WcSpendAllowanceUM {
val amount = value.amount?.value ?: 0.0.toBigDecimal()
val isUnlimited = value.amount?.value == null
return WcSpendAllowanceUM(
amountValue = amount,
amountText = if (value.amount?.value == null) {
TextReference.Res(R.string.wc_common_unlimited)
} else {
TextReference.Str(amount.amountText())
},
isUnlimited = isUnlimited,
tokenSymbol = value.amount?.currencySymbol ?: "",
tokenImageUrl = value.logoUrl,
networkIconRes = value.chainId?.toString()?.let { getActiveIconRes(it) },
)
}
}