From 0a02ad05cf0beb0f55cc16f4e401a64264f22ac9 Mon Sep 17 00:00:00 2001 From: abdrasulov Date: Fri, 18 Oct 2024 17:46:14 +0600 Subject: [PATCH] Rotate keys --- .../addresswatch/AddressWatchViewModel.kt | 4 +- .../sample/modules/main/MainViewModel.kt | 6 +-- build.gradle | 2 +- .../ethereumkit/core/EthereumKit.kt | 2 +- .../ethereumkit/models/TransactionSource.kt | 46 ++++++++--------- .../ethereumkit/network/EtherscanService.kt | 49 ++++++++++--------- gradle/wrapper/gradle-wrapper.properties | 2 +- 7 files changed, 58 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt index a2082274..9eff84e6 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt @@ -129,11 +129,11 @@ class AddressWatchViewModel : ViewModel() { when (Configuration.chain) { Chain.BinanceSmartChain -> { - transactionSource = TransactionSource.bscscan(Configuration.bscScanKey) + transactionSource = TransactionSource.bscscan(listOf(Configuration.bscScanKey)) rpcSource = RpcSource.binanceSmartChainHttp() } Chain.Ethereum -> { - transactionSource = TransactionSource.ethereumEtherscan(Configuration.etherscanKey) + transactionSource = TransactionSource.ethereumEtherscan(Configuration.etherscanKey.split(",")) rpcSource = RpcSource.Http(listOf(URI(Configuration.ethereumRpc)), null) } else -> { diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt index 891c145f..198b58c7 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt @@ -193,17 +193,17 @@ class MainViewModel : ViewModel() { private fun createKit(): EthereumKit { when (Configuration.chain) { Chain.BinanceSmartChain -> { - transactionSource = TransactionSource.bscscan(Configuration.bscScanKey) + transactionSource = TransactionSource.bscscan(listOf(Configuration.bscScanKey)) rpcSource = RpcSource.binanceSmartChainHttp() } Chain.Ethereum -> { - transactionSource = TransactionSource.ethereumEtherscan(Configuration.etherscanKey) + transactionSource = TransactionSource.ethereumEtherscan(Configuration.etherscanKey.split(",")) rpcSource = RpcSource.Http(listOf(URI(Configuration.ethereumRpc)), null) } Chain.ArbitrumOne -> { - transactionSource = TransactionSource.arbiscan(Configuration.arbiscanApiKey) + transactionSource = TransactionSource.arbiscan(listOf(Configuration.arbiscanApiKey),) rpcSource = RpcSource.arbitrumOneRpcHttp() } diff --git a/build.gradle b/build.gradle index bc9907be..91b79e63 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.3' + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt index 618001fc..70427139 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt @@ -515,7 +515,7 @@ class EthereumKit( private fun transactionProvider(transactionSource: TransactionSource, address: Address): ITransactionProvider { when (transactionSource.type) { is TransactionSource.SourceType.Etherscan -> { - val service = EtherscanService(transactionSource.type.apiBaseUrl, transactionSource.type.apiKey) + val service = EtherscanService(transactionSource.type.apiBaseUrl, transactionSource.type.apiKeys) return EtherscanTransactionProvider(service, address) } } diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt index ab90c546..7d9a90df 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt @@ -8,78 +8,78 @@ class TransactionSource(val name: String, val type: SourceType) { } sealed class SourceType { - class Etherscan(val apiBaseUrl: String, val txBaseUrl: String, val apiKey: String) : SourceType() + class Etherscan(val apiBaseUrl: String, val txBaseUrl: String, val apiKeys: List) : SourceType() } companion object { - private fun etherscan(apiSubdomain: String, txSubdomain: String?, apiKey: String): TransactionSource { + private fun etherscan(apiSubdomain: String, txSubdomain: String?, apiKeys: List): TransactionSource { return TransactionSource( "etherscan.io", - SourceType.Etherscan("https://$apiSubdomain.etherscan.io", "https://${txSubdomain?.let { "$it." } ?: ""}etherscan.io", apiKey) + SourceType.Etherscan("https://$apiSubdomain.etherscan.io", "https://${txSubdomain?.let { "$it." } ?: ""}etherscan.io", apiKeys) ) } - fun ethereumEtherscan(apiKey: String): TransactionSource { - return etherscan("api", null, apiKey) + fun ethereumEtherscan(apiKeys: List): TransactionSource { + return etherscan("api", null, apiKeys) } - fun goerliEtherscan(apiKey: String): TransactionSource { - return etherscan("api-goerli", "goerli", apiKey) + fun goerliEtherscan(apiKeys: List): TransactionSource { + return etherscan("api-goerli", "goerli", apiKeys) } - fun bscscan(apiKey: String): TransactionSource { + fun bscscan(apiKeys: List): TransactionSource { return TransactionSource( "bscscan.com", - SourceType.Etherscan("https://api.bscscan.com", "https://bscscan.com", apiKey) + SourceType.Etherscan("https://api.bscscan.com", "https://bscscan.com", apiKeys) ) } - fun polygonscan(apiKey: String): TransactionSource { + fun polygonscan(apiKeys: List): TransactionSource { return TransactionSource( "polygonscan.com", - SourceType.Etherscan("https://api.polygonscan.com", "https://polygonscan.com", apiKey) + SourceType.Etherscan("https://api.polygonscan.com", "https://polygonscan.com", apiKeys) ) } - fun optimisticEtherscan(apiKey: String): TransactionSource { + fun optimisticEtherscan(apiKeys: List): TransactionSource { return TransactionSource( "optimistic.etherscan.io", - SourceType.Etherscan("https://api-optimistic.etherscan.io", "https://optimistic.etherscan.io", apiKey) + SourceType.Etherscan("https://api-optimistic.etherscan.io", "https://optimistic.etherscan.io", apiKeys) ) } - fun arbiscan(apiKey: String): TransactionSource { + fun arbiscan(apiKeys: List): TransactionSource { return TransactionSource( "arbiscan.io", - SourceType.Etherscan("https://api.arbiscan.io", "https://arbiscan.io", apiKey) + SourceType.Etherscan("https://api.arbiscan.io", "https://arbiscan.io", apiKeys) ) } - fun snowtrace(apiKey: String): TransactionSource { + fun snowtrace(apiKeys: List): TransactionSource { return TransactionSource( "snowtrace.io", - SourceType.Etherscan("https://api.snowtrace.io", "https://snowtrace.io", apiKey) + SourceType.Etherscan("https://api.snowtrace.io", "https://snowtrace.io", apiKeys) ) } - fun gnosis(apiKey: String): TransactionSource { + fun gnosis(apiKeys: List): TransactionSource { return TransactionSource( "gnosisscan.io", - SourceType.Etherscan("https://api.gnosisscan.io", "https://gnosisscan.io", apiKey) + SourceType.Etherscan("https://api.gnosisscan.io", "https://gnosisscan.io", apiKeys) ) } - fun fantom(apiKey: String): TransactionSource { + fun fantom(apiKeys: List): TransactionSource { return TransactionSource( "ftmscan.com", - SourceType.Etherscan("https://api.ftmscan.com", "https://ftmscan.com", apiKey) + SourceType.Etherscan("https://api.ftmscan.com", "https://ftmscan.com", apiKeys) ) } - fun basescan(apiKey: String): TransactionSource { + fun basescan(apiKeys: List): TransactionSource { return TransactionSource( "basescan.org", - SourceType.Etherscan("https://api.basescan.org", "https://basescan.org", apiKey) + SourceType.Etherscan("https://api.basescan.org", "https://basescan.org", apiKeys) ) } diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/EtherscanService.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/EtherscanService.kt index 236bdee1..a5733da1 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/EtherscanService.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/EtherscanService.kt @@ -9,9 +9,7 @@ import io.horizontalsystems.ethereumkit.core.retryWhenError import io.horizontalsystems.ethereumkit.core.toHexString import io.horizontalsystems.ethereumkit.models.Address import io.reactivex.Single -import okhttp3.Interceptor import okhttp3.OkHttpClient -import okhttp3.Request import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory @@ -22,8 +20,10 @@ import java.util.logging.Logger class EtherscanService( baseUrl: String, - private val apiKey: String + private val apiKeys: List ) { + private val apiKeysSize = apiKeys.size + private var apiKeyIndex = 0 private val logger = Logger.getLogger("EtherscanService") @@ -32,21 +32,27 @@ class EtherscanService( private val gson: Gson init { - val loggingInterceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger { - override fun log(message: String) { - logger.info(message) - } - }).setLevel(HttpLoggingInterceptor.Level.BASIC) + val loggingInterceptor = HttpLoggingInterceptor { + logger.info(it) + }.setLevel(HttpLoggingInterceptor.Level.BASIC) val httpClient = OkHttpClient.Builder() - .addInterceptor(loggingInterceptor) - .addInterceptor(Interceptor { chain -> - val originalRequest: Request = chain.request() - val requestWithUserAgent: Request = originalRequest.newBuilder() + .addInterceptor { chain -> + val originalRequest = chain.request() + val originalUrl = originalRequest.url + + val url = originalUrl.newBuilder() + .addQueryParameter("apikey", getNextApiKey()) + .build() + + val request = originalRequest.newBuilder() .header("User-Agent", "Mobile App Agent") + .url(url) .build() - chain.proceed(requestWithUserAgent) - }) + + chain.proceed(request) + } + .addInterceptor(loggingInterceptor) gson = GsonBuilder() .setLenient() @@ -62,12 +68,17 @@ class EtherscanService( service = retrofit.create(EtherscanServiceAPI::class.java) } + private fun getNextApiKey(): String { + if (apiKeyIndex >= apiKeysSize) apiKeyIndex = 0 + + return apiKeys[apiKeyIndex++] + } + fun getTransactionList(address: Address, startBlock: Long): Single { return service.accountApi( action = "txlist", address = address.hex, startBlock = startBlock, - apiKey = apiKey ).map { parseResponse(it) }.retryWhenError(RequestError.RateLimitExceed::class) @@ -78,7 +89,6 @@ class EtherscanService( action = "txlistinternal", address = address.hex, startBlock = startBlock, - apiKey = apiKey ).map { parseResponse(it) }.retryWhenError(RequestError.RateLimitExceed::class) @@ -89,7 +99,6 @@ class EtherscanService( action = "tokentx", address = address.hex, startBlock = startBlock, - apiKey = apiKey ).map { parseResponse(it) }.retryWhenError(RequestError.RateLimitExceed::class) @@ -99,7 +108,6 @@ class EtherscanService( return service.accountApi( action = "txlistinternal", txHash = transactionHash.toHexString(), - apiKey = apiKey ).map { parseResponse(it) }.retryWhenError(RequestError.RateLimitExceed::class) @@ -110,7 +118,6 @@ class EtherscanService( action = "tokennfttx", address = address.hex, startBlock = startBlock, - apiKey = apiKey ).map { parseResponse(it) }.retryWhenError(RequestError.RateLimitExceed::class) @@ -121,7 +128,6 @@ class EtherscanService( action = "token1155tx", address = address.hex, startBlock = startBlock, - apiKey = apiKey ).map { parseResponse(it) }.retryWhenError(RequestError.RateLimitExceed::class) @@ -163,8 +169,7 @@ class EtherscanService( @Query("txhash") txHash: String? = null, @Query("startblock") startBlock: Long? = null, @Query("endblock") endBlock: Long? = null, - @Query("sort") sort: String? = "desc", - @Query("apikey") apiKey: String + @Query("sort") sort: String? = "desc" ): Single } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2d5bb0df..214d0119 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Apr 19 11:44:39 KGT 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME