Skip to content

Commit

Permalink
fix broken exchange logic + add network fee to calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
ismurzin committed Apr 24, 2024
1 parent 2e83082 commit c03b4c1
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -56,7 +61,17 @@ interface ChangellyAPIService {
@Query("from") from: String,
@Query("to") to: String,
@Query("amountFrom") amount: BigDecimal = BigDecimal.ONE,
): Response<ChangellyListResponse<FixRateForAmount>>
): Response<ChangellyListResponse<FixRate>>

@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<ChangellyListResponse<FixRate>>

@POST("createFixTransaction")
suspend fun createFixTransaction(
Expand All @@ -70,21 +85,15 @@ interface ChangellyAPIService {

@POST("getTransactions")
suspend fun getTransaction(
@Query("id") id: String
@Query("id") id: String,
@Query("limit") limit: Int = 1,
): Response<ChangellyResponse<List<ChangellyTransaction>>>

@POST("getTransactions")
suspend fun getTransactions(
@Query("id") id: List<String>,
): Response<ChangellyResponse<List<ChangellyTransaction>>>


@TestOnly
@POST("getFixRate")
suspend fun getFixRate(@Query("from") from: String,
@Query("to") to: String): Response<ChangellyResponse<FixRateForAmount>>


companion object {
const val BCH = "BCH"
const val BTC = "BTC"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ data class FixRate(
val maxTo: BigDecimal,
val minFrom: BigDecimal,
val minTo: BigDecimal,
val amountFrom: BigDecimal,
val amountTo: BigDecimal,
val amountFrom: BigDecimal?,
val amountTo: BigDecimal?,
val networkFee: BigDecimal?,
)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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"
}
Expand Down Expand Up @@ -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 ?: ""
Expand Down Expand Up @@ -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 ?: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -26,23 +31,25 @@ object Changelly2Repository {
from: String,
to: String,
amount: BigDecimal,
success: (ChangellyListResponse<FixRateForAmount>?) -> Unit,
success: (ChangellyListResponse<FixRate>?) -> Unit,
error: (Int, String) -> Unit,
finally: (() -> Unit)? = null
) =
doRequest(scope, {
api.getFixRateForAmount(exportSymbol(from), exportSymbol(to), amount)
}, success, error, finally)

fun fixRate(scope: CoroutineScope,
from: String,
to: String,
success: (ChangellyListResponse<FixRateForAmount>?) -> 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<FixRate>?) -> Unit,
error: (Int, String) -> Unit,
finally: (() -> Unit)? = null
) =
doRequest(scope, {
api.getFixRate(exportSymbol(from), exportSymbol(to))
}, success, error, finally)

fun createFixTransaction(
scope: CoroutineScope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,7 +34,7 @@ class ExchangeViewModel(application: Application) : AndroidViewModel(application
val mbwManager = MbwManager.getInstance(WalletApplication.getInstance())
var currencies = setOf("BTC", "ETH")
val fromAccount = MutableLiveData<WalletAccount<*>>()
val exchangeInfo = MutableLiveData<FixRateForAmount>()
val exchangeInfo = MutableLiveData<FixRate>()
val sellValue = object : MutableLiveData<String>() {
override fun setValue(value: String?) {
if (this.value != value) {
Expand All @@ -59,7 +58,7 @@ class ExchangeViewModel(application: Application) : AndroidViewModel(application
}
}
}
val swapEnableDelay = MutableLiveData<Boolean>(false)
val swapEnableDelay = MutableLiveData(false)
val swapEnabled = MediatorLiveData<Boolean>().apply {
value = false
fun update() {
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit c03b4c1

Please sign in to comment.