Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-02 15:15:08 +05:00
parent a3b65cd194
commit d22bfd0c87
27 changed files with 342 additions and 139 deletions

View file

@ -7,6 +7,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.R
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
@ -23,7 +24,6 @@ import com.tangem.features.send.v2.api.params.FeeSelectorParams
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import com.tangem.common.ui.R as CommonUiR
internal class DefaultGiveApprovalComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@ -38,6 +38,7 @@ internal class DefaultGiveApprovalComponent @AssistedInject constructor(
params = FeeSelectorParams.FeeSelectorBlockParams(
state = FeeSelectorUM.Loading,
onLoadFee = { model.loadFee() },
onDisableCustomFee = { model.shouldDisableCustomFee() },
onLoadFeeExtended = { selectedFeeToken -> model.loadFeeExtended(selectedFeeToken) },
feeCryptoCurrencyStatus = params.feeCryptoCurrencyStatus,
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
@ -71,22 +72,23 @@ internal class DefaultGiveApprovalComponent @AssistedInject constructor(
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
config = config,
containerColor = TangemTheme.colors.background.secondary,
titleText = resourceReference(CommonUiR.string.give_permission_title),
titleText = resourceReference(
if (uiState.isResetApproval) {
R.string.update_approval_permission_title
} else {
R.string.give_permission_title
},
),
titleAction = TopAppBarButtonUM.Icon(
iconRes = CommonUiR.drawable.ic_information_24,
iconRes = R.drawable.ic_information_24,
onClicked = model::showPermissionInfoDialog,
),
) {
GiveApprovalContent(
currency = currency,
subtitle = params.subtitle,
approveType = uiState.approveType,
approveItems = uiState.approveItems,
uiState = uiState,
onChangeApproveType = model::onChangeApproveType,
walletInteractionIcon = uiState.walletInteractionIcon,
isApproveEnabled = uiState.isApproveButtonEnabled,
isApproveLoading = uiState.isApproveLoading,
isHoldToConfirm = uiState.isHoldToConfirm,
onApproveClick = model::onApproveClick,
onCancelClick = model::onCancelClick,
onOpenLearnMoreAboutApproveClick = model::onOpenLearnMoreAboutApproveClick,

View file

@ -5,6 +5,7 @@ import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.left
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.TransactionSender.MultipleTransactionSendMode
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
@ -22,8 +23,10 @@ import com.tangem.core.ui.message.DialogMessage
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.models.AllowanceInfo
import com.tangem.domain.transaction.models.TransactionFeeExtended
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
import com.tangem.domain.transaction.usecase.GetAllowanceInfoUseCase
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.transaction.usecase.gasless.CreateAndSendGaslessTransactionUseCase
@ -32,6 +35,7 @@ import com.tangem.domain.transaction.usecase.gasless.GetFeeForTokenUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.approval.api.GiveApprovalComponent
import com.tangem.features.send.v2.api.callbacks.FeeSelectorModelCallback
import com.tangem.features.send.v2.api.entity.FeeItem
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -41,15 +45,17 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.math.BigDecimal
import java.math.RoundingMode
import javax.inject.Inject
@Stable
@ModelScoped
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LargeClass")
internal class GiveApprovalModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
paramsContainer: ParamsContainer,
private val createApprovalTransactionUseCase: CreateApprovalTransactionUseCase,
private val getAllowanceInfoUseCase: GetAllowanceInfoUseCase,
private val sendTransactionUseCase: SendTransactionUseCase,
private val getFeeUseCase: GetFeeUseCase,
private val getFeeForGaslessUseCase: GetFeeForGaslessUseCase,
@ -77,11 +83,14 @@ internal class GiveApprovalModel @Inject constructor(
isApproveButtonEnabled = false,
isApproveLoading = false,
isHoldToConfirm = params.isHoldToConfirm,
isResetApproval = params.isResetApproval,
),
)
private var feeSelectorUM: FeeSelectorUM = FeeSelectorUM.Loading
private var approvalTxList: Map<TransactionData.Uncompiled, TransactionFee> = emptyMap()
override fun onFeeResult(feeSelectorUM: FeeSelectorUM) {
this.feeSelectorUM = feeSelectorUM
uiState.update { it.copy(isApproveButtonEnabled = feeSelectorUM.isPrimaryButtonEnabled) }
@ -122,83 +131,127 @@ internal class GiveApprovalModel @Inject constructor(
)
}
suspend fun prepareApprovalTransaction(): Either<Throwable, TransactionData> {
val cryptoCurrencyStatus = params.cryptoCurrencyStatus
val tokenCurrency = cryptoCurrencyStatus.currency as? CryptoCurrency.Token
?: return Either.Left(IllegalStateException("Currency is not a token"))
return createApprovalTransactionUseCase(
cryptoCurrencyStatus = cryptoCurrencyStatus,
userWalletId = params.userWalletId,
amount = getApprovalAmount(),
contractAddress = tokenCurrency.contractAddress,
spenderAddress = params.spenderAddress,
suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
return onApprovalTx(
onApprove = { approve ->
getFeeUseCase(
transactionData = approve,
userWallet = userWallet,
network = params.cryptoCurrencyStatus.currency.network,
).onRight { fee ->
approvalTxList = mapOf(approve to fee)
}
},
onResetApprove = { (revokeApproval, approve) ->
getFeeUseCase(
transactionData = revokeApproval,
userWallet = userWallet,
network = params.cryptoCurrencyStatus.currency.network,
).map { revokeFee ->
estimateFeeForResetApproval(
revokeTransactionFee = revokeFee,
revokeApprovalTransaction = revokeApproval,
approvalTransaction = approve,
)
}
},
)
}
suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
val approvalTransaction = prepareApprovalTransaction()
.getOrElse { return GetFeeError.DataError(it).left() }
return getFeeUseCase(
transactionData = approvalTransaction,
userWallet = userWallet,
network = params.cryptoCurrencyStatus.currency.network,
)
fun shouldDisableCustomFee(): Boolean {
return approvalTxList.size > 1
}
suspend fun loadFeeExtended(maybeToken: CryptoCurrencyStatus?): Either<GetFeeError, TransactionFeeExtended> {
val approvalTransaction = prepareApprovalTransaction()
.getOrElse { return GetFeeError.DataError(it).left() }
val approve = createApprovalTransactionUseCase(
userWalletId = params.userWalletId,
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
amount = getApprovalAmount(),
contractAddress = (params.cryptoCurrencyStatus.currency as CryptoCurrency.Token).contractAddress,
spenderAddress = params.spenderAddress,
).getOrElse { error ->
TangemLogger.e("Failed to create approveTransaction", error)
return GetFeeError.DataError(error).left()
}
return if (maybeToken == null) {
getFeeForGaslessUseCase(
transactionData = approvalTransaction,
transactionData = approve,
userWallet = userWallet,
network = params.cryptoCurrencyStatus.currency.network,
)
} else {
getFeeForTokenUseCase(
transactionData = approvalTransaction,
transactionData = approve,
userWallet = userWallet,
token = maybeToken.currency,
)
}
}
private fun estimateFeeForResetApproval(
revokeTransactionFee: TransactionFee,
revokeApprovalTransaction: TransactionData.Uncompiled,
approvalTransaction: TransactionData.Uncompiled,
) = when (revokeTransactionFee) {
is TransactionFee.Choosable -> {
val approveFee = revokeTransactionFee.copy(
minimum = revokeTransactionFee.minimum.increaseEthereumGasLimitBy(2.toBigDecimal()),
normal = revokeTransactionFee.normal.increaseEthereumGasLimitBy(2.toBigDecimal()),
priority = revokeTransactionFee.priority.increaseEthereumGasLimitBy(2.toBigDecimal()),
)
approvalTxList = mapOf(
revokeApprovalTransaction to revokeTransactionFee,
approvalTransaction to approveFee,
)
revokeTransactionFee.copy(
minimum = approveFee.minimum + revokeTransactionFee.minimum,
normal = approveFee.normal + revokeTransactionFee.normal,
priority = approveFee.priority + revokeTransactionFee.priority,
)
}
is TransactionFee.Single -> {
val approveFee = revokeTransactionFee.copy(normal = revokeTransactionFee.normal)
approvalTxList = mapOf(
revokeApprovalTransaction to revokeTransactionFee,
approvalTransaction to approveFee,
)
revokeTransactionFee.copy(normal = approveFee.normal + revokeTransactionFee.normal)
}
}
private suspend fun sendApprovalTransaction(): Boolean {
val cryptoCurrencyStatus = params.cryptoCurrencyStatus
val tokenCurrency = cryptoCurrencyStatus.currency as? CryptoCurrency.Token ?: return false
val feeContent = feeSelectorUM as? FeeSelectorUM.Content ?: return false
val selectedFee = feeContent.selectedFeeItem.fee
val feeExtended = feeContent.feeExtraInfo.transactionFeeExtended
val isFeeInTokenCurrency = feeExtended?.transactionFee?.normal is Fee.Ethereum.TokenCurrency
val transactionData = createApprovalTransactionUseCase(
cryptoCurrencyStatus = cryptoCurrencyStatus,
userWalletId = params.userWalletId,
amount = getApprovalAmount(),
fee = selectedFee,
contractAddress = tokenCurrency.contractAddress,
spenderAddress = params.spenderAddress,
).getOrElse { error ->
TangemLogger.e("Failed to create approval transaction", error)
return false
val transactions = approvalTxList.map { (tx, fee) ->
tx.copy(
fee = when (feeContent.selectedFeeItem) {
is FeeItem.Fast -> (fee as? TransactionFee.Choosable)?.priority ?: fee.normal
is FeeItem.Market -> fee.normal
is FeeItem.Slow -> (fee as? TransactionFee.Choosable)?.minimum ?: fee.normal
else -> feeContent.selectedFeeItem.fee
},
)
}
return if (isFeeInTokenCurrency) {
createAndSendGaslessTransactionUseCase(
userWallet = userWallet,
transactionData = transactionData,
transactionData = transactions.first(),
fee = feeExtended,
)
} else {
sendTransactionUseCase(
txData = transactionData,
txsData = transactions,
userWallet = userWallet,
network = tokenCurrency.network,
sendMode = MultipleTransactionSendMode.DEFAULT,
)
}.fold(
ifLeft = { error ->
@ -241,4 +294,88 @@ internal class GiveApprovalModel @Inject constructor(
null
}
}
private suspend fun <T> onApprovalTx(
onApprove: suspend (TransactionData.Uncompiled) -> Either<GetFeeError, T>,
onResetApprove:
suspend (Pair<TransactionData.Uncompiled, TransactionData.Uncompiled>) -> Either<GetFeeError, T>,
): Either<GetFeeError, T> {
val cryptoCurrencyStatus = params.cryptoCurrencyStatus
val tokenCurrency = cryptoCurrencyStatus.currency as? CryptoCurrency.Token
?: return GetFeeError.DataError(IllegalStateException("Currency is not a token")).left()
val amount = params.amount.toBigDecimalOrNull()
?: return GetFeeError.DataError(IllegalArgumentException("Invalid amount format")).left()
val allowance = getAllowanceInfoUseCase(
userWalletId = params.userWalletId,
cryptoCurrency = cryptoCurrencyStatus.currency,
spenderAddress = params.spenderAddress,
requiredAmount = amount,
).getOrElse { error ->
TangemLogger.e("Failed to get allowance info", error)
return GetFeeError.DataError(error).left()
}
val approve = createApprovalTransactionUseCase(
userWalletId = params.userWalletId,
cryptoCurrencyStatus = cryptoCurrencyStatus,
amount = getApprovalAmount(),
contractAddress = tokenCurrency.contractAddress,
spenderAddress = params.spenderAddress,
).getOrElse { error ->
TangemLogger.e("Failed to create approveTransaction", error)
return GetFeeError.DataError(error).left()
}
return if (allowance is AllowanceInfo.ResetNeeded) {
val revokeApproval = createApprovalTransactionUseCase(
userWalletId = params.userWalletId,
cryptoCurrencyStatus = cryptoCurrencyStatus,
amount = BigDecimal.ZERO,
contractAddress = tokenCurrency.contractAddress,
spenderAddress = params.spenderAddress,
).getOrElse { error ->
TangemLogger.e("Failed to create revoke approveTransaction", error)
return GetFeeError.DataError(error).left()
}
onResetApprove(revokeApproval to approve)
} else {
onApprove(approve)
}
}
private fun Fee.increaseEthereumGasLimitBy(multiplier: BigDecimal): Fee {
if (this !is Fee.Ethereum) return this
val increasedGasPrice = amount.value?.movePointRight(amount.decimals)
?.divide(gasLimit.toBigDecimal(), RoundingMode.HALF_UP)
val increasedGasLimit = gasLimit
.multiply(multiplier.toBigInteger())
val increasedAmount = amount.copy(
value = increasedGasPrice?.multiply(
increasedGasLimit.toBigDecimal().movePointLeft(amount.decimals),
),
)
return when (this) {
is Fee.Ethereum.EIP1559 -> copy(amount = increasedAmount, gasLimit = increasedGasLimit)
is Fee.Ethereum.Legacy -> copy(amount = increasedAmount, gasLimit = increasedGasLimit)
is Fee.Ethereum.TokenCurrency -> error("handle in [REDACTED_TASK_KEY]")
}
}
private operator fun Fee.plus(otherFee: Fee): Fee {
if (this !is Fee.Ethereum || otherFee !is Fee.Ethereum) return this
val gasLimit = this.gasLimit
val increasedGasPrice = this.amount.value?.movePointRight(this.amount.decimals)
?.divide(gasLimit.toBigDecimal(), RoundingMode.HALF_UP)
val increasedGasLimit = gasLimit + otherFee.gasLimit
val increasedAmount = this.amount.copy(
value = increasedGasLimit.toBigDecimal().multiply(increasedGasPrice).movePointLeft(this.amount.decimals),
)
return when (this) {
is Fee.Ethereum.EIP1559 -> copy(amount = increasedAmount, gasLimit = increasedGasLimit)
is Fee.Ethereum.Legacy -> copy(amount = increasedAmount, gasLimit = increasedGasLimit)
is Fee.Ethereum.TokenCurrency -> this
}
}
}

View file

@ -12,4 +12,5 @@ internal data class GiveApprovalUM(
val isApproveButtonEnabled: Boolean,
val isApproveLoading: Boolean,
val isHoldToConfirm: Boolean = false,
val isResetApproval: Boolean = false,
)

View file

@ -27,28 +27,24 @@ import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.window.PopupProperties
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
import com.tangem.core.ui.R
import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.containers.FooterContainer
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.approval.impl.model.GiveApprovalUM
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import com.tangem.common.ui.R as CommonUiR
@Composable
@Suppress("LongParameterList")
internal fun GiveApprovalContent(
currency: String,
uiState: GiveApprovalUM,
subtitle: TextReference,
approveType: ApproveType,
approveItems: ImmutableList<ApproveType>,
onChangeApproveType: (ApproveType) -> Unit,
walletInteractionIcon: Int?,
isApproveEnabled: Boolean,
isApproveLoading: Boolean,
isHoldToConfirm: Boolean,
onApproveClick: () -> Unit,
onCancelClick: () -> Unit,
onOpenLearnMoreAboutApproveClick: () -> Unit,
@ -73,20 +69,21 @@ internal fun GiveApprovalContent(
ApprovalInfo(
currency = currency,
approveType = approveType,
approveItems = approveItems,
approveType = uiState.approveType,
approveItems = uiState.approveItems,
onChangeApproveType = onChangeApproveType,
onOpenLearnMoreAboutApproveClick = onOpenLearnMoreAboutApproveClick,
feeSelectorBlockComponent = feeSelectorBlockComponent,
isResetApproval = uiState.isResetApproval,
)
SpacerH(height = TangemTheme.dimens.spacing20)
if (isHoldToConfirm) {
if (uiState.isHoldToConfirm) {
HoldToConfirmButton(
text = stringResourceSafe(id = CommonUiR.string.common_approve),
enabled = isApproveEnabled,
isLoading = isApproveLoading,
text = stringResourceSafe(id = R.string.common_approve),
enabled = uiState.isApproveButtonEnabled,
isLoading = uiState.isApproveLoading,
onConfirm = onApproveClick,
modifier = Modifier
.fillMaxWidth()
@ -94,21 +91,21 @@ internal fun GiveApprovalContent(
)
} else {
PrimaryButtonIconEnd(
text = stringResourceSafe(id = CommonUiR.string.common_approve),
iconResId = walletInteractionIcon,
showProgress = isApproveLoading,
text = stringResourceSafe(id = R.string.common_approve),
iconResId = uiState.walletInteractionIcon,
showProgress = uiState.isApproveLoading,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing16),
onClick = onApproveClick,
enabled = isApproveEnabled,
enabled = uiState.isApproveButtonEnabled,
)
}
SpacerH12()
SecondaryButton(
text = stringResourceSafe(id = CommonUiR.string.common_cancel),
text = stringResourceSafe(id = R.string.common_cancel),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing16),
@ -124,6 +121,7 @@ internal fun GiveApprovalContent(
private fun ApprovalInfo(
currency: String,
approveType: ApproveType,
isResetApproval: Boolean,
approveItems: ImmutableList<ApproveType>,
onChangeApproveType: (ApproveType) -> Unit,
onOpenLearnMoreAboutApproveClick: () -> Unit,
@ -131,7 +129,7 @@ private fun ApprovalInfo(
) {
FooterContainer(
footer = annotatedReference {
append(stringResourceSafe(CommonUiR.string.swap_approve_description))
append(stringResourceSafe(R.string.swap_approve_description))
append(" ")
withLink(
link = LinkAnnotation.Clickable(
@ -140,7 +138,7 @@ private fun ApprovalInfo(
),
block = {
appendColored(
text = stringResourceSafe(CommonUiR.string.common_learn_more),
text = stringResourceSafe(R.string.common_learn_more),
color = TangemTheme.colors.text.accent,
)
},
@ -157,7 +155,13 @@ private fun ApprovalInfo(
}
SpacerH16()
FooterContainer(
footer = resourceReference(CommonUiR.string.give_permission_policy_type_footer),
footer = resourceReference(
if (isResetApproval) {
R.string.update_approval_permission_fee_note
} else {
R.string.give_permission_policy_type_footer
},
),
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
) {
feeSelectorBlockComponent.Content(
@ -202,7 +206,7 @@ private fun AmountItem(
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResourceSafe(id = CommonUiR.string.give_permission_rows_amount, currency),
text = stringResourceSafe(id = R.string.give_permission_rows_amount, currency),
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography.subtitle1,
maxLines = 1,
@ -215,7 +219,7 @@ private fun AmountItem(
maxLines = 1,
)
Icon(
painter = rememberVectorPainter(ImageVector.vectorResource(id = CommonUiR.drawable.ic_chevron_24)),
painter = rememberVectorPainter(ImageVector.vectorResource(id = R.drawable.ic_chevron_24)),
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
modifier = Modifier.padding(start = TangemTheme.dimens.spacing2),
@ -275,10 +279,10 @@ private fun DropdownSelector(
Text(
text = when (item) {
ApproveType.LIMITED -> stringResourceSafe(
id = CommonUiR.string.give_permission_current_transaction,
id = R.string.give_permission_current_transaction,
)
ApproveType.UNLIMITED -> stringResourceSafe(
id = CommonUiR.string.give_permission_unlimited,
id = R.string.give_permission_unlimited,
)
},
color = TangemTheme.colors.text.primary1,
@ -288,7 +292,7 @@ private fun DropdownSelector(
SpacerWMax()
Icon(
painter = rememberVectorPainter(
image = ImageVector.vectorResource(id = CommonUiR.drawable.ic_check_24),
image = ImageVector.vectorResource(id = R.drawable.ic_check_24),
),
tint = color,
contentDescription = null,
@ -316,13 +320,8 @@ private fun GiveApprovalContentPreview(
GiveApprovalContent(
currency = params.currency,
subtitle = params.subtitle,
approveType = params.approveType,
approveItems = params.approveItems,
uiState = params.uiState,
onChangeApproveType = {},
walletInteractionIcon = params.walletInteractionIcon,
isApproveEnabled = params.isApproveEnabled,
isApproveLoading = params.isApproveLoading,
isHoldToConfirm = false,
onApproveClick = {},
onCancelClick = {},
onOpenLearnMoreAboutApproveClick = {},
@ -334,11 +333,7 @@ private fun GiveApprovalContentPreview(
private data class GiveApprovalPreviewParams(
val currency: String,
val subtitle: TextReference,
val approveType: ApproveType,
val approveItems: ImmutableList<ApproveType>,
val walletInteractionIcon: Int?,
val isApproveEnabled: Boolean,
val isApproveLoading: Boolean,
val uiState: GiveApprovalUM,
)
private class GiveApprovalContentPreviewProvider : PreviewParameterProvider<GiveApprovalPreviewParams> {
@ -347,20 +342,36 @@ private class GiveApprovalContentPreviewProvider : PreviewParameterProvider<Give
GiveApprovalPreviewParams(
currency = "USDT",
subtitle = stringReference("Allow this app to access your USDT"),
approveType = ApproveType.LIMITED,
approveItems = persistentListOf(ApproveType.LIMITED, ApproveType.UNLIMITED),
walletInteractionIcon = CommonUiR.drawable.ic_tangem_24,
isApproveEnabled = true,
isApproveLoading = false,
uiState = GiveApprovalUM(
approveType = ApproveType.LIMITED,
approveItems = persistentListOf(ApproveType.LIMITED, ApproveType.UNLIMITED),
walletInteractionIcon = R.drawable.ic_tangem_24,
isApproveButtonEnabled = true,
isApproveLoading = false,
),
),
GiveApprovalPreviewParams(
currency = "USDC",
subtitle = stringReference("Allow this app to access your USDC"),
approveType = ApproveType.UNLIMITED,
approveItems = persistentListOf(ApproveType.LIMITED, ApproveType.UNLIMITED),
walletInteractionIcon = CommonUiR.drawable.ic_tangem_24,
isApproveEnabled = false,
isApproveLoading = true,
uiState = GiveApprovalUM(
approveType = ApproveType.UNLIMITED,
approveItems = persistentListOf(ApproveType.LIMITED, ApproveType.UNLIMITED),
walletInteractionIcon = R.drawable.ic_tangem_24,
isApproveButtonEnabled = false,
isApproveLoading = true,
),
),
GiveApprovalPreviewParams(
currency = "USDC",
subtitle = stringReference("Allow this app to access your USDC"),
uiState = GiveApprovalUM(
approveType = ApproveType.UNLIMITED,
approveItems = persistentListOf(ApproveType.LIMITED, ApproveType.UNLIMITED),
walletInteractionIcon = R.drawable.ic_tangem_24,
isApproveButtonEnabled = true,
isApproveLoading = false,
isResetApproval = true,
),
),
)
}