Skip to content

Commit 0a0662b

Browse files
committed
chore(ocp/fiat): round HALF_UP (closest) when formatting
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 4087121 commit 0a0662b

5 files changed

Lines changed: 38 additions & 14 deletions

File tree

apps/flipcash/features/cash/src/main/kotlin/com/flipcash/app/cash/internal/CashScreenViewModel.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.flipcash.app.core.ui.CurrencyHolder
77
import com.flipcash.app.onramp.ConfirmationEvent
88
import com.flipcash.app.onramp.OnRampAmount
99
import com.flipcash.app.onramp.OnRampAmountController
10+
import com.flipcash.features.cash.BuildConfig
1011
import com.flipcash.features.cash.R
1112
import com.flipcash.services.analytics.AnalyticsEvent
1213
import com.flipcash.services.analytics.FlipcashAnalyticsService
@@ -26,6 +27,7 @@ import com.getcode.opencode.model.financial.Rate
2627
import com.getcode.opencode.model.financial.SendLimit
2728
import com.getcode.opencode.model.financial.TokenWithLocalizedBalance
2829
import com.getcode.opencode.model.financial.minus
30+
import com.getcode.opencode.utils.roundTo
2931
import com.getcode.solana.keys.Mint
3032
import com.getcode.ui.components.text.AmountAnimatedInputUiModel
3133
import com.getcode.ui.components.text.NumberInputHelper
@@ -82,11 +84,9 @@ internal class CashScreenViewModel @Inject constructor(
8284
val isError: Boolean
8385
get() {
8486
if (amountAnimatedModel.amountData.amount.isEmpty()) return false
85-
87+
val enteredAmount = Fiat(amountAnimatedModel.amountData.amount.toDoubleOrNull() ?: 0.0)
8688
if (maxForGive != null) {
87-
if ((amountAnimatedModel.amountData.amount.toDoubleOrNull()
88-
?: 0.0) <= maxForGive.first
89-
) {
89+
if (enteredAmount.doubleValue <= maxForGive.first.roundTo(2)) {
9090
return false
9191
}
9292
}
@@ -130,7 +130,7 @@ internal class CashScreenViewModel @Inject constructor(
130130
).convertingTo(conversionRate)
131131
val tokenBalance = stateFlow.value.token?.balance?.underlyingTokenAmount ?: Fiat.Zero
132132

133-
val isOverBalance = enteredInUsdc > tokenBalance
133+
val isOverBalance = enteredInUsdc > tokenBalance.rounded()
134134
if (isOverBalance || conversionRate == Rate.ignore) {
135135
BottomBarManager.showMessage(
136136
resources.getString(R.string.error_title_youNeedMoreCash),

apps/flipcash/features/withdrawal/src/main/kotlin/com/flipcash/app/withdrawal/WithdrawalViewModel.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import com.getcode.opencode.model.financial.TokenWithBalance
2828
import com.getcode.opencode.model.financial.TokenWithLocalizedBalance
2929
import com.getcode.opencode.model.financial.minus
3030
import com.getcode.opencode.model.transactions.WithdrawalAvailability
31+
import com.getcode.opencode.utils.roundTo
3132
import com.getcode.solana.keys.Mint
3233
import com.getcode.ui.components.text.AmountAnimatedInputUiModel
3334
import com.getcode.ui.components.text.NumberInputHelper
@@ -101,11 +102,8 @@ internal class WithdrawalViewModel @Inject constructor(
101102
val isError: Boolean
102103
get() {
103104
if (amountEntryState.amountAnimatedModel.amountData.amount.isEmpty()) return false
104-
105-
if (
106-
(amountEntryState.amountAnimatedModel.amountData.amount.toDoubleOrNull()
107-
?: 0.0) <= tokenBalance.doubleValue
108-
) {
105+
val enteredAmount = Fiat(amountEntryState.amountAnimatedModel.amountData.amount.toDoubleOrNull() ?: 0.0)
106+
if (enteredAmount.doubleValue <= tokenBalance.rounded().doubleValue) {
109107
return false
110108
}
111109

@@ -172,7 +170,7 @@ internal class WithdrawalViewModel @Inject constructor(
172170
).convertingTo(conversionRate)
173171
val tokenBalance = stateFlow.value.token?.balance ?: Fiat.Zero
174172

175-
val isOverBalance = enteredInUsdc > tokenBalance
173+
val isOverBalance = enteredInUsdc > tokenBalance.rounded()
176174
if (isOverBalance || conversionRate == Rate.ignore) {
177175
BottomBarManager.showError(
178176
title = resources.getString(R.string.error_title_insufficientFunds),

services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Fiat.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.icu.util.ULocale
44
import android.os.Parcelable
55
import com.flipcash.libs.currency.math.Estimator
66
import com.flipcash.libs.currency.math.divideWithHighPrecision
7+
import com.getcode.opencode.utils.roundTo
78
import com.getcode.solana.keys.Mint
89
import kotlinx.parcelize.Parcelize
910
import kotlinx.serialization.Serializable
@@ -60,6 +61,13 @@ data class Fiat(
6061
data class Length(val decimalPlaces: Int) : Formatting
6162
}
6263

64+
fun rounded(decimalPlaces: Int = 2): Fiat {
65+
return Fiat(
66+
fiat = doubleValue.roundTo(decimalPlaces, ROUNDING_MODE),
67+
currencyCode = currencyCode
68+
)
69+
}
70+
6371
// Formatting
6472
fun formatted(
6573
formatting: Formatting = Formatting.None,
@@ -85,7 +93,7 @@ data class Fiat(
8593
}
8694
minimumFractionDigits = preferredDigits
8795
maximumFractionDigits = preferredDigits
88-
roundingMode = RoundingMode.DOWN.ordinal
96+
roundingMode = ROUNDING_MODE
8997
(this as android.icu.text.DecimalFormat).decimalFormatSymbols =
9098
decimalFormatSymbols.apply {
9199
currencySymbol = ""
@@ -140,13 +148,14 @@ data class Fiat(
140148
maximumFractionDigits = fractionDigits
141149
minimumFractionDigits = fractionDigits
142150
}
143-
roundingMode = RoundingMode.DOWN.ordinal
151+
roundingMode = ROUNDING_MODE
144152
}
145153

146154
return formatter.format(tokens.toDouble())
147155
}
148156

149157
companion object {
158+
private val ROUNDING_MODE = RoundingMode.HALF_UP.ordinal
150159
const val MULTIPLIER: Double = 1_000_000.0
151160

152161
val Zero = Fiat(0, CurrencyCode.USD)

services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.flipcash.libs.currency.math.Estimator
44
import com.flipcash.libs.currency.math.divideWithHighPrecision
55
import com.flipcash.libs.currency.math.units
66
import com.getcode.opencode.model.transactions.ExchangeData
7+
import com.getcode.services.opencode.BuildConfig
78
import com.getcode.solana.keys.Mint
89
import kotlinx.serialization.Serializable
910
import java.math.BigDecimal
@@ -65,7 +66,7 @@ data class LocalFiat(
6566
token: Token,
6667
balance: Fiat = Fiat.Zero,
6768
rate: Rate,
68-
debug: Boolean = false,
69+
debug: Boolean = BuildConfig.DEBUG,
6970
): LocalFiat {
7071
val usdValue = amount.convertingToUsdIfNeeded(rate)
7172

@@ -102,6 +103,7 @@ data class LocalFiat(
102103
val fx = rate.fx * usdFx.toDouble()
103104

104105
if (debug) {
106+
println("############## EXCHANGE REPORT ###################")
105107
println("requested quarks: ${usdValue.quarks * 1_000_000}")
106108
println("balance quarks: ${balance.quarks * 1_000_000}")
107109
println("capped quarks: ${cappedValue.quarks * 1_000_000}")
@@ -111,6 +113,7 @@ data class LocalFiat(
111113
println("fx: $fx")
112114
val sellAmount = Fiat.tokenBalance(quarks.toLong(), token = token)
113115
println("sellAmount: ${sellAmount.formatted(formatting = Fiat.Formatting.Length(10))}")
116+
println("##################################################")
114117
}
115118

116119
return LocalFiat(

services/opencode/src/main/kotlin/com/getcode/opencode/utils/Double.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.getcode.opencode.utils
22

3+
import java.math.BigDecimal
4+
import java.math.RoundingMode
5+
36

47
fun Double.toByteArray(): ByteArray {
58
val longBits = java.lang.Double.doubleToLongBits(this)
@@ -10,4 +13,15 @@ fun Double.toByteArray(): ByteArray {
1013
}
1114

1215
return byteArray
16+
}
17+
18+
/**
19+
* Rounds the Double value to the specified number of decimal places using the given rounding mode.
20+
*
21+
* @param decimals The number of decimal places to round to.
22+
* @param mode The rounding mode to apply (e.g., RoundingMode.HALF_UP).
23+
* @return The rounded Double value.
24+
*/
25+
fun Double.roundTo(decimals: Int, mode: Int = RoundingMode.HALF_UP.ordinal): Double {
26+
return BigDecimal.valueOf(this).setScale(decimals, mode).toDouble()
1327
}

0 commit comments

Comments
 (0)