Skip to content

Commit

Permalink
AND-5267 Added support for Tron transaction history
Browse files Browse the repository at this point in the history
  • Loading branch information
Yoggam1 committed Nov 14, 2023
1 parent 7b687f3 commit bc48090
Show file tree
Hide file tree
Showing 19 changed files with 283 additions and 96 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ internal class EthereumTransactionHistoryProvider(
val token = Token(
name = transfer.name.orEmpty(),
symbol = transfer.symbol.orEmpty(),
contractAddress = transfer.contract,
contractAddress = transfer.contract.orEmpty(),
decimals = transfer.decimals,
)
Amount(value = BigDecimal(transferValue).movePointLeft(transfer.decimals), token = token)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ class TronAddressService : AddressService() {
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package com.tangem.blockchain.blockchains.tron

import com.tangem.Log
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.txhistory.TransactionHistoryItem
import com.tangem.blockchain.common.txhistory.TransactionHistoryItem.TransactionStatus
import com.tangem.blockchain.common.txhistory.TransactionHistoryProvider
import com.tangem.blockchain.common.txhistory.TransactionHistoryRequest
import com.tangem.blockchain.common.txhistory.TransactionHistoryState
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.network.blockbook.network.BlockBookApi
import com.tangem.blockchain.network.blockbook.network.responses.GetAddressResponse
import com.tangem.common.extensions.guard
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.math.BigDecimal
import java.util.concurrent.TimeUnit

private const val PREFIX = "0x"

internal class TronTransactionHistoryProvider(
private val blockchain: Blockchain,
private val blockBookApi: BlockBookApi,
) : TransactionHistoryProvider {
override suspend fun getTransactionHistoryState(
address: String,
filterType: TransactionHistoryRequest.FilterType,
): TransactionHistoryState {
return try {
val response = withContext(Dispatchers.IO) {
blockBookApi.getTransactions(
address = address,
page = 1,
pageSize = 1, // We don't need to know all transactions to define state
filterType = filterType,
)
}
if (!response.transactions.isNullOrEmpty()) {
TransactionHistoryState.Success.HasTransactions(response.transactions.size)
} else {
TransactionHistoryState.Success.Empty
}
} catch (e: Exception) {
TransactionHistoryState.Failed.FetchError(e)
}
}

override suspend fun getTransactionsHistory(request: TransactionHistoryRequest): Result<PaginationWrapper<TransactionHistoryItem>> {
return try {
val response =
withContext(Dispatchers.IO) {
blockBookApi.getTransactions(
address = request.address,
page = request.page.number,
pageSize = request.page.size,
filterType = request.filterType,
)
}
val txs = response.transactions
?.mapNotNull { tx ->
tx.toTransactionHistoryItem(
walletAddress = request.address,
filterType = request.filterType
)
}
?: emptyList()
Result.Success(
PaginationWrapper(
page = response.page ?: request.page.number,
totalPages = response.totalPages ?: 0,
itemsOnPage = response.itemsOnPage ?: 0,
items = txs
)
)
} catch (e: Exception) {
Result.Failure(e.toBlockchainSdkError())
}
}

private fun GetAddressResponse.Transaction.toTransactionHistoryItem(
walletAddress: String,
filterType: TransactionHistoryRequest.FilterType,
): TransactionHistoryItem? {
val destinationType = extractDestinationType(this, filterType).guard {
Log.info { "Transaction $this doesn't contain a required value" }
return null
}
val amount = extractAmount(tx = this, filterType = filterType).guard {
Log.info { "Transaction $this doesn't contain a required value" }
return null
}
val sourceType = extractSourceType(tx = this, filterType = filterType).guard {
Log.info { "Transaction $this doesn't contain a required value" }
return null
}
return TransactionHistoryItem(
txHash = txid.removePrefix(PREFIX),
timestamp = TimeUnit.SECONDS.toMillis(blockTime.toLong()),
isOutgoing = fromAddress?.equals(walletAddress, ignoreCase = true) == true,
destinationType = destinationType,
sourceType = sourceType,
status = if (confirmations > 0) TransactionStatus.Confirmed else TransactionStatus.Unconfirmed,
type = extractType(tx = this),
amount = amount,
)
}

private fun extractDestinationType(
tx: GetAddressResponse.Transaction,
filterType: TransactionHistoryRequest.FilterType,
): TransactionHistoryItem.DestinationType? {
tx.toAddress ?: return null
tx.fromAddress ?: return null
return when (filterType) {
TransactionHistoryRequest.FilterType.Coin -> {
TransactionHistoryItem.DestinationType.Single(
addressType = if (tx.tokenTransfers.isEmpty()) {
TransactionHistoryItem.AddressType.User(tx.toAddress)
} else {
TransactionHistoryItem.AddressType.Contract(tx.toAddress)
}
)
}

is TransactionHistoryRequest.FilterType.Contract -> {
val transfer = tx.getTokenTransfer(filterType.address) ?: return null
TransactionHistoryItem.DestinationType.Single(
addressType = TransactionHistoryItem.AddressType.User(transfer.to)
)
}
}
}

private fun extractSourceType(
tx: GetAddressResponse.Transaction,
filterType: TransactionHistoryRequest.FilterType,
): TransactionHistoryItem.SourceType? {
val address = when (filterType) {
TransactionHistoryRequest.FilterType.Coin -> tx.fromAddress
is TransactionHistoryRequest.FilterType.Contract -> {
tx.getTokenTransfer(filterType.address)?.from
}
}.guard { return null }

return TransactionHistoryItem.SourceType.Single(address = address)
}

private fun extractType(tx: GetAddressResponse.Transaction): TransactionHistoryItem.TransactionType {
// Contract type 1 means transfer
if (tx.contractType == 1) return TransactionHistoryItem.TransactionType.Transfer

return TransactionHistoryItem.TransactionType.ContractMethod(id = tx.contractAddress.orEmpty())
}

private fun extractAmount(
tx: GetAddressResponse.Transaction,
filterType: TransactionHistoryRequest.FilterType,
): Amount? {
return when (filterType) {
TransactionHistoryRequest.FilterType.Coin -> Amount(
value = BigDecimal(tx.value).movePointLeft(blockchain.decimals()),
blockchain = blockchain,
type = AmountType.Coin
)

is TransactionHistoryRequest.FilterType.Contract -> {
val transfer = tx.getTokenTransfer(filterType.address) ?: return null
val transferValue = transfer.value ?: "0"
val token = Token(
name = transfer.name.orEmpty(),
symbol = transfer.symbol.orEmpty(),
contractAddress = transfer.token.orEmpty(),
decimals = transfer.decimals,
)
Amount(value = BigDecimal(transferValue).movePointLeft(transfer.decimals), token = token)
}
}
}

private fun GetAddressResponse.Transaction.getTokenTransfer(contractAddress: String): GetAddressResponse.Transaction.TokenTransfer? {
return tokenTransfers.firstOrNull { contractAddress.equals(it.token, ignoreCase = true) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.blockchain.common.txhistory.TransactionHistoryProvider
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.blockchain.extensions.bigIntegerValue
Expand All @@ -31,9 +32,10 @@ import java.math.BigDecimal

class TronWalletManager(
wallet: Wallet,
transactionHistoryProvider: TransactionHistoryProvider,
private val transactionBuilder: TronTransactionBuilder,
private val networkService: TronNetworkService,
) : WalletManager(wallet), TransactionSender {
) : WalletManager(wallet, transactionHistoryProvider = transactionHistoryProvider), TransactionSender {

override val currentHost: String = networkService.host

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.tangem.blockchain.common.assembly.impl

import com.tangem.blockchain.blockchains.bitcoin.getBitcoinNetworkProviders
import com.tangem.blockchain.blockchains.bitcoin.getBitcoinTransactionHistoryProvider
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinNetworkService
import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashTransactionBuilder
import com.tangem.blockchain.blockchains.bitcoincash.BitcoinCashWalletManager
import com.tangem.blockchain.common.assembly.WalletManagerAssembly
import com.tangem.blockchain.common.assembly.WalletManagerAssemblyInput
import com.tangem.blockchain.common.txhistory.getTransactionHistoryProvider

internal object BitcoinCashWalletManagerAssembly : WalletManagerAssembly<BitcoinCashWalletManager>() {

Expand All @@ -21,10 +21,10 @@ internal object BitcoinCashWalletManagerAssembly : WalletManagerAssembly<Bitcoin
networkProvider = BitcoinNetworkService(
providers = blockchain.getBitcoinNetworkProviders(blockchain, input.config),
),
transactionHistoryProvider = blockchain.getBitcoinTransactionHistoryProvider(input.config)
transactionHistoryProvider = blockchain.getTransactionHistoryProvider(input.config)
)
}
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package com.tangem.blockchain.common.assembly.impl
import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
import com.tangem.blockchain.blockchains.bitcoin.getBitcoinNetworkProviders
import com.tangem.blockchain.blockchains.bitcoin.getBitcoinTransactionHistoryProvider
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinNetworkService
import com.tangem.blockchain.common.assembly.WalletManagerAssembly
import com.tangem.blockchain.common.assembly.WalletManagerAssemblyInput
import com.tangem.blockchain.common.txhistory.getTransactionHistoryProvider

internal object BitcoinWalletManagerAssembly : WalletManagerAssembly<BitcoinWalletManager>() {

Expand All @@ -22,7 +22,7 @@ internal object BitcoinWalletManagerAssembly : WalletManagerAssembly<BitcoinWall
networkProvider = BitcoinNetworkService(
providers = blockchain.getBitcoinNetworkProviders(blockchain, input.config),
),
transactionHistoryProvider = blockchain.getBitcoinTransactionHistoryProvider(input.config)
transactionHistoryProvider = blockchain.getTransactionHistoryProvider(input.config)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package com.tangem.blockchain.common.assembly.impl

import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder
import com.tangem.blockchain.blockchains.bitcoin.getBitcoinNetworkProviders
import com.tangem.blockchain.blockchains.bitcoin.getBitcoinTransactionHistoryProvider
import com.tangem.blockchain.blockchains.bitcoin.network.BitcoinNetworkService
import com.tangem.blockchain.blockchains.dogecoin.DogecoinWalletManager
import com.tangem.blockchain.common.assembly.WalletManagerAssembly
import com.tangem.blockchain.common.assembly.WalletManagerAssemblyInput
import com.tangem.blockchain.common.txhistory.getTransactionHistoryProvider

internal object DogecoinWalletManagerAssembly : WalletManagerAssembly<DogecoinWalletManager>() {

Expand All @@ -22,8 +22,8 @@ internal object DogecoinWalletManagerAssembly : WalletManagerAssembly<DogecoinWa
networkProvider = BitcoinNetworkService(
providers = blockchain.getBitcoinNetworkProviders(blockchain, input.config),
),
transactionHistoryProvider = blockchain.getBitcoinTransactionHistoryProvider(input.config)
transactionHistoryProvider = blockchain.getTransactionHistoryProvider(input.config)
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.tangem.blockchain.common.assembly.impl

import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionBuilder
import com.tangem.blockchain.blockchains.bitcoin.getBitcoinTransactionHistoryProvider
import com.tangem.blockchain.blockchains.ducatus.DucatusWalletManager
import com.tangem.blockchain.blockchains.ducatus.network.DucatusNetworkService
import com.tangem.blockchain.common.assembly.WalletManagerAssembly
import com.tangem.blockchain.common.assembly.WalletManagerAssemblyInput
import com.tangem.blockchain.common.txhistory.getTransactionHistoryProvider

internal object DucatusWalletManagerAssembly : WalletManagerAssembly<DucatusWalletManager>() {

Expand All @@ -15,9 +15,9 @@ internal object DucatusWalletManagerAssembly : WalletManagerAssembly<DucatusWall
wallet = wallet,
transactionBuilder = BitcoinTransactionBuilder(wallet.publicKey.blockchainKey, wallet.blockchain),
networkProvider = DucatusNetworkService(),
transactionHistoryProvider = wallet.blockchain.getBitcoinTransactionHistoryProvider(input.config)
transactionHistoryProvider = wallet.blockchain.getTransactionHistoryProvider(input.config)
)
}
}

}
}
Loading

0 comments on commit bc48090

Please sign in to comment.