Updated on 2026-08-14

This commit is contained in:
Tangem 2023-05-31 09:58:40 +03:00
parent 5f1f826412
commit 7a177e3467
13 changed files with 274 additions and 100 deletions

View file

@ -87,12 +87,54 @@ sealed class AnalyticsParam {
}
sealed class TxSentFrom(val value: String) {
object Send : TxSentFrom("Send")
object Swap : TxSentFrom("Swap")
data class Send(
override val blockchain: String,
override val token: String,
override val feeType: FeeType,
) : TxSentFrom("Send"), TxData
data class Swap(
override val blockchain: String,
override val token: String,
override val feeType: FeeType,
) : TxSentFrom("Swap"), TxData
data class Approve(
override val blockchain: String,
override val token: String,
override val feeType: FeeType,
val permissionType: String,
) : TxSentFrom("Approve"), TxData
object WalletConnect : TxSentFrom("WalletConnect")
object Sell : TxSentFrom("Sell")
}
sealed interface TxData {
val blockchain: String
val token: String
val feeType: FeeType
}
sealed class FeeType(val value: String) {
object Fixed : FeeType("Fixed")
object Min : FeeType("Min")
object Normal : FeeType("Normal")
object Max : FeeType("Max")
companion object {
fun fromString(feeType: String): FeeType {
return when (feeType) {
Min.value -> Min
Normal.value -> Normal
Max.value -> Max
Fixed.value -> Fixed
else -> Fixed
}
}
}
}
sealed class WalletCreationType(val value: String) {
object PrivateKey : WalletCreationType("Private key")
object NewSeed : WalletCreationType("New seed")
@ -100,9 +142,13 @@ sealed class AnalyticsParam {
}
companion object Key {
const val BLOCKCHAIN = "blockchain"
const val TOKEN = "Token"
const val SOURCE = "Source"
const val BALANCE = "Balance"
const val BATCH = "Batch"
const val FEE_TYPE = "Fee Type"
const val PERMISSION_TYPE = "Permission Type"
const val PRODUCT_TYPE = "Product Type"
const val FIRMWARE = "Firmware"
const val CURRENCY = "Currency"

View file

@ -51,7 +51,17 @@ sealed class Basic(
class TransactionSent(sentFrom: AnalyticsParam.TxSentFrom) : Basic(
event = "Transaction sent",
params = mapOf(AnalyticsParam.SOURCE to sentFrom.value),
params = buildMap {
this[AnalyticsParam.SOURCE] = sentFrom.value
if (sentFrom is AnalyticsParam.TxData) {
this[AnalyticsParam.BLOCKCHAIN] = sentFrom.blockchain
this[AnalyticsParam.TOKEN] = sentFrom.token
this[AnalyticsParam.FEE_TYPE] = sentFrom.feeType.value
}
if (sentFrom is AnalyticsParam.TxSentFrom.Approve) {
this[AnalyticsParam.PERMISSION_TYPE] = sentFrom.permissionType
}
},
)
class ScanError(error: Throwable) : Basic(

View file

@ -7,28 +7,20 @@ import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
import com.tangem.blockchain.blockchains.ton.TonTransactionExtras
import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.common.TransactionError
import com.tangem.blockchain.common.TransactionSender
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.*
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.services.Result
import com.tangem.core.analytics.Analytics
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.domain.models.scan.CardDTO
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.analytics.events.Token
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
@ -39,25 +31,11 @@ import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.extensions.minimalAmount
import com.tangem.tap.features.demo.DemoTransactionSender
import com.tangem.tap.features.demo.isDemoCard
import com.tangem.tap.features.send.redux.AddressPayIdActionUi
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction
import com.tangem.tap.features.send.redux.AmountAction
import com.tangem.tap.features.send.redux.AmountActionUi
import com.tangem.tap.features.send.redux.*
import com.tangem.tap.features.send.redux.FeeAction.RequestFee
import com.tangem.tap.features.send.redux.PrepareSendScreen
import com.tangem.tap.features.send.redux.SendAction
import com.tangem.tap.features.send.redux.SendActionUi
import com.tangem.tap.features.send.redux.states.ButtonState
import com.tangem.tap.features.send.redux.states.ExternalTransactionData
import com.tangem.tap.features.send.redux.states.MainCurrencyType
import com.tangem.tap.features.send.redux.states.TransactionExtrasState
import com.tangem.tap.features.send.redux.states.*
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdk
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.walletCurrenciesManager
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
@ -65,7 +43,7 @@ import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.Middleware
import timber.log.Timber
import java.util.*
import java.util.EnumSet
/**
[REDACTED_AUTHOR]
@ -134,9 +112,16 @@ private fun verifyAndSendTransaction(
},
sendAllCallback = {
sendTransaction(
action, walletManager, amountToSend, feeAmount, destinationAddress,
sendState.transactionExtrasState, card, sendState.externalTransactionData,
dispatch,
action = action,
walletManager = walletManager,
amountToSend = amountToSend,
feeAmount = feeAmount,
feeType = sendState.feeState.selectedFeeType,
destinationAddress = destinationAddress,
transactionExtras = sendState.transactionExtrasState,
card = card,
externalTransactionData = sendState.externalTransactionData,
dispatch = dispatch,
)
},
reduceAmount,
@ -145,8 +130,16 @@ private fun verifyAndSendTransaction(
}
else -> {
sendTransaction(
action, walletManager, amountToSend, feeAmount, destinationAddress,
sendState.transactionExtrasState, card, sendState.externalTransactionData, dispatch,
action = action,
walletManager = walletManager,
amountToSend = amountToSend,
feeAmount = feeAmount,
feeType = sendState.feeState.selectedFeeType,
destinationAddress = destinationAddress,
transactionExtras = sendState.transactionExtrasState,
card = card,
externalTransactionData = sendState.externalTransactionData,
dispatch = dispatch,
)
}
}
@ -158,6 +151,7 @@ private fun sendTransaction(
walletManager: WalletManager,
amountToSend: Amount,
feeAmount: Amount,
feeType: FeeType,
destinationAddress: String,
transactionExtras: TransactionExtrasState,
card: CardDTO,
@ -253,7 +247,15 @@ private fun sendTransaction(
Analytics.send(Basic.TransactionSent(AnalyticsParam.TxSentFrom.Sell))
dispatch(WalletAction.TradeCryptoAction.FinishSelling(externalTransactionData.transactionId))
} else {
Analytics.send(Basic.TransactionSent(AnalyticsParam.TxSentFrom.Send))
Analytics.send(
Basic.TransactionSent(
sentFrom = AnalyticsParam.TxSentFrom.Send(
blockchain = walletManager.wallet.blockchain.fullName,
token = amountToSend.currencySymbol,
feeType = feeType.convertToAnalyticsFeeType(),
),
),
)
dispatch(NavigationAction.PopBackTo())
}
scope.launch(Dispatchers.IO) {

View file

@ -1,6 +1,7 @@
package com.tangem.tap.features.send.redux.states
import com.tangem.blockchain.common.Amount
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.features.wallet.redux.ProgressState
import java.math.BigDecimal
@ -8,7 +9,16 @@ import java.math.BigDecimal
[REDACTED_AUTHOR]
*/
enum class FeeType {
SINGLE, LOW, NORMAL, PRIORITY
SINGLE, LOW, NORMAL, PRIORITY;
}
fun FeeType.convertToAnalyticsFeeType(): AnalyticsParam.FeeType {
return when (this) {
FeeType.SINGLE -> AnalyticsParam.FeeType.Fixed
FeeType.LOW -> AnalyticsParam.FeeType.Min
FeeType.NORMAL -> AnalyticsParam.FeeType.Normal
FeeType.PRIORITY -> AnalyticsParam.FeeType.Max
}
}
data class FeeState(

View file

@ -34,14 +34,11 @@ class TransactionManagerImpl(
) : TransactionManager {
override suspend fun sendApproveTransaction(
networkId: String,
feeAmount: BigDecimal,
gasLimit: Int,
destinationAddress: String,
dataToSign: String,
txData: ApproveTxData,
derivationPath: String?,
analyticsData: AnalyticsData,
): SendTxResult {
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
val blockchain = requireNotNull(Blockchain.fromNetworkId(txData.networkId)) { "blockchain not found" }
val walletManager = getActualWalletManager(blockchain, derivationPath)
walletManager.update()
val amount = Amount(value = BigDecimal.ZERO, blockchain = blockchain)
@ -49,40 +46,55 @@ class TransactionManagerImpl(
walletManager = walletManager,
amount = amount,
blockchain = blockchain,
feeAmount = feeAmount,
gasLimit = gasLimit,
destinationAddress = destinationAddress,
dataToSign = dataToSign,
feeAmount = txData.feeAmount,
gasLimit = txData.gasLimit,
destinationAddress = txData.destinationAddress,
dataToSign = txData.dataToSign,
successEvent = AnalyticsParam.TxSentFrom.Approve(
blockchain = blockchain.fullName,
token = analyticsData.tokenSymbol,
feeType = AnalyticsParam.FeeType.fromString(analyticsData.feeType),
permissionType = analyticsData.permissionType ?: "",
),
)
}
override suspend fun sendTransaction(
networkId: String,
amountToSend: BigDecimal,
feeAmount: BigDecimal,
gasLimit: Int,
destinationAddress: String,
dataToSign: String,
txData: SwapTxData,
isSwap: Boolean,
currencyToSend: Currency,
derivationPath: String?,
analyticsData: AnalyticsData,
): SendTxResult {
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
val blockchain = requireNotNull(Blockchain.fromNetworkId(txData.networkId)) { "blockchain not found" }
val walletManager = getActualWalletManager(blockchain, derivationPath)
walletManager.update()
val amount = if (isSwap) {
createAmountForSwap(amountToSend, currencyToSend, blockchain)
createAmountForSwap(txData.amountToSend, txData.currencyToSend, blockchain)
} else {
createAmount(amountToSend, currencyToSend, blockchain)
createAmount(txData.amountToSend, txData.currencyToSend, blockchain)
}
val successEvent = if (isSwap) {
AnalyticsParam.TxSentFrom.Swap(
blockchain = blockchain.fullName,
token = analyticsData.tokenSymbol,
feeType = AnalyticsParam.FeeType.fromString(analyticsData.feeType),
)
} else {
AnalyticsParam.TxSentFrom.Send(
blockchain = blockchain.fullName,
token = analyticsData.tokenSymbol,
feeType = AnalyticsParam.FeeType.fromString(analyticsData.feeType),
)
}
return sendTransactionInternal(
walletManager = walletManager,
amount = amount,
blockchain = blockchain,
feeAmount = feeAmount,
gasLimit = gasLimit,
destinationAddress = destinationAddress,
dataToSign = dataToSign,
feeAmount = txData.feeAmount,
gasLimit = txData.gasLimit,
destinationAddress = txData.destinationAddress,
dataToSign = txData.dataToSign,
successEvent = successEvent,
)
}
@ -95,6 +107,7 @@ class TransactionManagerImpl(
gasLimit: Int,
destinationAddress: String,
dataToSign: String,
successEvent: AnalyticsParam.TxSentFrom,
): SendTxResult {
val txData = walletManager.createTransaction(
amount = amount,
@ -110,7 +123,10 @@ class TransactionManagerImpl(
FirebaseCrashlytics.getInstance().recordException(ex)
return SendTxResult.UnknownError(ex)
}
return handleSendResult(sendResult)
return handleSendResult(
result = sendResult,
successEvent = successEvent,
)
}
override fun getExplorerTransactionLink(networkId: String, txAddress: String): String {
@ -319,10 +335,10 @@ class TransactionManagerImpl(
}
}
private fun handleSendResult(result: SimpleResult): SendTxResult {
private fun handleSendResult(result: SimpleResult, successEvent: AnalyticsParam.TxSentFrom): SendTxResult {
when (result) {
is SimpleResult.Success -> {
analytics.send(Basic.TransactionSent(AnalyticsParam.TxSentFrom.Swap))
analytics.send(Basic.TransactionSent(sentFrom = successEvent))
return SendTxResult.Success
}
is SimpleResult.Failure -> {