Skip to content

Commit

Permalink
fix: fix many bugs with retrieving rates from FX services
Browse files Browse the repository at this point in the history
  • Loading branch information
HashEngineering committed Jun 20, 2024
1 parent 206be34 commit b1cf7de
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package org.dash.wallet.common.ui.recyclerview
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import org.dash.wallet.common.R
import org.dash.wallet.common.databinding.RadiobuttonRowBinding
Expand All @@ -29,8 +30,9 @@ import org.dash.wallet.common.ui.radio_group.RadioGroupAdapter
import org.dash.wallet.common.ui.setRoundedRippleBackground

class IconifiedListAdapter(
diffCallback: DiffUtil.ItemCallback<IconifiedViewItem> = RadioGroupAdapter.DiffCallback(),
private val clickListener: (IconifiedViewItem, Int) -> Unit
): ListAdapter<IconifiedViewItem, IconifiedViewHolder>(RadioGroupAdapter.DiffCallback()) {
): ListAdapter<IconifiedViewItem, IconifiedViewHolder>(diffCallback) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IconifiedViewHolder {
val inflater = LayoutInflater.from(parent.context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class FiatExchangeRateApiAggregator @Inject constructor(
val lastCurrencyCode = mayaConfig.get(MayaConfig.EXCHANGE_RATE_CURRENCY_CODE)
if (lastCurrencyCode != currencyCode || lastUpdate == null || lastUpdate == 0L ||
(System.currentTimeMillis() - lastUpdate) > MayaConfig.expirationDuration) {

if (currencyCode == MayaConstants.DEFAULT_EXCHANGE_CURRENCY) {
return ExchangeRate(MayaConstants.DEFAULT_EXCHANGE_CURRENCY, "1.0")
}
val currencyBeaconResponse =
currencyBeaconApi.getRates(MayaConstants.DEFAULT_EXCHANGE_CURRENCY, currencyCode)
if (currencyBeaconResponse.isSuccessful) {
Expand Down Expand Up @@ -72,7 +76,7 @@ class FiatExchangeRateApiAggregator @Inject constructor(
return if (exchangeRate != 0.0) {
saveNewExchangeRate(exchangeRate, currencyCode)
} else {
null
ExchangeRate(MayaConstants.DEFAULT_EXCHANGE_CURRENCY, "1.0")
}
} else {
val lastValue = mayaConfig.get(MayaConfig.EXCHANGE_RATE_VALUE) ?: 0
Expand Down Expand Up @@ -101,7 +105,6 @@ class FiatExchangeRateAggregatedProvider @Inject constructor(
) : FiatExchangeRateProvider {
companion object {
private val log = LoggerFactory.getLogger(FiatExchangeRateApiAggregator::class.java)
private val UPDATE_FREQ_MS = TimeUnit.SECONDS.toMillis(30)
}

private val responseScope = CoroutineScope(
Expand All @@ -111,31 +114,23 @@ class FiatExchangeRateAggregatedProvider @Inject constructor(
override val fiatExchangeRate = MutableStateFlow(ExchangeRate(MayaConstants.DEFAULT_EXCHANGE_CURRENCY, "1.0"))

override fun observeFiatRate(currencyCode: String): Flow<ExchangeRate?> {
if (shouldRefresh()) {
refreshRates(currencyCode)
}
refreshRates(currencyCode)
return fiatExchangeRate
}

private fun refreshRates(currencyCode: String) {
if (!shouldRefresh()) {
return
}

responseScope.launch {
updateExchangeRates(currencyCode)
poolListLastUpdated = System.currentTimeMillis()
}
}

private fun shouldRefresh(): Boolean {
val now = System.currentTimeMillis()
return poolListLastUpdated == 0L || now - poolListLastUpdated > UPDATE_FREQ_MS
}

private suspend fun updateExchangeRates(currencyCode: String) {
fiatExchangeRateApi.getRate(currencyCode)?.let { rate ->
fiatExchangeRate.value = rate
val newRate = fiatExchangeRateApi.getRate(currencyCode)
if (newRate != null) {
fiatExchangeRate.value = newRate
} else {
fiatExchangeRate.value = ExchangeRate(MayaConstants.DEFAULT_EXCHANGE_CURRENCY, "1.0")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import org.dash.wallet.integrations.maya.model.getMayaErrorString
import org.dash.wallet.integrations.maya.model.getMayaErrorType

class MayaAddressInputFragment : AddressInputFragment() {
private val mayaViewModel by viewModels<MayaViewModel>()
private val mayaViewModel by mayaViewModels<MayaViewModel>()
private val mayaAddressInputViewModel by viewModels<MayaAddressInputViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class MayaConvertCryptoFragment : Fragment(R.layout.fragment_maya_convert_crypto
private val binding by viewBinding(FragmentMayaConvertCryptoBinding::bind)
private val viewModel by viewModels<MayaConvertCryptoViewModel>()
private val convertViewModel by mayaViewModels<ConvertViewViewModel>()
private val mayaViewModel by viewModels<MayaViewModel>()
private val mayaViewModel by mayaViewModels<MayaViewModel>()
private val args by navArgs<MayaConvertCryptoFragmentArgs>()

private var loadingDialog: AdaptiveDialog? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DiffUtil
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.dash.wallet.common.ui.decorators.ListDividerDecorator
Expand All @@ -40,22 +41,38 @@ import org.dash.wallet.integrations.maya.R
import org.dash.wallet.integrations.maya.databinding.FragmentCurrencyPickerBinding
import org.dash.wallet.integrations.maya.model.PoolInfo
import org.dash.wallet.integrations.maya.payments.MayaCurrencyList
import org.slf4j.LoggerFactory

@AndroidEntryPoint
class MayaCryptoCurrencyPickerFragment : Fragment(R.layout.fragment_currency_picker) {
companion object {
private val log = LoggerFactory.getLogger(MayaCryptoCurrencyPickerFragment::class.java)
}
private val binding by viewBinding(FragmentCurrencyPickerBinding::bind)
private val viewModel by viewModels<MayaViewModel>()
private val viewModel by mayaViewModels<MayaViewModel>()
private var itemList = listOf<IconifiedViewItem>()
private lateinit var defaultItemMap: Map<String, IconifiedViewItem>

class FullDiffCallback : DiffUtil.ItemCallback<IconifiedViewItem>() {
override fun areItemsTheSame(oldItem: IconifiedViewItem, newItem: IconifiedViewItem): Boolean {
return oldItem.title == newItem.title &&
oldItem.iconRes == newItem.iconRes &&
oldItem.additionalInfo == newItem.additionalInfo
}

override fun areContentsTheSame(oldItem: IconifiedViewItem, newItem: IconifiedViewItem): Boolean {
return oldItem == newItem
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.toolbar.setNavigationOnClickListener {
findNavController().popBackStack()
}

val adapter = IconifiedListAdapter() { item, index ->
val adapter = IconifiedListAdapter(diffCallback = FullDiffCallback()) { item, _ ->
viewModel.poolList.value.firstOrNull {
it.asset == item.id
}?.let {
Expand Down Expand Up @@ -132,6 +149,7 @@ class MayaCryptoCurrencyPickerFragment : Fragment(R.layout.fragment_currency_pic
)
}
}.sortedBy { it.title }
log.info("exchange rate: updating itemList with {}", itemList[0].additionalInfo)
adapter.submitList(itemList)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import org.dash.wallet.integrations.maya.R
class MayaPortalFragment : Fragment(R.layout.fragment_integration_portal) {

private val binding by viewBinding(FragmentIntegrationPortalBinding::bind)
private val viewModel by viewModels<MayaViewModel>()
private val viewModel by mayaViewModels<MayaViewModel>()
private var balanceAnimator: ObjectAnimator? = null

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,23 @@ class MayaViewModel @Inject constructor(

walletUIConfig.observe(WalletUIConfig.SELECTED_CURRENCY)
.filterNotNull()
.onEach { log.info("selected currency: {}", it) }
.onEach { log.info("exchange rate selected currency: {}", it) }
.flatMapLatest(fiatExchangeRateProvider::observeFiatRate)
.onEach {
it?.let { fiatRate ->
fiatFormat = fiatFormat.minDecimals(GenericUtils.getCurrencyDigits(it.currencyCode))
fiatFormat = fiatFormat.minDecimals(GenericUtils.getCurrencyDigits(fiatRate.currencyCode))
fiatExchangeRate = fiatRate.fiat
}
log.info("exchange rate: $it")
}
.flatMapLatest { mayaApi.observePoolList(it!!.fiat) }
.onEach {
.onEach { newPoolList ->
log.info("exchange rate in view model: {}", fiatExchangeRate?.toFriendlyString())
log.info("Pool List: {}", it)
log.info("Pool List: {}", it.map { pool -> pool.assetPriceFiat })
it.forEach { pool ->
newPoolList.forEach { pool ->
pool.setAssetPrice(fiatExchangeRate!!)
}
poolList.value = it
log.info("exchange rate Pool List: {}", newPoolList.map { pool -> pool.assetPriceFiat.toFriendlyString() })
poolList.value = newPoolList
}
.launchIn(viewModelScope)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,19 @@ object MayaConstants {
private const val MAINNET_BASE_URL = "https://mayanode.mayachain.info/mayachain/"

/**
* https://exchangerate.host/#/docs
* https://www.exchangerate-api.com/docs/overview
*/
const val EXCHANGERATE_BASE_URL = "https://api.exchangerate.host/"
const val EXCHANGERATE_BASE_URL = "https://v6.exchangerate-api.com/v6/cb83a189f4780ccfde2883d6/"

/**
* https://currencybeacon.com/api-documentation
*/
const val CURRENCYBEACON_BASE_URL = "https://api.currencybeacon.com/v1/"

/**
* https://freecurrencyapi.com/docs/
*/
const val FREE_CURRENCY_API_BASE_URL = "https://api.freecurrencyapi.com/v1/"

fun getBaseUrl(params: NetworkParameters): String {
return MAINNET_BASE_URL
Expand All @@ -43,4 +53,4 @@ object MayaConstants {
const val ERROR_ID_2FA_REQUIRED = "two_factor_required"
const val ERROR_MSG_INVALID_REQUEST = "That code was invalid"
const val TRANSACTION_TYPE_SEND = "send"
}
}

0 comments on commit b1cf7de

Please sign in to comment.