Updated on 2026-08-14

This commit is contained in:
Tangem 2025-03-28 14:22:23 +05:00
parent 8adc79a8c3
commit f4bb2bbc2d
21 changed files with 327 additions and 236 deletions

View file

@ -14,14 +14,14 @@ import com.tangem.blockchain.blockchains.ton.TonTransactionExtras
import com.tangem.blockchain.blockchains.tron.TronTransactionExtras
import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.smartcontract.SmartContractCallData
import com.tangem.blockchain.common.smartcontract.SmartContractCallDataProviderFactory
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.common.extensions.hexToBytes
import com.tangem.datasource.local.walletmanager.WalletManagersStore
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.transaction.TransactionRepository
import com.tangem.domain.transaction.models.TransactionType
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -29,7 +29,6 @@ import kotlinx.coroutines.withContext
import timber.log.Timber
import java.math.BigDecimal
import java.math.BigInteger
import com.tangem.blockchain.blockchains.tron.TransactionType as SdkTransactionType
internal class DefaultTransactionRepository(
private val walletManagersFacade: WalletManagersFacade,
@ -45,7 +44,6 @@ internal class DefaultTransactionRepository(
userWalletId: UserWalletId,
network: Network,
txExtras: TransactionExtras?,
hash: String?,
): TransactionData.Uncompiled = withContext(coroutineDispatcherProvider.io) {
val blockchain = Blockchain.fromId(network.id.value)
val walletManager = walletManagersFacade.getOrCreateWalletManager(
@ -54,14 +52,50 @@ internal class DefaultTransactionRepository(
derivationPath = network.derivationPath.value,
) ?: error("Wallet manager not found")
return@withContext walletManager.createTransactionDataInternal(
return@withContext walletManager.createTransaction(
amount = amount,
fee = fee,
memo = memo,
destination = destination,
).copy(
extras = txExtras ?: getMemoExtras(networkId = network.id.value, memo),
)
}
override suspend fun createTransferTransaction(
amount: Amount,
fee: Fee,
memo: String?,
destination: String,
userWalletId: UserWalletId,
network: Network,
): TransactionData.Uncompiled = withContext(coroutineDispatcherProvider.io) {
val blockchain = Blockchain.fromId(network.id.value)
val callData = SmartContractCallDataProviderFactory.getTokenTransferCallData(
destinationAddress = destination,
amount = amount,
blockchain = blockchain,
)
val extras = if (amount.type is AmountType.Token && callData != null) {
createTransactionDataExtras(
callData = callData,
network = network,
nonce = null,
gasLimit = null,
)
} else {
null
}
return@withContext createTransaction(
amount = amount,
fee = fee,
memo = null,
destination = destination,
userWalletId = userWalletId,
network = network,
txExtras = txExtras,
hash = hash,
txExtras = getMemoExtras(networkId = network.id.value, memo = memo) ?: extras,
)
}
@ -73,25 +107,16 @@ internal class DefaultTransactionRepository(
spenderAddress: String,
userWalletId: UserWalletId,
network: Network,
hash: String?,
): TransactionData.Uncompiled = withContext(coroutineDispatcherProvider.io) {
val blockchain = Blockchain.fromId(network.id.value)
val walletManager = walletManagersFacade.getOrCreateWalletManager(
userWalletId = userWalletId,
blockchain = blockchain,
derivationPath = network.derivationPath.value,
) ?: error("Wallet manager not found")
val approver = walletManager as? Approver ?: error("Cannot cast to Approver")
val approvalData = approver.getApproveData(
spenderAddress = spenderAddress,
value = approvalAmount,
)
val extras = createTransactionDataExtras(
data = approvalData,
callData = SmartContractCallDataProviderFactory.getApprovalCallData(
spenderAddress = spenderAddress,
amount = approvalAmount,
blockchain = blockchain,
),
network = network,
transactionType = TransactionType.APPROVE,
nonce = null,
gasLimit = null,
)
@ -104,7 +129,6 @@ internal class DefaultTransactionRepository(
userWalletId = userWalletId,
network = network,
txExtras = extras,
hash = hash,
)
}
@ -115,9 +139,6 @@ internal class DefaultTransactionRepository(
destination: String,
userWalletId: UserWalletId,
network: Network,
isSwap: Boolean,
txExtras: TransactionExtras?,
hash: String?,
): Result<Unit> = withContext(coroutineDispatcherProvider.io) {
val blockchain = Blockchain.fromId(network.id.value)
val walletManager = walletManagersStore.getSyncOrNull(
@ -129,14 +150,12 @@ internal class DefaultTransactionRepository(
val validator = walletManager as? TransactionValidator
if (validator != null) {
val transactionData = walletManager.createTransactionDataInternal(
val transactionData = walletManager.createTransaction(
amount = amount,
fee = fee ?: Fee.Common(amount = amount),
memo = memo,
destination = destination,
network = network,
txExtras = txExtras,
hash = hash,
).copy(
extras = getMemoExtras(networkId = network.id.value, memo = memo),
)
validator.validate(transactionData = transactionData)
@ -178,9 +197,8 @@ internal class DefaultTransactionRepository(
}
override fun createTransactionDataExtras(
data: String,
callData: SmartContractCallData,
network: Network,
transactionType: TransactionType,
nonce: BigInteger?,
gasLimit: BigInteger?,
): TransactionExtras {
@ -189,15 +207,14 @@ internal class DefaultTransactionRepository(
return when {
blockchain.isEvm() -> {
EthereumTransactionExtras(
data = data.hexToBytes(),
callData = callData,
gasLimit = gasLimit,
nonce = nonce,
)
}
blockchain == Blockchain.Tron -> {
TronTransactionExtras(
data = data.hexToBytes(),
txType = convertToSdkTransactionType(transactionType),
callData = callData,
)
}
else -> error("Data extras not supported for $blockchain")
@ -226,33 +243,6 @@ internal class DefaultTransactionRepository(
)
}
private fun convertToSdkTransactionType(transactionType: TransactionType): SdkTransactionType {
return when (transactionType) {
TransactionType.APPROVE -> SdkTransactionType.APPROVE
}
}
@Suppress("LongParameterList")
private fun WalletManager.createTransactionDataInternal(
amount: Amount,
fee: Fee,
memo: String?,
destination: String,
network: Network,
txExtras: TransactionExtras?,
hash: String?,
): TransactionData.Uncompiled {
if (txExtras != null && memo != null) {
// throw error for now to avoid programmers errors when use extras
error("Both txExtras and memo provided, use only one of them")
}
val extras = txExtras ?: getMemoExtras(network.id.value, memo)
return createTransaction(amount, fee, destination).copy(
hash = hash,
extras = extras,
)
}
@Suppress("CyclomaticComplexMethod")
private fun getMemoExtras(networkId: String, memo: String?): TransactionExtras? {
val blockchain = Blockchain.fromId(networkId)