Giter Site home page Giter Site logo

horizontalsystems / ethereum-kit-android Goto Github PK

View Code? Open in Web Editor NEW
99.0 17.0 54.0 31.79 MB

Comprehensive EVM SDK (Ethereum, Binance Smart Chain, Avalanche, Arbitrum, Optimism, Polygon) for Android, implemented on Kotlin. Create wallets, watch wallets (read-only), sync transactions, filter transactions by type (erc20, bep20, swap transactions etc.), swap using native DEX protocols, connect to DeFi smart contracts using WalletConnect. Easily extendable to work with custom smart contracts. Full support for EIP1159.

Home Page: https://unstoppable.money

License: MIT License

Kotlin 95.25% Java 4.75%
ethereum web3 ethereum-wallet erc20 ethereum-library erc-20 ethereum-sdk binance-smart-chain bep20 eip1159

ethereum-kit-android's Introduction

EthereumKit

EthereumKit is a native(Kotlin) toolkit for EVM compatible networks. It's implemented and used by Unstoppable Wallet, a multi-currency crypto wallet. It implements a lot of features of the DeFi world natively (no need for WalletConnect) out-of-the-box.

Core Features

  • Restore with mnemonic phrase, BIP39 Seed, EVM private key, or simply an Ethereum address
  • Local storage of account data (ETH, Token/NFT balance and transactions)
  • Synchronization over HTTP/WebSocket
  • Watch accounts. Restore with any address
  • Ethereum Name Service (ENS) support
  • EIP-1559 Gas Prices with live updates
  • Reactive-functional API by RxAndroid
  • Implementation of Ethereum's JSON-RPC API
  • Support for Infura and Etherscan
  • Can be extended to natively support any smart contract
  • EIP20 token standard support
  • EIP721 and EIP1155 non-fungible tokens(NFT)
  • Uniswap (PancakeSwap, QuickSwap, Trader Joe) support
  • 1Inch support

Blockchains supported

Any EVM blockchain that supports the Ethereum's RPC API and has an Etherscan-like block explorer can be easily integrated to your wallet using EthereumKit. The following blockchains are currently integrated to Unstoppable Wallet:

  • Ethereum
  • Binance Smart Chain
  • Polygon
  • ArbitrumOne
  • Optimism
  • Avalanche C-Chain

Usage

Initialization

First you need to initialize an EthereumKit instance

val context = Application()
val address = Address("0x..your..address")

val evmKit = EthereumKit.getInstance(
    context,
    address,
    Chain.Ethereum,
    RpcSource.ethereumInfuraHttp("projectId", "projectSecret"),
    TransactionSource.ethereumEtherscan("apiKey"),
    "unique_wallet_id"
)

Starting and Stopping

EthereumKit instance requires to be started with start command. This start the process of synchronization with the blockchain state.

evmKit.start()
evmKit.stop()

Get wallet data

You can get account state, last block height, sync state, transactions sync state and some others synchronously:

evmKit.accountState?.let { state ->
    state.balance
    state.nonce
}

evmKit.lastBlockHeight

You also can subscribe to Rx observables of those and more:

evmKit.accountStateFlowable.subscribe { state -> println("balance: ${state.balance}); nonce: ${state.nonce}") }
evmKit.lastBlockHeightFlowable.subscribe { height -> println(height) }
evmKit.syncStateFlowable.subscribe { state -> println(state) }
evmKit.transactionsSyncStateFlowable.subscribe { state -> println(state) }

// Subscribe to ETH transactions synced by the kit
evmKit.getFullTransactionsFlowable(listOf(listOf("ETH"))).subscribe { transactions -> 
    println(transactions.size) 
}

// Subscribe to all EVM transactions
evmKit.allTransactionsFlowable.subscribe { transactionsPair -> 
    println(transactionsPair.first.size) 
}

Send Transaction

To send a transaction you need a Signer object. Here's how you can create it using Mnemonic seed phrase:

val seed = Mnemonic().toSeed(listOf("mnemonic", "phrase"), "passphrase_if_exists'")
val signer = Signer.getInstance(seed, Chain.Ethereum)

Now you can use it to sign an Ethereum transaction:

val toAddress = Address("0x..recipient..address..here")
val amount = BigInteger("100000000000000000")                         // 0.1 ETH in WEIs
val gasPrice = GasPrice.Legacy(50_000_000_000)

// Construct TransactionData which is the key payload of any EVM transaction
val transactionData = ethereumKit.transferTransactionData(toAddress, amount)

// Estimate gas for the transaction
val estimateGasSingle = ethereumKit.estimateGas(transactionData, gasPrice)

// Generate a raw transaction which is ready to be signed. This step also synchronizes the nonce
val rawTransactionSingle = estimateGasSingle.flatMap { estimateGasSingle ->
    ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)
}

val sendSingle = rawTransactionSingle.flatMap { rawTransaction ->
    // Sign the transaction
    val signature = signer.signature(rawTransaction)

    // Send the transaction to RPC node
    ethereumKit.send(rawTransaction, signature)
}

// This step is needed for Rx reactive code to run
val disposables = CompositeDisposable()

sendSingle.subscribe { fullTransaction ->
    // ethereumKit.send returns FullTransaction object that contains transaction and a transaction decoration
    val transaction = fullTransaction.transaction

    println("Transaction sent: ${transaction.hash.toHexString()}")
    println("To: ${transaction.to?.let { it.eip55 }}")
    println("Amount: ${transaction.value?.let { it.toString(10) }}")
}.let {
    disposables.add(it)
}

Get ETH transactions

The following code retrieves the transactions that have ETH coin incoming or outgoing, including the transactions where ETH is received in internal transactions.

ethereumKit.getFullTransactionsAsync(listOf(listOf("ETH")))
        .subscribe { fullTransactions ->
            for (fullTransaction in fullTransactions) {
                println("Transaction hash: ${fullTransaction.transaction.hash.toHexString()}")

                when (val decoration = fullTransaction.decoration) {
                    is IncomingDecoration -> {
                        println("From: ${decoration.from.eip55}")
                        println("Amount: ${decoration.value.toString(10)}")
                    }

                    is OutgoingDecoration -> {
                        println("To: ${decoration.to.eip55}")
                        println("Amount: ${decoration.value.toString(10)}")
                    }
                    
                    else -> {}
                }
            }
        }.let {
            disposables.add(it)
        }

EIP20 tokens

Initialization

val contractAddress = Address("0x..token..contract..address..")
val erc20Kit = Erc20Kit.getInstance(context, ethereumKit, contractAddress)

// Decorators are needed to detect transactions as `Erc20` transfer/approve transactions
Erc20Kit.addTransactionSyncer(ethereumKit)
        
// Erc20 transactions syncer is needed to pull Eip20 transfer transactions from Etherscan
Erc20Kit.addDecorators(ethereumKit)

Get token balance

erc20Kit.balance?.let { balance ->
    println(balance.toString(10))
}

Send Erc20 transfer transaction

val toAddress = Address("0x..recipient..address..here")
val amount = BigInteger("100000000000000000")
val gasPrice = GasPrice.Legacy(50_000_000_000)

// Construct TransactionData which calls a `Transfer` method of the EIP20 compatible smart contract
val transactionData = erc20Kit.buildTransferTransactionData(toAddress, amount)

ethereumKit.estimateGas(transactionData, gasPrice)
        .flatMap { estimateGasSingle ->
            ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)
        }
        .flatMap { rawTransaction ->
            val signature = signer.signature(rawTransaction)
            ethereumKit.send(rawTransaction, signature)
        }
        .subscribe { fullTransaction ->
            println("Transaction sent: ${fullTransaction.transaction.hash.toHexString()}")

            val decoration = fullTransaction.decoration as? OutgoingDecoration ?: return@subscribe
                    
            println("To: ${decoration.to.eip55}")
            println("Amount: ${decoration.value.toString(10)}")
        }.let {
            disposables.add(it)
        }

Get Erc20 transactions

ethereumKit.getFullTransactionsAsync(listOf(listOf(contractAddress.eip55)))
        .subscribe { fullTransactions ->
            for (fullTransaction in fullTransactions) {
                println("Transaction sent: ${fullTransaction.transaction.hash.toHexString()}")

                when (val decoration = fullTransaction.decoration) {
                    is IncomingDecoration -> {
                        println("From: ${decoration.from.eip55}")
                        println("Amount: ${decoration.value.toString(10)}")
                    }

                    is OutgoingDecoration -> {
                        println("To: ${decoration.to.eip55}")
                        println("Amount: ${decoration.value.toString(10)}")
                    }

                    else -> {}
                }
            }
        }.let {
            disposables.add(it)
        }

Uniswap

Initialization

val uniswapKit = UniswapKit.getInstance(ethereumKit)

// Decorators are needed to detect and decorate transactions as `Uniswap` transactions
UniswapKit.addDecorators(ethereumKit)

Send sample swap transaction

// Sample swap data
val tokenIn = uniswapKit.etherToken()
val tokenOut = uniswapKit.token(Address("0x..token..address"), 18)
val amount = BigDecimal(1)
val gasPrice = GasPrice.Legacy(50_000_000_000)

// Get SwapData. SwapData is a list of pairs available in Uniswap smart contract at the moment
uniswapKit.swapData(tokenIn, tokenOut)
        .map { swapData ->
            // Get TradeData. TradeData is the best swap route evaluated by UniswapKit
            val tradeData = uniswapKit.bestTradeExactIn(swapData, amount)

            // Convert TradeData to EvmKit TransactionData
            uniswapKit.transactionData(tradeData)
        }
        .flatMap { transactionData ->
            ethereumKit.estimateGas(transactionData, gasPrice)
                    .flatMap { estimateGasSingle ->
                        ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)
                    }
        }
        .flatMap { rawTransaction ->
            val signature = signer.signature(rawTransaction)
            ethereumKit.send(rawTransaction, signature)
        }
        .subscribe { fullTransaction ->
            println("Transaction sent: ${fullTransaction.transaction.hash.toHexString()}")
        }.let {
            disposables.add(it)
        }

ExactIn/ExactOut

With UniswapKit you can build swap transaction that either has an exact In or exact Out amount. That is, if you want to swap exactly 1 ETH to USDT, you get TradeData using bestTradeExactIn method. Similarly, if you want to swap ETH to USDT and you want to get exactly 1000 USDT, then you get TradeData using bestTradeExactOut

Trade Options

UniswapKit supports Price Impact/Deadline/Recipient options. You can set them in TradeOptions object passed to bestTradeExactIn/bestTradeExactOut methods. Please, look at official Uniswap app documentation to learn about those options.

1Inch

OneInchKit is an extension that wraps interactions with 1Inch API.

Initialization

val oneInchKit = OneInchKit.getInstance(ethereumKit)
OneInchKit.addDecorators(ethereumKit)

Sample code to get swap data from 1Inch API, sign it and send to RPC node

// Sample swap data
val tokenFromAddress = Address("0x..from..token..address")
val tokenToAddress = Address("0x..to..token..address")
val amount = BigInteger("100000000000000000")
val gasPrice = GasPrice.Legacy(50_000_000_000)

// Get Swap object, evaluated transaction data by 1Inch aggregator
oneInchKit.getSwapAsync(
        fromToken = tokenFromAddress,
        toToken = tokenToAddress,
        amount = amount,
        slippagePercentage = 1F,
        recipient = null,
        gasPrice = gasPrice
)
        .flatMap { swap ->
            val tx = swap.transaction
            val transactionData = TransactionData(tx.to, tx.value, tx.data)

            ethereumKit.rawTransaction(transactionData, gasPrice, tx.gasLimit)
        }
        .flatMap { rawTransaction ->
            val signature = signer.signature(rawTransaction)
            ethereumKit.send(rawTransaction, signature)
        }
        .subscribe { fullTransaction ->
            println("Transaction sent: ${fullTransaction.transaction.hash.toHexString()}")
        }.let {
            disposables.add(it)
        }

NFTs

NftKit support EIP721 and EIP1155

Initialization

val nftKit = NftKit.getInstance(App.instance, ethereumKit)

nftKit.addEip721Decorators()
nftKit.addEip1155Decorators()

nftKit.addEip721TransactionSyncer()
nftKit.addEip1155TransactionSyncer()

Get NFTs owned by the user

val nftBalances = nftKit.nftBalances

for (nftBalance in nftBalances) {
    println("---- ${nftBalance.balance} pieces of ${nftBalance.nft.tokenName} ---")
    println("Contract Address: ${nftBalance.nft.contractAddress.eip55}")
    println("TokenID: ${nftBalance.nft.tokenId.toString(10)}")
}

Send an NFT

val nftContractAddress = Address("0x..contract..address")
val tokenId = BigInteger("234123894712031638516723498")
val to = Address("0x..recipient..address")
val gasPrice = GasPrice.Legacy(50_000_000_000)

// Construct a TransactionData
val transactionData = nftKit.transferEip721TransactionData(nftContractAddress, to, tokenId)

ethereumKit.estimateGas(transactionData, gasPrice)
        .flatMap { estimateGasSingle ->
            ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)
        }
        .flatMap { rawTransaction ->
            val signature = signer.signature(rawTransaction)
            ethereumKit.send(rawTransaction, signature)
        }
        .subscribe { fullTransaction ->
            println("Transaction sent: ${fullTransaction.transaction.hash.toHexString()}")
        }.let {
            disposables.add(it)
        }

Extending

Smart contract call

In order to send an EVM smart contract call transaction, you need to create an instance of TransactionData object. Then you can sign and send it as seen above.

Prerequisites

  • JDK >= 11
  • Android 8 (minSdkVersion 26) or greater

Installation

Add the JitPack to module build.gradle

repositories {
    maven { url 'https://jitpack.io' }
}

Add the following dependency to your build.gradle file:

dependencies {
    implementation 'com.github.horizontalsystems:ethereum-kit-android:master-SNAPSHOT'
}

Example App

All features of the library are used in example project. It can be referred as a starting point for usage of the library.

License

The EthereumKit is open source and available under the terms of the MIT License

ethereum-kit-android's People

Contributors

abdrasulov avatar esen avatar nk-the-crazy avatar omurovch avatar rafaelekol avatar tmedetbekov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ethereum-kit-android's Issues

Custom token swipe is not working

My token address is 0x2c8aec2fd0c0feba71e0424873461908067d5bf4. when I swipe token from ETH to SHUBH (SHUBH), it show error pair is not found. but we have provide liquidity from SHUBH (SHUBH) to ETH in uniswape.
Screenshot_20211009-230240_Erium Wallet

PeerGroup refactoring

  • reimplement PeerGroup using TDD
  • handle outgoing and incoming data correctly
  • handle forks and block header sync (and validation)

Refactor transaction status in erc20 kit

func transactionStatus(transactionHash: Data) -> Single<TransactionStatus>
has useless transactionReceiptStatusSingle. transactionReceiptStatusSingle - is not valid for pending transactions.

We need to implement this sync the right way and use same approach for EthereumKit and Erc20Kit now these kits has different approach

How to generate ETH Public Address

I've been poking around the ETH kit for a little while and I haven't come across a way to generate an ETH public address using the kit. If there isn't a way what's a workaround, and is there a possibility for the feature to be implemented? If there's already a way using the kit let me know. Thank you for your time!

Creation of new OkHttpClients instead of reusing one

Erc20Kit can work with only one token at a time. Each instance of Erc20Kit requires new TransactionManager which in turn requires EtherscanTransactionsProvider which needs EtherscanService. Each new EtherscanService creates new instance of OkHttpClient which is resource-heavy. Is there some specific reason for it?

It would be great if users will be able to provide OkHttpClient through class constructors as it allows proper resource management on app level.

Handle "Announce" messages

When "Announce" message is received,

  • New block(s) must be downloaded from the peer
  • New state must be requested and validated
  • Peer's bestBlockHeight must be updated
  • The following delegate methods should be called

IBlockchainDelegate#onUpdate(lastBlockHeight: Int)
IBlockchainDelegate#onUpdate(balance: String)
IBlockchainDelegate#onUpdate(syncState: SyncState)

Some ERC20 Tokens incorrectly display the amount in transactions

Some ERC20 charge fee in tokens

Ex.: Stasis EURS for every transfer the contract collects arbitrary variable and fixed fee in EURS that will be deducted from your token balance in addition to the transferred amount.

At the moment: when i send this token, from my token balance deduct transferred Amount+ fixed fee in EURS, but in my transactions list I see only the amount of fee. It will be more correct to display 2 transactions: Transferred Amount and Fee in token

Update:

It should be taken into account that there is no standard for fee on ERC20 level. In other words, each ERC20 token may potentially have their own customized version of the fee on an ERC20 contract level. Therefore, whatever fix we apply it should be universal and work correctly for all such contracts.

Add geth mobile aar as a module

In maven repo there is only old version org.ethereum:geth:1.8.11 available. Need to update it by downloading aar file and adding it manually.

ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/MainNet.kt

Path : ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/MainNet.kt

BlockHeader(hashHex = "bce9c39107fd4b58a31ab28975e4b5689a8a5e41d06b2736795cd6f643ac2d73".hexStringToByteArray(),
                    totalDifficulty = BigInteger("18601822522462629"),
                    parentHash = "c272ad832f06865beabc3dd4c83699e039740fba7239a0aa2c20c5ae434bec54".hexStringToByteArray(),
                    unclesHash = "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".hexStringToByteArray(),
                    coinbase = "cd626bc764e1d553e0d75a42f5c4156b91a63f23".hexStringToByteArray(),
                    stateRoot = "4f3513d052a8a85a7015359f17e9e61c4fc8169443017268500e09df991c0c55".hexStringToByteArray(),
                    transactionsRoot = "b82f3e93274ff1f68d10c7f6acef7d239794ae603e1a17f880793ed100f5be95".hexStringToByteArray(),
                    receiptsRoot = "6b1dfc93f7aa063b150605b05f6976c0d23159f7a27c708d9b7e9a8e19469199".hexStringToByteArray(),
                    logsBloom = "00000001000000000001000004000000002040000080000008000004000000000000000000000000000000000000000010044000002000000002000000000000010000000028000000008008800020000020000000808000800001080000000001000000020000000004000000000801000004000002400404000010000000000000010000000400000040000000000100000020000000000000000020020000000080200000000000002000000000000000000000000800000000000000000200000042000000000020000080000000008070810000040000000000000020080000000008000000000010200000020004000040000000000000000004000000".hexStringToByteArray(),
                    difficulty = ("ccc2825").hexStringToByteArray(),
                    height = 5227842,
                    gasLimit = "7a1200".hexStringToByteArray(),
                    gasUsed = 0x3161d0,
                    timestamp = 0x5c8f815b,
                    extraData = "d883010817846765746888676f312e31302e34856c696e7578".hexStringToByteArray(),
                    mixHash = ("cae580f260efcee4ed8789380528e9770b5c260d289321ff8c6352eb031d830").hexStringToByteArray(),
                    nonce = "004d35d804eac7d8".hexStringToByteArray())

Here coinbase = "cd626bc764e1d553e0d75a42f5c4156b91a63f23".hexStringToByteArray(),

What is the use of this in Ethereum Kit ? Just learning few things.
If a wallet user transfers some coins from one wallet to another using Unstoppable Ether Kit, does unstoppable wallet collect some fees ?

increase gas limit to 150000

There are a number of ERC20 tokens where 150000 gas limit seems insufficient to execute token transfer.

When that happens the transaction broadcasts to the network but the actual transfer fails due to insufficient gas limit. At the end user ends up paying current 100K gas limit but no transfer of tokens takes place.

Therefore we should increase gas limit to 150K.

Is there a reason why minsdk level is set to 26?

Due to the current situation, I have to set minsdk to 23.
I checked that build is possible in version 0.3.1, can I use this version?

I tried version 0.3.1 that can be built under minsdk 26, but there was an error.

The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with.

Sending using ERC20 adapter uses wrong address and amount.

erc20kit/src/main/java/io/horizontalsystems/erc20kit/core/TransactionManager.kt

On line 40 it should be
return TransactionData(to = to, value = value, TransferMethod(to, value).encodedABI())

as it current overwrites the to address with the tokens contract address, and the value with 0.

App crashed on Unlink

PeerGroup: Closing all peer connections...
Process: io.horizontalsystems.bankwallet.dev, PID: 14364
    io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | null
        at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
        at io.reactivex.internal.operators.flowable.FlowableFromCallable.subscribeActual(FlowableFromCallable.java:43)
        at io.reactivex.Flowable.subscribe(Flowable.java:14479)
        at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:37)
        at io.reactivex.Flowable.subscribe(Flowable.java:14479)
        at io.reactivex.internal.operators.flowable.FlowableElementAtSingle.subscribeActual(FlowableElementAtSingle.java:41)
        at io.reactivex.Single.subscribe(Single.java:3438)
        at io.reactivex.internal.operators.single.SingleZipArray.subscribeActual(SingleZipArray.java:63)
        at io.reactivex.Single.subscribe(Single.java:3438)
        at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.io.InterruptedIOException
        at okhttp3.internal.http2.Http2Stream.waitForIo(Http2Stream.java:579)
        at okhttp3.internal.http2.Http2Stream.takeResponseHeaders(Http2Stream.java:143)
        at okhttp3.internal.http2.Http2Codec.readResponseHeaders(Http2Codec.java:125)
        at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
        at okhttp3.RealCall.execute(RealCall.java:77)
        at org.web3j.protocol.http.HttpService.performIO(HttpService.java:151)
        at org.web3j.protocol.Service.send(Service.java:35)
        at org.web3j.protocol.core.Request.send(Request.java:73)
        at org.web3j.protocol.core.-$$Lambda$KiEniAM70PKnVH3c3FV-XYYYWF0.call(Unknown Source:2)
        at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:31)
        at org.web3j.protocol.core.-$$Lambda$gE3Z3_l3iQHxXAJugv_wSeyhask.call(Unknown Source:2)
        at io.reactivex.internal.operators.flowable.FlowableFromCallable.subscribeActual(FlowableFromCallable.java:39)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.