@@ -7,14 +7,15 @@ import io.horizontalsystems.ethereumkit.models.Balance
77import io.horizontalsystems.ethereumkit.models.GasPrice
88import io.horizontalsystems.ethereumkit.models.LastBlockHeight
99import io.horizontalsystems.ethereumkit.models.Transaction
10+ import io.horizontalsystems.ethereumkit.models.etherscan.EtherscanTransaction
1011import io.horizontalsystems.ethereumkit.network.EtherscanService
1112import io.horizontalsystems.hdwalletkit.HDWallet
1213import io.horizontalsystems.hdwalletkit.Mnemonic
1314import io.reactivex.Flowable
1415import io.reactivex.Single
1516import io.reactivex.android.schedulers.AndroidSchedulers
1617import io.reactivex.disposables.CompositeDisposable
17- import io.reactivex.functions.Function5
18+ import io.reactivex.functions.Function3
1819import io.reactivex.schedulers.Schedulers
1920import io.realm.OrderedCollectionChangeSet
2021import io.realm.Realm
@@ -29,6 +30,7 @@ import org.web3j.abi.datatypes.Type
2930import org.web3j.abi.datatypes.generated.Uint256
3031import org.web3j.crypto.RawTransaction
3132import org.web3j.crypto.TransactionEncoder
33+ import org.web3j.tuples.generated.Tuple3
3234import org.web3j.utils.Convert
3335import org.web3j.utils.Numeric
3436import java.math.BigDecimal
@@ -105,7 +107,6 @@ class EthereumKit(seed: ByteArray, networkType: NetworkType, walletId: String) {
105107 timer = Timer (30 , object : Timer .Listener {
106108 override fun onTimeIsUp () {
107109 refresh()
108- erc20List.forEach { refresh(it.key) }
109110 }
110111 })
111112 }
@@ -138,18 +139,29 @@ class EthereumKit(seed: ByteArray, networkType: NetworkType, walletId: String) {
138139
139140 @Synchronized
140141 fun refresh () {
142+ val tokenList = erc20List.values
143+ if (kitState is KitState .Syncing ) {
144+ return
145+ }
146+
147+ tokenList.find { it.kitState is KitState .Syncing }?.let {
148+ return
149+ }
150+
141151 kitState = KitState .Syncing (0.0 )
152+ tokenList.forEach { it.kitState = KitState .Syncing (0.0 ) }
142153
143- Flowable .zip(updateBalance(), updateLastBlockHeight(), updateTransactions(), updateTransactions(token = true ), updateGasPrice(),
144- Function5 <BigDecimal , Int , Int , Int , Double , Unit > { _, _, _, _, _ ->
145- Unit
146- })
147- .subscribeOn(io.reactivex.schedulers.Schedulers .io())
154+ Flowable .zip(web3j.getBlockNumber(), web3j.getGasPrice(), web3j.getBalance(receiveAddress), Function3 { h: Int , g: Double , b: BigDecimal -> Tuple3 (h, g, b) })
155+ .subscribeOn(Schedulers .io())
148156 .subscribe({
149- kitState = KitState .Synced
157+ updateLastBlockHeight(it.value1)
158+ updateGasPrice(it.value2)
159+ updateBalance(it.value3, receiveAddress, ETH_DECIMAL )
160+
161+ refreshTransactions()
150162 }, {
151- it?.printStackTrace()
152163 kitState = KitState .NotSynced
164+ tokenList.forEach { it.kitState = KitState .NotSynced }
153165 }).let {
154166 disposables.add(it)
155167 }
@@ -203,31 +215,13 @@ class EthereumKit(seed: ByteArray, networkType: NetworkType, walletId: String) {
203215 holder.balance = it.balance.toBigDecimal()
204216 }
205217
206- refresh(token.contractAddress )
218+ refresh()
207219 }
208220
209221 fun unregister (contractAddress : String ) {
210222 erc20List.remove(contractAddress)
211223 }
212224
213- @Synchronized
214- fun refresh (contractAddress : String ) {
215- val erc20 = erc20List[contractAddress] ? : return
216-
217- erc20.kitState = KitState .Syncing (0.0 )
218-
219- updateBalance(contractAddress, erc20.listener.decimal)
220- .subscribeOn(io.reactivex.schedulers.Schedulers .io())
221- .subscribe({
222- erc20.kitState = KitState .Synced
223- }, {
224- it?.printStackTrace()
225- erc20.kitState = KitState .NotSynced
226- }).let {
227- disposables.add(it)
228- }
229- }
230-
231225 fun feeERC20 (): Double {
232226 realmFactory.realm.use { realm ->
233227 val gwei = realm.where(GasPrice ::class .java).findFirst()?.gasPriceInGwei
@@ -396,92 +390,108 @@ class EthereumKit(seed: ByteArray, networkType: NetworkType, walletId: String) {
396390 }
397391 }
398392
399- private fun updateGasPrice (): Flowable <Double > {
400- return web3j.getGasPrice()
401- .map { gasPrice ->
402- realmFactory.realm.use { realm ->
403- realm.executeTransaction {
404- it.insertOrUpdate(GasPrice (gasPrice))
405- }
406- }
407- gasPrice
408- }
409- .onErrorReturn {
410- DEFAULT_GAS_PRICE
411- }
412- }
393+ private fun getBlockHeight (token : Boolean = false): Int {
394+ realmFactory.realm.use {
395+ val query = it.where(Transaction ::class .java)
396+ if (token) {
397+ query.notEqualTo(" contractAddress" , " " )
398+ } else {
399+ query.equalTo(" contractAddress" , " " )
400+ }
413401
414- private fun updateBalance (contractAddress : String? = null, decimal : Int = ETH_DECIMAL ): Flowable <BigDecimal > {
415- val flowable = if (contractAddress == null ) {
416- web3j.getBalance(receiveAddress)
417- } else {
418- web3j.getTokenBalance(receiveAddress, contractAddress, decimal)
402+ return query.sort(" blockNumber" , Sort .DESCENDING ).findFirst()?.blockNumber?.toInt() ? : 0
419403 }
404+ }
420405
421- return flowable.map { balance ->
422- realmFactory.realm.use { realm ->
423- realm.executeTransaction {
424- it.insertOrUpdate(Balance (contractAddress ? : receiveAddress, balance, decimal))
425- }
426- }
406+ private fun refreshTransactions () {
407+ var lastBlockHeight = getBlockHeight()
408+
409+ etherscanService.getTransactionList(receiveAddress, lastBlockHeight + 1 )
410+ .subscribeOn(io.reactivex.schedulers.Schedulers .io())
411+ .subscribe({
412+ saveTransactions(it.result)
413+ kitState = KitState .Synced
414+ }, {
415+ kitState = KitState .NotSynced
416+ })
417+ .let { disposables.add(it) }
418+
419+ if (erc20List.isEmpty())
420+ return
421+
422+ lastBlockHeight = getBlockHeight(token = true )
423+ etherscanService.getTokenTransactions(receiveAddress, lastBlockHeight + 1 )
424+ .subscribeOn(io.reactivex.schedulers.Schedulers .io())
425+ .subscribe({
426+ saveTransactions(it.result)
427+ refreshTokensBalances()
428+ }, {
429+ erc20List.values.forEach { it.kitState = KitState .NotSynced }
430+ })
431+ .let { disposables.add(it) }
427432
428- balance
429- }
430433 }
431434
432- private fun updateLastBlockHeight (): Flowable <Int > {
433- return web3j.getBlockNumber()
434- .map { height ->
435- lastBlockHeight = height
436- realmFactory.realm.use { realm ->
437- realm.executeTransaction {
438- it.insertOrUpdate(LastBlockHeight (height))
439- }
440- }
435+ private fun refreshTokensBalances () {
436+ erc20List.values.forEach { holder ->
437+ val erc20Address = holder.listener.contractAddress
438+ val erc20Decimal = holder.listener.decimal
439+
440+ web3j.getTokenBalance(receiveAddress, erc20Address, erc20Decimal)
441+ .subscribeOn(io.reactivex.schedulers.Schedulers .io())
442+ .subscribe({
443+ updateBalance(it, erc20Address, erc20Decimal)
444+ holder.kitState = KitState .Synced
445+ }, {
446+ holder.kitState = KitState .NotSynced
447+ })
448+ .let { disposables.add(it) }
449+ }
450+ }
441451
442- listener?.onLastBlockHeightUpdate(height)
452+ //
453+ // InsertOrUpdate records
454+ //
443455
444- erc20List.forEach {
445- it.value.listener.onLastBlockHeightUpdate(height)
446- }
456+ private fun updateGasPrice (gasPrice : Double ) {
457+ realmFactory.realm.use { realm ->
458+ realm.executeTransaction {
459+ it.insertOrUpdate(GasPrice (gasPrice))
460+ }
461+ }
462+ }
447463
448- height
449- }
464+ private fun updateBalance (balance : BigDecimal , address : String , decimal : Int ) {
465+ realmFactory.realm.use { realm ->
466+ realm.executeTransaction {
467+ it.insertOrUpdate(Balance (address, balance, decimal))
468+ }
469+ }
450470 }
451471
452- private fun updateTransactions (token : Boolean = false): Flowable <Int > {
472+ private fun updateLastBlockHeight (height : Int ) {
473+ lastBlockHeight = height
453474
454- val lastBlockHeight = realmFactory.realm.use {
455- var query = it.where(Transaction ::class .java)
456- query = if (token) {
457- query.notEqualTo(" contractAddress" , " " )
458- .notEqualTo(" input" , " 0x" )
459- } else {
460- query.equalTo(" contractAddress" , " " )
461- .equalTo(" input" , " 0x" )
475+ realmFactory.realm.use { realm ->
476+ realm.executeTransaction {
477+ it.insertOrUpdate(LastBlockHeight (height))
462478 }
463- query.sort(" blockNumber" , Sort .DESCENDING )
464- .findFirst()?.blockNumber?.toInt() ? : 0
465479 }
466480
467- val flowable = if (token) {
468- etherscanService.getTokenTransactions(receiveAddress, lastBlockHeight + 1 )
469- } else {
470- etherscanService.getTransactionList(receiveAddress, lastBlockHeight + 1 )
481+ listener?.onLastBlockHeightUpdate(height)
482+
483+ erc20List.forEach {
484+ it.value.listener.onLastBlockHeightUpdate(height )
471485 }
486+ }
472487
473- return flowable.map { response ->
474- realmFactory.realm.use { realm ->
475- realm.executeTransaction {
476- response.result
477- .map { tx -> Transaction (tx) }
478- .forEach { tx ->
479- realm.insertOrUpdate(tx)
480- }
488+ private fun saveTransactions (list : List <EtherscanTransaction >) {
489+ realmFactory.realm.use { realm ->
490+ realm.executeTransaction {
491+ list.map { tx -> Transaction (tx) }.forEach { tx ->
492+ realm.insertOrUpdate(tx)
481493 }
482494 }
483-
484- response.result.size
485495 }
486496 }
487497
0 commit comments