Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 5.3 dev #393

Merged
merged 10 commits into from
Dec 4, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ internal fun Blockchain.getBitcoinNetworkProviders(
} else {
listOf(
"https://api.ravencoin.org/api/",
"https://ravencoin.network/api/",
"https://explorer.rvn.zelcore.io/api/",
)
}.map(::RavencoinNetworkProvider)
else -> throw IllegalStateException("$this isn't supported")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,23 @@ import com.tangem.blockchain.common.address.Address as SdkAddress
internal class DecimalAddressService : AddressService() {

override fun makeAddress(walletPublicKey: ByteArray, curve: EllipticCurve?): String {
return makeErcAddress(walletPublicKey)
return makeDscAddress(walletPublicKey)
}

override fun makeAddresses(
walletPublicKey: ByteArray,
curve: EllipticCurve?,
): Set<SdkAddress> {
val ercAddress = makeErcAddress(walletPublicKey)
val dscAddress = makeDscAddress(walletPublicKey)

return setOf(
SdkAddress(ercAddress),
SdkAddress(
convertErcAddressToDscAddress(ercAddress),
AddressType.Legacy,
)
SdkAddress(dscAddress, AddressType.Legacy),
SdkAddress(convertDscAddressToDelAddress(dscAddress), AddressType.Default),
)
}

private fun makeErcAddress(walletPublicKey: ByteArray): String {
/** Same as ERC55 address */
private fun makeDscAddress(walletPublicKey: ByteArray): String {
val decompressedPublicKey = walletPublicKey
.toDecompressedPublicKey()
.sliceArray(1..64)
Expand All @@ -50,7 +48,7 @@ internal class DecimalAddressService : AddressService() {
override fun validate(address: String): Boolean {
val addressToValidate = when {
address.startsWith(ADDRESS_PREFIX) || address.startsWith(LEGACY_ADDRESS_PREFIX) -> {
convertDscAddressToErcAddress(address) ?: return false
convertDelAddressToDscAddress(address)
}

else -> address
Expand All @@ -64,20 +62,22 @@ internal class DecimalAddressService : AddressService() {
private const val LEGACY_ADDRESS_PREFIX = "dx"
private const val ERC55_ADDRESS_PREFIX = "0x"

fun convertDscAddressToErcAddress(addressHex: String): String? {
fun convertDelAddressToDscAddress(addressHex: String): String {
if (addressHex.startsWith(ERC55_ADDRESS_PREFIX)) {
return addressHex
}

val (prefix, addressBytes) = Bech32.decode(addressHex).let { it.hrp to it.data }
if (prefix == null || addressBytes == null) return null
require(value = prefix != null && addressBytes != null) {
"Unable to convert DEL address to DSC address: $addressHex"
}

val convertedAddressBytes = Crypto.convertBits(addressBytes, 0, addressBytes.size, 5, 8, false)

return convertedAddressBytes.toHexString()
}

fun convertErcAddressToDscAddress(addressHex: String): String {
fun convertDscAddressToDelAddress(addressHex: String): String {
if (addressHex.startsWith(ADDRESS_PREFIX) || addressHex.startsWith(LEGACY_ADDRESS_PREFIX)) {
return addressHex
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.tangem.blockchain.blockchains.decimal

import com.tangem.blockchain.blockchains.ethereum.network.EthereumInfoResponse
import com.tangem.blockchain.blockchains.ethereum.network.EthereumJsonRpcProvider
import com.tangem.blockchain.blockchains.ethereum.network.EthereumNetworkService
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.network.blockchair.BlockchairToken
import java.math.BigDecimal
import java.math.BigInteger

internal class DecimalNetworkService(
jsonRpcProviders: List<EthereumJsonRpcProvider>,
) : EthereumNetworkService(jsonRpcProviders, blockcypherNetworkProvider = null, blockchairEthNetworkProvider = null) {

override suspend fun getInfo(address: String, tokens: Set<Token>): Result<EthereumInfoResponse> {
return super.getInfo(convertAddress(address), tokens)
}

override suspend fun getAllowance(ownerAddress: String, token: Token, spenderAddress: String): Result<BigDecimal> {
return super.getAllowance(convertAddress(ownerAddress), token, spenderAddress)
}

override suspend fun getSignatureCount(address: String): Result<Int> {
return super.getSignatureCount(convertAddress(address))
}

override suspend fun getTokensBalance(address: String, tokens: Set<Token>): Result<Map<Token, BigDecimal>> {
return super.getTokensBalance(convertAddress(address), tokens)
}

override suspend fun findErc20Tokens(address: String): Result<List<BlockchairToken>> {
return super.findErc20Tokens(convertAddress(address))
}

override suspend fun getGasLimit(to: String, from: String, value: String?, data: String?): Result<BigInteger> {
return super.getGasLimit(convertAddress(to), convertAddress(from), value, data)
}

private fun convertAddress(address: String): String {
return DecimalAddressService.convertDelAddressToDscAddress(address)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ internal class DecimalWalletManager(
)

private fun convertAddress(destinationAddress: String): String {
return DecimalAddressService.convertDscAddressToErcAddress(destinationAddress) ?: destinationAddress
return DecimalAddressService.convertDelAddressToDscAddress(destinationAddress)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private fun getNowNodesProvider(
}

private fun getGetBlockProvider(accessToken: String): EthereumJsonRpcProvider =
EthereumJsonRpcProvider(baseUrl = "go.getblock.io/$accessToken")
EthereumJsonRpcProvider(baseUrl = "https://go.getblock.io/$accessToken/")

private fun getInfuraProvider(
baseUrl: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.tangem.blockchain.blockchains.ethereum.network

import com.tangem.blockchain.blockchains.ethereum.EthereumUtils
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.toBlockchainSdkError
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.blockchain.network.MultiNetworkProvider
Expand All @@ -13,7 +16,7 @@ import kotlinx.coroutines.coroutineScope
import java.math.BigDecimal
import java.math.BigInteger

class EthereumNetworkService(
open class EthereumNetworkService(
jsonRpcProviders: List<EthereumJsonRpcProvider>,
private val blockcypherNetworkProvider: BlockcypherNetworkProvider? = null,
private val blockchairEthNetworkProvider: BlockchairEthNetworkProvider? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,3 @@ class StellarNetworkService(
)
}
}

fun <T : Any> T.getPrivateProperty(variableName: String): Any? {
return javaClass.getDeclaredField(variableName).let { field ->
field.isAccessible = true
return@let field.get(this)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.tangem.blockchain.blockchains.stellar

import com.tangem.blockchain.common.NetworkProvider
import com.tangem.blockchain.common.toBlockchainSdkError
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.stellar.sdk.Server
import org.stellar.sdk.Transaction
Expand All @@ -13,6 +14,8 @@ import org.stellar.sdk.responses.RootResponse
import org.stellar.sdk.responses.SubmitTransactionResponse
import org.stellar.sdk.responses.operations.OperationResponse
import shadow.okhttp3.OkHttpClient
import com.tangem.blockchain.extensions.Result
import org.stellar.sdk.requests.ErrorResponse
import java.io.IOException

internal class StellarWrapperNetworkProvider(
Expand All @@ -25,34 +28,51 @@ internal class StellarWrapperNetworkProvider(
get() = server.httpClient

@Throws(IOException::class)
fun submitTransaction(transaction: Transaction?): SubmitTransactionResponse {
return server.submitTransaction(transaction)
fun submitTransaction(transaction: Transaction?): Result<SubmitTransactionResponse> {
return runWithErrorHandling { server.submitTransaction(transaction) }
}

fun accountCall(data: String): AccountResponse {
return server.accounts().account(data)
fun accountCall(data: String): Result<AccountResponse> {
return runWithErrorHandling { server.accounts().account(data) }
}

fun rootCall(): RootResponse {
return server.root()
fun rootCall(): Result<RootResponse> {
return runWithErrorHandling { server.root() }
}

fun ledgerCall(ledgerSeq: Long): LedgerResponse {
return server.ledgers().ledger(ledgerSeq)
fun ledgerCall(ledgerSeq: Long): Result<LedgerResponse> {
return runWithErrorHandling { server.ledgers().ledger(ledgerSeq) }
}

fun paymentsCall(accountId: String): Page<OperationResponse> {
return server.payments().forAccount(accountId).order(RequestBuilder.Order.DESC).execute()
fun paymentsCall(accountId: String): Result<Page<OperationResponse>> {
return runWithErrorHandling {
server.payments().forAccount(accountId).order(RequestBuilder.Order.DESC).execute()
}
}

fun feeCall(): FeeStatsResponse {
return server.feeStats().execute()
fun feeCall(): Result<FeeStatsResponse> {
return runWithErrorHandling { server.feeStats().execute() }
}

fun operationsLimit(accountId: String): Page<OperationResponse> {
return server.operations().forAccount(accountId)
.limit(RECORD_LIMIT)
.includeFailed(true)
.execute()
fun operationsLimit(accountId: String): Result<Page<OperationResponse>> {
return runWithErrorHandling {
server.operations().forAccount(accountId)
.limit(RECORD_LIMIT)
.includeFailed(true)
.execute()
}
}
}

private fun <T> runWithErrorHandling(block: () -> T): Result<T> {
return try {
val result = block()
Result.Success(result)
} catch (exception: Exception) {
if (exception is ErrorResponse && exception.code == 404) {
throw exception // handled in NetworkService
} else {
Result.Failure(exception.toBlockchainSdkError())
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ package com.tangem.blockchain.common.address

// btc:
// segwit = default

// decimal:
// 0x = legacy
// d0 = default
enum class AddressType {
Default,
Legacy
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.tangem.blockchain.common.assembly.impl

import com.tangem.blockchain.blockchains.decimal.DecimalNetworkService
import com.tangem.blockchain.blockchains.decimal.DecimalWalletManager
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionBuilder
import com.tangem.blockchain.blockchains.ethereum.getEthereumJsonRpcProviders
import com.tangem.blockchain.blockchains.ethereum.network.EthereumNetworkService
import com.tangem.blockchain.common.assembly.WalletManagerAssembly
import com.tangem.blockchain.common.assembly.WalletManagerAssemblyInput

Expand All @@ -15,9 +15,9 @@ internal object DecimalWalletManagerAssembly : WalletManagerAssembly<DecimalWall
wallet = this,
transactionBuilder = EthereumTransactionBuilder(
walletPublicKey = publicKey.blockchainKey,
blockchain = blockchain
blockchain = blockchain,
),
networkProvider = EthereumNetworkService(
networkProvider = DecimalNetworkService(
jsonRpcProviders = blockchain.getEthereumJsonRpcProviders(input.config),
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.tangem.blockchain.common.txhistory

import com.tangem.blockchain.blockchains.bitcoin.BitcoinTransactionHistoryProvider
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionHistoryProvider
import com.tangem.blockchain.blockchains.tron.TronTransactionHistoryProvider
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.blockchain.network.blockbook.config.BlockBookConfig
Expand All @@ -27,12 +26,12 @@ internal fun Blockchain.getTransactionHistoryProvider(

Blockchain.Ethereum,
Blockchain.EthereumTestnet,
Blockchain.Arbitrum,
// Blockchain.Arbitrum,
Blockchain.Avalanche,
Blockchain.BSC,
Blockchain.Polygon,
// Blockchain.Polygon,
Blockchain.EthereumPow,
Blockchain.Kava,
// Blockchain.Kava,
-> {
EthereumTransactionHistoryProvider(
blockchain = this,
Expand All @@ -43,15 +42,15 @@ internal fun Blockchain.getTransactionHistoryProvider(
)
}

Blockchain.Tron -> {
TronTransactionHistoryProvider(
blockchain = this,
BlockBookApi(
config = BlockBookConfig.NowNodes(nowNodesCredentials = config.nowNodeCredentials),
blockchain = this,
)
)
}
// Blockchain.Tron -> {
// TronTransactionHistoryProvider(
// blockchain = this,
// BlockBookApi(
// config = BlockBookConfig.NowNodes(nowNodesCredentials = config.nowNodeCredentials),
// blockchain = this,
// )
// )
// }

else -> DefaultTransactionHistoryProvider
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal class DecimalExternalLinkProvider(isTestnet: Boolean) : ExternalLinkPro
override val testNetTopUpUrl: String = "https://testnet.console.decimalchain.com/wallet/"

override fun explorerUrl(walletAddress: String, contractAddress: String?): String {
val address = DecimalAddressService.convertErcAddressToDscAddress(walletAddress)
val address = DecimalAddressService.convertDscAddressToDelAddress(walletAddress)

return explorerBaseUrl + "address/$address"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.tangem.blockchain.blockchains.ethereum.network.EthereumResponse
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.extensions.SimpleResult
import org.stellar.sdk.requests.ErrorResponse
import retrofit2.HttpException
import java.io.IOException

Expand Down Expand Up @@ -63,8 +64,10 @@ object ResultChecker {
}

private fun BlockchainSdkError.WrappedThrowable.isNetworkError(): Boolean {
return cause is IOException || cause is HttpException || cause is JsonDataException
return cause is IOException || cause is HttpException || cause is JsonDataException || stellarNetworkError(cause)
}
}


private fun stellarNetworkError(cause: Throwable?): Boolean {
return cause is ErrorResponse && cause.code != 404
}
}
Loading