Skip to content

Instantly share code, notes, and snippets.

@Legion1900
Last active October 13, 2020 09:35
Show Gist options
  • Save Legion1900/26bbd2d05c9e974a785441632cf79ff3 to your computer and use it in GitHub Desktop.
Save Legion1900/26bbd2d05c9e974a785441632cf79ff3 to your computer and use it in GitHub Desktop.
/*
* Code of this class belongs to https://github.com/horizontalsystems/ethereum-kit-android library;
* Modified by Sapien Wallet team on 10.12.2020
* */
import com.google.gson.Gson
import com.google.gson.JsonElement
import com.google.gson.reflect.TypeToken
import com.sapien.wallet.di.modules.ApiKeyModule
import com.sapien.wallet.di.modules.retrofit.GsonModule
import io.horizontalsystems.ethereumkit.api.models.etherscan.EtherscanResponse
import io.horizontalsystems.ethereumkit.core.retryWhenError
import io.horizontalsystems.ethereumkit.models.Address
import io.reactivex.Single
import retrofit2.http.GET
import retrofit2.http.Query
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
@Singleton
class EtherscanService @Inject constructor(
@Named(GsonModule.ETHERSCAN_SERVICE) private val gson: Gson,
private val service: EtherscanServiceAPI,
@Named(ApiKeyModule.ETHERSCAN) private val apiKey: String
) {
fun getTransactionList(address: Address, startBlock: Long): Single<EtherscanResponse> {
return service.getTransactionList("account", "txList", address.hex, startBlock, 99_999_999, "desc", apiKey)
.map { parseResponse(it) }
.retryWhenError(RequestError.RateLimitExceed::class)
}
fun getInternalTransactionList(address: Address, startBlock: Long): Single<EtherscanResponse> {
return service.getTransactionList(
"account",
"txlistinternal",
address.hex,
startBlock,
99_999_999,
"desc",
apiKey
)
.map { parseResponse(it) }
.retryWhenError(RequestError.RateLimitExceed::class)
}
fun getTokenTransactions(contractAddress: Address, address: Address, startBlock: Long): Single<EtherscanResponse> {
return service.getTokenTransactions(
"account",
"tokentx",
contractAddress.hex,
address.hex,
startBlock,
99_999_999,
"desc",
apiKey
)
.map { parseResponse(it) }
.retryWhenError(RequestError.RateLimitExceed::class)
}
private fun parseResponse(response: JsonElement): EtherscanResponse {
try {
val responseObj = response.asJsonObject
val status = responseObj["status"].asJsonPrimitive.asString
val message = responseObj["message"].asJsonPrimitive.asString
if (status == "0" && message != "No transactions found") {
val result = responseObj["result"].asJsonPrimitive.asString
if (message == "NOTOK" && result == "Max rate limit reached") {
throw RequestError.RateLimitExceed()
}
}
val result: List<Map<String, String>> =
gson.fromJson(responseObj["result"], object : TypeToken<List<Map<String, String>>>() {}.type)
return EtherscanResponse(status, message, result)
} catch (rateLimitExceeded: RequestError.RateLimitExceed) {
throw rateLimitExceeded
} catch (err: Throwable) {
throw RequestError.ResponseError("Unexpected response: $response")
}
}
open class RequestError(message: String? = null) : Exception(message ?: "") {
class ResponseError(message: String) : RequestError(message)
class RateLimitExceed : RequestError()
}
interface EtherscanServiceAPI {
@GET("/api")
fun getTransactionList(
@Query("module") module: String,
@Query("action") action: String,
@Query("address") address: String,
@Query("startblock") startblock: Long,
@Query("endblock") endblock: Long,
@Query("sort") sort: String,
@Query("apiKey") apiKey: String
): Single<JsonElement>
@GET("/api")
fun getTokenTransactions(
@Query("module") module: String,
@Query("action") action: String,
@Query("contractaddress") contractAddress: String,
@Query("address") address: String,
@Query("startblock") startblock: Long,
@Query("endblock") endblock: Long,
@Query("sort") sort: String,
@Query("apiKey") apiKey: String
): Single<JsonElement>
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment