diff --git a/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/MainViewModel.kt b/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/MainViewModel.kt index e3fb33f24..4547f6200 100644 --- a/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/MainViewModel.kt +++ b/app/src/main/java/io/horizontalsystems/bitcoinkit/demo/MainViewModel.kt @@ -70,11 +70,13 @@ class MainViewModel : ViewModel(), BitcoinKit.Listener { } fun send(address: String, amount: Long) { - bitcoinKit.send(address, amount, feePriority = feePriority) + val feeRate = feeRateFromPriority(feePriority) + bitcoinKit.send(address, amount, feeRate = feeRate) } fun fee(value: Long, address: String? = null): Long { - return bitcoinKit.fee(value, address, feePriority = feePriority) + val feeRate = feeRateFromPriority(feePriority) + return bitcoinKit.fee(value, address, feeRate = feeRate) } fun showDebugInfo() { @@ -106,4 +108,18 @@ class MainViewModel : ViewModel(), BitcoinKit.Listener { override fun onKitStateUpdate(bitcoinKit: BitcoinKit, state: KitState) { this.state.postValue(state) } + + private fun feeRateFromPriority(feePriority: FeePriority): Int { + val lowPriority = 20 + val mediumPriority = 42 + val highPriority = 81 + return when (feePriority) { + FeePriority.Lowest -> lowPriority + FeePriority.Low -> (lowPriority + mediumPriority) / 2 + FeePriority.Medium -> mediumPriority + FeePriority.High -> (mediumPriority + highPriority) / 2 + FeePriority.Highest -> highPriority + is FeePriority.Custom -> feePriority.feeRate.toInt() + } + } } diff --git a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/BitcoinKit.kt b/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/BitcoinKit.kt index f0469a6e7..65b99851c 100644 --- a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/BitcoinKit.kt +++ b/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/BitcoinKit.kt @@ -5,7 +5,10 @@ import io.horizontalsystems.bitcoinkit.blocks.BlockSyncer import io.horizontalsystems.bitcoinkit.blocks.Blockchain import io.horizontalsystems.bitcoinkit.core.* import io.horizontalsystems.bitcoinkit.managers.* -import io.horizontalsystems.bitcoinkit.models.* +import io.horizontalsystems.bitcoinkit.models.BitcoinPaymentData +import io.horizontalsystems.bitcoinkit.models.BlockInfo +import io.horizontalsystems.bitcoinkit.models.PublicKey +import io.horizontalsystems.bitcoinkit.models.TransactionInfo import io.horizontalsystems.bitcoinkit.network.* import io.horizontalsystems.bitcoinkit.network.peer.PeerGroup import io.horizontalsystems.bitcoinkit.network.peer.PeerHostManager @@ -46,7 +49,6 @@ class BitcoinKit(seed: ByteArray, networkType: NetworkType, walletId: String? = private val peerGroup: PeerGroup private val initialSyncer: InitialSyncer - private val feeRateSyncer: FeeRateSyncer private val addressManager: AddressManager private val addressConverter: AddressConverter private val paymentAddressParser: PaymentAddressParser @@ -108,7 +110,6 @@ class BitcoinKit(seed: ByteArray, networkType: NetworkType, walletId: String? = val blockHashFetcher = BlockHashFetcherBCoin(addressSelector, BCoinApi(network, HttpRequester()), BlockHashFetcherHelper()) val blockDiscovery = BlockDiscoveryBatch(Wallet(hdWallet), blockHashFetcher, network.checkpointBlock.height) - feeRateSyncer = FeeRateSyncer(realmFactory, ApiFeeRate(networkType), connectionManager) initialSyncer = InitialSyncer(realmFactory, blockDiscovery, stateManager, addressManager, peerGroup, kitStateProvider) transactionBuilder = TransactionBuilder(realmFactory, addressConverter, hdWallet, network, addressManager, unspentOutputProvider) transactionCreator = TransactionCreator(realmFactory, transactionBuilder, transactionProcessor, peerGroup) @@ -119,12 +120,10 @@ class BitcoinKit(seed: ByteArray, networkType: NetworkType, walletId: String? = // fun start() { initialSyncer.sync() - feeRateSyncer.start() } fun stop() { initialSyncer.stop() - feeRateSyncer.stop() dataProvider.clear() } @@ -143,12 +142,12 @@ class BitcoinKit(seed: ByteArray, networkType: NetworkType, walletId: String? = return dataProvider.transactions(fromHash, limit) } - fun fee(value: Long, address: String? = null, senderPay: Boolean = true, feePriority: FeePriority = FeePriority.Medium): Long { - return transactionBuilder.fee(value, getFeeRate(feePriority), senderPay, address) + fun fee(value: Long, address: String? = null, senderPay: Boolean = true, feeRate: Int): Long { + return transactionBuilder.fee(value, feeRate, senderPay, address) } - fun send(address: String, value: Long, senderPay: Boolean = true, feePriority: FeePriority = FeePriority.Medium) { - transactionCreator.create(address, value, getFeeRate(feePriority), senderPay) + fun send(address: String, value: Long, senderPay: Boolean = true, feeRate: Int) { + transactionCreator.create(address, value, feeRate, senderPay) } fun receiveAddress(): String { @@ -224,22 +223,6 @@ class BitcoinKit(seed: ByteArray, networkType: NetworkType, walletId: String? = } } - private fun getFeeRate(feePriority: FeePriority): Int { - val feeRate: Double = when(feePriority) { - FeePriority.Lowest -> dataProvider.feeRate.lowPriority - FeePriority.Low -> { - (dataProvider.feeRate.lowPriority + dataProvider.feeRate.mediumPriority) / 2 - } - FeePriority.Medium -> dataProvider.feeRate.mediumPriority - FeePriority.High -> { - (dataProvider.feeRate.mediumPriority + dataProvider.feeRate.highPriority) / 2 - } - FeePriority.Highest -> dataProvider.feeRate.highPriority - is FeePriority.Custom -> feePriority.feeRate - } - return feeRate.toInt() - } - enum class NetworkType { MainNet, TestNet, diff --git a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/core/DataProvider.kt b/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/core/DataProvider.kt index fba9f8a7d..f08179311 100644 --- a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/core/DataProvider.kt +++ b/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/core/DataProvider.kt @@ -33,12 +33,6 @@ class DataProvider(private val realmFactory: RealmFactory, private val listener: var lastBlockInfo: BlockInfo? private set - val feeRate: FeeRate - get() = realmFactory.realm.use { realm -> - realm.where(FeeRate::class.java).findAll().firstOrNull()?.let { realm.copyFromRealm(it) } - ?: FeeRate.defaultFeeRate - } - init { lastBlockInfo = realmFactory.realm.use { realm -> realm.where(Block::class.java) diff --git a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/managers/ApiFeeRate.kt b/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/managers/ApiFeeRate.kt deleted file mode 100644 index f33cdd4d0..000000000 --- a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/managers/ApiFeeRate.kt +++ /dev/null @@ -1,36 +0,0 @@ -package io.horizontalsystems.bitcoinkit.managers - -import io.horizontalsystems.bitcoinkit.BitcoinKit -import io.horizontalsystems.bitcoinkit.BitcoinKit.NetworkType -import io.horizontalsystems.bitcoinkit.models.FeeRate -import io.reactivex.Maybe - -class ApiFeeRate(networkType: BitcoinKit.NetworkType) { - private val apiManager = ApiManager("https://ipfs.io") - private val coinCode = when (networkType) { - NetworkType.MainNet, NetworkType.TestNet, NetworkType.RegTest -> "BTC" - NetworkType.MainNetBitCash, NetworkType.TestNetBitCash -> "BCH" - } - - fun getFeeRate(): Maybe { - return Maybe.create { subscriber -> - try { - val json = apiManager.getJson("ipns/QmXTJZBMMRmBbPun6HFt3tmb3tfYF2usLPxFoacL7G5uMX/blockchain/estimatefee/index.json") - - val btcRates = json.get("rates").asObject().get(coinCode).asObject() - val rate = FeeRate().apply { - lowPriority = btcRates["low_priority"].asDouble() - mediumPriority = btcRates["medium_priority"].asDouble() - highPriority = btcRates["high_priority"].asDouble() - date = json["time"].asLong() - dateStr = json["time_str"].asString() - } - - subscriber.onSuccess(rate) - subscriber.onComplete() - } catch (e: Exception) { - subscriber.onError(e) - } - } - } -} diff --git a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/managers/FeeRateSyncer.kt b/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/managers/FeeRateSyncer.kt deleted file mode 100644 index ec0db1cbe..000000000 --- a/bitcoinkit/src/main/kotlin/io/horizontalsystems/bitcoinkit/managers/FeeRateSyncer.kt +++ /dev/null @@ -1,56 +0,0 @@ -package io.horizontalsystems.bitcoinkit.managers - -import io.horizontalsystems.bitcoinkit.core.RealmFactory -import io.horizontalsystems.bitcoinkit.models.FeeRate -import io.reactivex.Observable -import io.reactivex.disposables.Disposable -import java.util.concurrent.TimeUnit - -class FeeRateSyncer(private val realmFactory: RealmFactory, private val apiFeeRate: ApiFeeRate, private val connectionManager: ConnectionManager? = null) { - - private var timer = Observable.interval(0, 3, TimeUnit.MINUTES) - private var feeRateDisposable: Disposable? = null - private var timerDisposable: Disposable? = null - - constructor(realmFactory: RealmFactory, apiFeeRate: ApiFeeRate, timer: Observable, connectionManager: ConnectionManager) : this(realmFactory, apiFeeRate, connectionManager) { - this.timer = timer - } - - fun start() { - if (timerDisposable != null && timerDisposable?.isDisposed == false) { - return - } - - timerDisposable = timer.subscribe { - if (connectionManager?.isOnline == true && (feeRateDisposable == null || feeRateDisposable?.isDisposed == true)) { - updateFeeRate() - } - } - } - - fun stop() { - timerDisposable?.dispose() - timerDisposable = null - } - - private fun updateFeeRate() { - feeRateDisposable = apiFeeRate.getFeeRate() - .subscribe({ saveFeeRate(it) }, { dispose() }) - } - - private fun saveFeeRate(feeRate: FeeRate) { - dispose() - - realmFactory.realm.use { realm -> - realm.executeTransaction { - realm.insertOrUpdate(feeRate) - } - } - } - - private fun dispose() { - feeRateDisposable?.dispose() - feeRateDisposable = null - } - -} diff --git a/bitcoinkit/src/test/kotlin/io/horizontalsystems/bitcoinkit/managers/ApiFeeRateTest.kt b/bitcoinkit/src/test/kotlin/io/horizontalsystems/bitcoinkit/managers/ApiFeeRateTest.kt deleted file mode 100644 index e7be4b0f1..000000000 --- a/bitcoinkit/src/test/kotlin/io/horizontalsystems/bitcoinkit/managers/ApiFeeRateTest.kt +++ /dev/null @@ -1,70 +0,0 @@ -package io.horizontalsystems.bitcoinkit.managers - -import com.eclipsesource.json.JsonObject -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.whenever -import helpers.RxTestRule -import io.horizontalsystems.bitcoinkit.BitcoinKit.NetworkType -import io.horizontalsystems.bitcoinkit.models.FeeRate -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.mock -import org.powermock.api.mockito.PowerMockito -import org.powermock.core.classloader.annotations.PrepareForTest -import org.powermock.modules.junit4.PowerMockRunner - -@RunWith(PowerMockRunner::class) -@PrepareForTest(ApiFeeRate::class, ApiManager::class) - -class ApiFeeRateTest { - private val apiManager = mock(ApiManager::class.java) - - private val feeRate = FeeRate().apply { - lowPriority = 1.0 - mediumPriority = 3.0 - highPriority = 12.0 - dateStr = "2018-11-27 09:55" - date = 1543312547801 - } - - private val coinJsonObject = JsonObject().apply { - this.add("low_priority", feeRate.lowPriority.toInt()) - this.add("medium_priority", feeRate.mediumPriority.toInt()) - this.add("high_priority", feeRate.highPriority.toInt()) - } - - private val btcJsonObject = JsonObject().add("BTC", coinJsonObject) - private val jsonObject = JsonObject().apply { - this.add("rates", btcJsonObject) - this.add("time", feeRate.date) - this.add("time_str", feeRate.dateStr) - } - - private lateinit var apiFeeRate: ApiFeeRate - - @Before - fun setup() { - RxTestRule.setup() - - PowerMockito - .whenNew(ApiManager::class.java) - .withAnyArguments() - .thenReturn(apiManager) - - whenever(apiManager.getJson(any())).thenReturn(jsonObject) - } - - @Test - fun getFeeRate() { - apiFeeRate = ApiFeeRate(NetworkType.MainNet) - apiFeeRate.getFeeRate().test().assertValue { - feeRate.lowPriority == it.lowPriority && - feeRate.mediumPriority == it.mediumPriority && - feeRate.highPriority == it.highPriority && - feeRate.date == it.date && - feeRate.dateStr == it.dateStr - } - } - -}