Skip to content

Commit

Permalink
Merge pull request #374 from tangem/feature/AND-5267_tron_tx_history
Browse files Browse the repository at this point in the history
AND-5267 Added support for Tron transaction history
  • Loading branch information
Yoggam1 authored Nov 16, 2023
2 parents 7b687f3 + 519ce41 commit 6b2ec4e
Show file tree
Hide file tree
Showing 20 changed files with 284 additions and 97 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# Each line is a file pattern followed by one or more owners.

# These owners will be the default owners for everything in the repo.
* @roman-pv @iiiburnyiii @Mama1emon @kozarezvlad @Yoggam1 @Sateetas
* @roman-pv @iiiburnyiii @Mama1emon @kozarezvlad @Yoggam1 @Sateetas @iMaks99

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 6b2ec4e

Please sign in to comment.