From 4082d86da1995ee4309dd618c87ccad5ec762735 Mon Sep 17 00:00:00 2001 From: ismurzin Date: Mon, 22 Apr 2024 17:51:03 +0400 Subject: [PATCH] fix broken exchange logic + add network fee to calculation --- .../external/changelly/ChangellyAPIService.kt | 31 +++++++++----- .../external/changelly/model/FixRate.kt | 1 + .../changelly/model/FixRateForAmount.kt | 22 ---------- .../external/changelly2/ExchangeFragment.kt | 42 +++++++++++++------ .../changelly2/remote/Changelly2Repository.kt | 29 ++++++++----- .../changelly2/viewmodel/ExchangeViewModel.kt | 7 ++-- 6 files changed, 71 insertions(+), 61 deletions(-) delete mode 100644 mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRateForAmount.kt diff --git a/mbw/src/main/java/com/mycelium/wallet/external/changelly/ChangellyAPIService.kt b/mbw/src/main/java/com/mycelium/wallet/external/changelly/ChangellyAPIService.kt index a253ae148..1b6f5932d 100644 --- a/mbw/src/main/java/com/mycelium/wallet/external/changelly/ChangellyAPIService.kt +++ b/mbw/src/main/java/com/mycelium/wallet/external/changelly/ChangellyAPIService.kt @@ -1,7 +1,12 @@ package com.mycelium.wallet.external.changelly -import com.mycelium.wallet.external.changelly.model.* -import org.jetbrains.annotations.TestOnly +import com.mycelium.wallet.external.changelly.model.ChangellyCurrency +import com.mycelium.wallet.external.changelly.model.ChangellyGetExchangeAmountResponse +import com.mycelium.wallet.external.changelly.model.ChangellyListResponse +import com.mycelium.wallet.external.changelly.model.ChangellyResponse +import com.mycelium.wallet.external.changelly.model.ChangellyTransaction +import com.mycelium.wallet.external.changelly.model.ChangellyTransactionOffer +import com.mycelium.wallet.external.changelly.model.FixRate import retrofit2.Call import retrofit2.Response import retrofit2.http.POST @@ -56,7 +61,17 @@ interface ChangellyAPIService { @Query("from") from: String, @Query("to") to: String, @Query("amountFrom") amount: BigDecimal = BigDecimal.ONE, - ): Response> + ): Response> + + @Deprecated( + "To get the fixed rate, you need to use getFixRateForAmount, but the transaction amount must be within limits", + ReplaceWith("getFixRateForAmount") + ) + @POST("getFixRate") + suspend fun getFixRate( + @Query("from") from: String, + @Query("to") to: String, + ): Response> @POST("createFixTransaction") suspend fun createFixTransaction( @@ -70,7 +85,8 @@ interface ChangellyAPIService { @POST("getTransactions") suspend fun getTransaction( - @Query("id") id: String + @Query("id") id: String, + @Query("limit") limit: Int = 1, ): Response>> @POST("getTransactions") @@ -78,13 +94,6 @@ interface ChangellyAPIService { @Query("id") id: List, ): Response>> - - @TestOnly - @POST("getFixRate") - suspend fun getFixRate(@Query("from") from: String, - @Query("to") to: String): Response> - - companion object { const val BCH = "BCH" const val BTC = "BTC" diff --git a/mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRate.kt b/mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRate.kt index 792f2579d..3437e33ce 100644 --- a/mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRate.kt +++ b/mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRate.kt @@ -13,4 +13,5 @@ data class FixRate( val minTo: BigDecimal, val amountFrom: BigDecimal, val amountTo: BigDecimal, + val networkFee: BigDecimal, ) diff --git a/mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRateForAmount.kt b/mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRateForAmount.kt deleted file mode 100644 index 2db4651db..000000000 --- a/mbw/src/main/java/com/mycelium/wallet/external/changelly/model/FixRateForAmount.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.mycelium.wallet.external.changelly.model - -import java.math.BigDecimal - - -data class FixRateForAmount(val id: String, - val result: BigDecimal, - val networkFee: BigDecimal, - val from: String, - val to: String, - val amountFrom: BigDecimal, - val amountTo: BigDecimal, - val max: BigDecimal, - val maxFrom:BigDecimal, - val maxTo:BigDecimal, - val min:BigDecimal, - val minFrom:BigDecimal, - val minTo:BigDecimal) { - - fun getExpectedValue() = result - networkFee -} - diff --git a/mbw/src/main/java/com/mycelium/wallet/external/changelly2/ExchangeFragment.kt b/mbw/src/main/java/com/mycelium/wallet/external/changelly2/ExchangeFragment.kt index 6e4aa1046..5f5c30b71 100644 --- a/mbw/src/main/java/com/mycelium/wallet/external/changelly2/ExchangeFragment.kt +++ b/mbw/src/main/java/com/mycelium/wallet/external/changelly2/ExchangeFragment.kt @@ -22,7 +22,10 @@ import com.bumptech.glide.load.resource.bitmap.CircleCrop import com.bumptech.glide.request.RequestOptions import com.mrd.bitlib.model.BitcoinAddress import com.mycelium.view.RingDrawable -import com.mycelium.wallet.* +import com.mycelium.wallet.BuildConfig +import com.mycelium.wallet.MbwManager +import com.mycelium.wallet.R +import com.mycelium.wallet.Utils import com.mycelium.wallet.activity.modern.ModernMain import com.mycelium.wallet.activity.modern.event.BackHandler import com.mycelium.wallet.activity.modern.event.BackListener @@ -36,14 +39,19 @@ import com.mycelium.wallet.activity.util.toStringWithUnit import com.mycelium.wallet.activity.view.ValueKeyboard import com.mycelium.wallet.activity.view.loader import com.mycelium.wallet.databinding.FragmentChangelly2ExchangeBinding -import com.mycelium.wallet.event.* +import com.mycelium.wallet.event.ExchangeRatesRefreshed +import com.mycelium.wallet.event.ExchangeSourceChanged +import com.mycelium.wallet.event.PageSelectedEvent +import com.mycelium.wallet.event.SelectedAccountChanged +import com.mycelium.wallet.event.SelectedCurrencyChanged +import com.mycelium.wallet.event.TransactionBroadcasted import com.mycelium.wallet.external.changelly.model.ChangellyResponse import com.mycelium.wallet.external.changelly.model.ChangellyTransactionOffer import com.mycelium.wallet.external.changelly.model.FixRate -import com.mycelium.wallet.external.changelly.model.FixRateForAmount import com.mycelium.wallet.external.changelly2.remote.Changelly2Repository import com.mycelium.wallet.external.changelly2.viewmodel.ExchangeViewModel import com.mycelium.wallet.external.partner.openLink +import com.mycelium.wallet.startCoroutineTimer import com.mycelium.wapi.wallet.AesKeyCipher import com.mycelium.wapi.wallet.BroadcastResultType import com.mycelium.wapi.wallet.Transaction @@ -183,7 +191,7 @@ class ExchangeFragment : Fragment(), BackListener { val exchangeInfoResult = viewModel.exchangeInfo.value?.result if (friendlyDigits == null || exchangeInfoResult == null) N_A else amount.toBigDecimal().setScale(friendlyDigits, RoundingMode.HALF_UP) - ?.div(viewModel.exchangeInfo.value!!.getExpectedValue()) + ?.div(exchangeInfoResult) ?.stripTrailingZeros() ?.toPlainString() ?: N_A } catch (e: NumberFormatException) { @@ -358,13 +366,17 @@ class ExchangeFragment : Fragment(), BackListener { private fun computeBuyValue() { val amount = viewModel.sellValue.value - viewModel.buyValue.value = if (amount?.isNotEmpty() == true - && viewModel.exchangeInfo.value?.result != null) { + val info = viewModel.exchangeInfo.value + val rate = info?.result + val networkFee = info?.networkFee ?: BigDecimal.ZERO + viewModel.buyValue.value = if (amount?.isNotEmpty() == true && rate != null) { try { - (amount.toBigDecimal() * viewModel.exchangeInfo.value?.getExpectedValue()!!) - .setScale(viewModel.toCurrency.value?.friendlyDigits!!, RoundingMode.HALF_UP) - .stripTrailingZeros() - .toPlainString() + val result = amount.toBigDecimal() * rate - networkFee + if (result <= BigDecimal.ZERO) null + else result + .setScale(viewModel.toCurrency.value?.friendlyDigits!!, RoundingMode.HALF_UP) + .stripTrailingZeros() + .toPlainString() } catch (e: NumberFormatException) { "N/A" } @@ -439,7 +451,12 @@ class ExchangeFragment : Fragment(), BackListener { { result -> val data = result?.result?.firstOrNull() if (data != null) { - viewModel.exchangeInfo.value = data + val info = viewModel.exchangeInfo.value + viewModel.exchangeInfo.value = if (info == null) data else data.copy( + amountFrom = info.amountFrom, + amountTo = info.amountTo, + networkFee = info.networkFee, + ) viewModel.errorRemote.value = "" } else { viewModel.errorRemote.value = result?.error?.message ?: "" @@ -485,8 +502,7 @@ class ExchangeFragment : Fragment(), BackListener { fromAmount, { result -> result?.result?.firstOrNull()?.let { - val info = viewModel.exchangeInfo.value - viewModel.exchangeInfo.postValue(it) + viewModel.exchangeInfo.value = it viewModel.errorRemote.value = "" } ?: run { viewModel.errorRemote.value = result?.error?.message ?: "" diff --git a/mbw/src/main/java/com/mycelium/wallet/external/changelly2/remote/Changelly2Repository.kt b/mbw/src/main/java/com/mycelium/wallet/external/changelly2/remote/Changelly2Repository.kt index 7d07040ac..1cedf7b66 100644 --- a/mbw/src/main/java/com/mycelium/wallet/external/changelly2/remote/Changelly2Repository.kt +++ b/mbw/src/main/java/com/mycelium/wallet/external/changelly2/remote/Changelly2Repository.kt @@ -3,7 +3,12 @@ package com.mycelium.wallet.external.changelly2.remote import androidx.lifecycle.LifecycleCoroutineScope import com.mycelium.bequant.remote.doRequest import com.mycelium.wallet.external.changelly.ChangellyRetrofitFactory -import com.mycelium.wallet.external.changelly.model.* +import com.mycelium.wallet.external.changelly.model.ChangellyCurrency +import com.mycelium.wallet.external.changelly.model.ChangellyListResponse +import com.mycelium.wallet.external.changelly.model.ChangellyResponse +import com.mycelium.wallet.external.changelly.model.ChangellyTransaction +import com.mycelium.wallet.external.changelly.model.ChangellyTransactionOffer +import com.mycelium.wallet.external.changelly.model.FixRate import kotlinx.coroutines.CoroutineScope import java.math.BigDecimal @@ -26,7 +31,7 @@ object Changelly2Repository { from: String, to: String, amount: BigDecimal, - success: (ChangellyListResponse?) -> Unit, + success: (ChangellyListResponse?) -> Unit, error: (Int, String) -> Unit, finally: (() -> Unit)? = null ) = @@ -34,15 +39,17 @@ object Changelly2Repository { api.getFixRateForAmount(exportSymbol(from), exportSymbol(to), amount) }, success, error, finally) - fun fixRate(scope: CoroutineScope, - from: String, - to: String, - success: (ChangellyListResponse?) -> Unit, - error: (Int, String) -> Unit, - finally: (() -> Unit)? = null) = - doRequest(scope, { - api.getFixRateForAmount(exportSymbol(from), exportSymbol(to)) - }, success, error, finally) + fun fixRate( + scope: CoroutineScope, + from: String, + to: String, + success: (ChangellyListResponse?) -> Unit, + error: (Int, String) -> Unit, + finally: (() -> Unit)? = null + ) = + doRequest(scope, { + api.getFixRate(exportSymbol(from), exportSymbol(to)) + }, success, error, finally) fun createFixTransaction( scope: CoroutineScope, diff --git a/mbw/src/main/java/com/mycelium/wallet/external/changelly2/viewmodel/ExchangeViewModel.kt b/mbw/src/main/java/com/mycelium/wallet/external/changelly2/viewmodel/ExchangeViewModel.kt index 2a0f17202..447317aad 100644 --- a/mbw/src/main/java/com/mycelium/wallet/external/changelly2/viewmodel/ExchangeViewModel.kt +++ b/mbw/src/main/java/com/mycelium/wallet/external/changelly2/viewmodel/ExchangeViewModel.kt @@ -14,7 +14,6 @@ import com.mycelium.wallet.WalletApplication import com.mycelium.wallet.activity.util.toStringFriendlyWithUnit import com.mycelium.wallet.activity.util.toStringWithUnit import com.mycelium.wallet.external.changelly.model.FixRate -import com.mycelium.wallet.external.changelly.model.FixRateForAmount import com.mycelium.wapi.wallet.Address import com.mycelium.wapi.wallet.Transaction import com.mycelium.wapi.wallet.Util @@ -35,7 +34,7 @@ class ExchangeViewModel(application: Application) : AndroidViewModel(application val mbwManager = MbwManager.getInstance(WalletApplication.getInstance()) var currencies = setOf("BTC", "ETH") val fromAccount = MutableLiveData>() - val exchangeInfo = MutableLiveData() + val exchangeInfo = MutableLiveData() val sellValue = object : MutableLiveData() { override fun setValue(value: String?) { if (this.value != value) { @@ -59,7 +58,7 @@ class ExchangeViewModel(application: Application) : AndroidViewModel(application } } } - val swapEnableDelay = MutableLiveData(false) + val swapEnableDelay = MutableLiveData(false) val swapEnabled = MediatorLiveData().apply { value = false fun update() { @@ -152,7 +151,7 @@ class ExchangeViewModel(application: Application) : AndroidViewModel(application } val exchangeRateToValue = Transformations.map(exchangeInfo) { - it.getExpectedValue().toPlainString() + it.result.toPlainString() } val exchangeRateToCurrency = Transformations.map(exchangeInfo) {