Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-27 15:48:07 +01:00
parent f916d7394b
commit cf6ee347b8
14 changed files with 161 additions and 197 deletions

View file

@ -1,28 +1,17 @@
package com.tangem.tap.proxy
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.Message
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.blockchains.optimism.EthereumOptimisticRollupWalletManager
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.blockchain.common.transaction.TransactionSendResult
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.externallinkprovider.TxExploreState
import com.tangem.blockchain.network.ResultChecker
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.hexToBytes
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.lib.crypto.TransactionManager
import com.tangem.lib.crypto.models.*
import com.tangem.lib.crypto.models.transactions.SendTxResult
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.TangemSigner
import java.math.BigDecimal
import java.math.BigInteger
import java.math.MathContext
@ -30,59 +19,10 @@ import java.math.RoundingMode
@Suppress("LargeClass")
class TransactionManagerImpl(
private val appStateHolder: AppStateHolder,
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val walletManagersFacade: WalletManagersFacade,
private val userWalletsListManager: UserWalletsListManager,
) : TransactionManager {
override suspend fun sendApproveTransaction(
txData: ApproveTxData,
derivationPath: String?,
analyticsData: AnalyticsData,
): SendTxResult {
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)
return sendTransactionInternal(
walletManager = walletManager,
amount = amount,
blockchain = blockchain,
feeAmount = txData.feeAmount,
gasLimit = txData.gasLimit,
destinationAddress = txData.destinationAddress,
dataToSign = txData.dataToSign,
)
}
@Suppress("LongParameterList")
private suspend fun sendTransactionInternal(
walletManager: WalletManager,
amount: Amount,
blockchain: Blockchain,
feeAmount: BigDecimal,
gasLimit: Int,
destinationAddress: String,
dataToSign: String,
): SendTxResult {
val txData = walletManager.createTransaction(
amount = amount,
fee = Fee.Common(Amount(value = feeAmount, blockchain = blockchain)),
destination = destinationAddress,
).copy(hash = dataToSign, extras = createExtras(walletManager, gasLimit, dataToSign))
val signer = transactionSigner(walletManager)
val sendResult = try {
(walletManager as? TransactionSender)?.send(txData, signer) ?: error("Cannot cast to TransactionSender")
} catch (ex: Exception) {
FirebaseCrashlytics.getInstance().recordException(ex)
return SendTxResult.UnknownError(ex)
}
return handleSendResult(result = sendResult)
}
override fun getExplorerTransactionLink(networkId: String, txAddress: String): String {
val blockchain = Blockchain.fromNetworkId(networkId) ?: error("blockchain not found")
return when (val txUrlState = blockchain.getExploreTxUrl(txAddress)) {
@ -301,60 +241,6 @@ class TransactionManagerImpl(
}
}
private fun handleSendResult(result: Result<TransactionSendResult>): SendTxResult {
when (result) {
is Result.Success -> {
return SendTxResult.Success
}
is Result.Failure -> {
if (ResultChecker.isNetworkError(result)) return SendTxResult.NetworkError(result.error)
val error = result.error as? BlockchainSdkError ?: return SendTxResult.UnknownError()
when (error) {
is BlockchainSdkError.WrappedTangemError -> {
val errorByCode = mapErrorByCode(error)
if (errorByCode != null) {
return errorByCode
}
val tangemSdkError = error.tangemError as? TangemSdkError ?: return SendTxResult.UnknownError()
if (tangemSdkError is TangemSdkError.UserCancelled) return SendTxResult.UserCancelledError
return SendTxResult.TangemSdkError(tangemSdkError.code, tangemSdkError.cause)
}
else -> {
return SendTxResult.TangemSdkError(error.code, error.cause)
}
}
}
}
}
private fun mapErrorByCode(error: BlockchainSdkError.WrappedTangemError): SendTxResult? {
return when (error.code) {
USER_CANCELLED_ERROR_CODE -> {
return SendTxResult.UserCancelledError
}
else -> {
null
}
}
}
private fun transactionSigner(walletManager: WalletManager): TransactionSigner {
val actualCard = requireNotNull(appStateHolder.getActualCard()) { "no card found" }
return TangemSigner(
card = actualCard,
tangemSdk = cardSdkConfigRepository.sdk,
initialMessage = Message(),
) { signResponse ->
appStateHolder.mainStore?.dispatch(
GlobalAction.UpdateWalletSignedHashes(
walletSignedHashes = signResponse.totalSignedHashes,
walletPublicKey = walletManager.wallet.publicKey.seedKey,
remainingSignatures = signResponse.remainingSignatures,
),
)
}
}
private suspend fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager {
val selectedUserWallet = requireNotNull(
userWalletsListManager.selectedUserWalletSync,
@ -368,24 +254,6 @@ class TransactionManagerImpl(
return requireNotNull(walletManager) { "no wallet manager found" }
}
private fun createExtras(
walletManager: WalletManager,
gasLimit: Int,
transactionHash: String,
): TransactionExtras? {
return when (walletManager) {
is EthereumWalletManager -> {
return EthereumTransactionExtras(
data = transactionHash.removePrefix(HEX_PREFIX).hexToBytes(),
gasLimit = gasLimit.toBigInteger(),
)
}
else -> {
null
}
}
}
/**
* Create proxy fees
*
@ -483,8 +351,6 @@ class TransactionManagerImpl(
}
companion object {
private const val HEX_PREFIX = "0x"
private const val USER_CANCELLED_ERROR_CODE = 50002
private const val MULTIPLIER_GAS_PRICE_FOR_NORMAL_FEE = 150 // 50%
private const val MULTIPLIER_GAS_PRICE_FOR_PRIORITY_FEE = 200 // 50%
}