Skip to content

Commit 8e8c3e1

Browse files
committed
fix(tokens): correct locale/region of completely empty balances
Also localize balance in valueExchangeIn back to USD if needed Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 2b66a6d commit 8e8c3e1

4 files changed

Lines changed: 57 additions & 24 deletions

File tree

apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.getcode.opencode.controllers.TokenController
1616
import com.getcode.opencode.exchange.Exchange
1717
import com.getcode.opencode.model.financial.Fiat
1818
import com.getcode.opencode.model.financial.LocalFiat
19+
import com.getcode.opencode.model.financial.Rate
1920
import com.getcode.opencode.model.financial.TokenWithLocalizedBalance
2021
import com.getcode.opencode.model.financial.sum
2122
import com.getcode.opencode.model.financial.toFiat
@@ -50,13 +51,25 @@ class SelectTokenViewModel @Inject constructor(
5051

5152
data class State(
5253
val purpose: TokenPurpose,
54+
val rate: Rate = Rate.oneToOne,
5355
val reservesEnabled: Boolean = false,
5456
val preferredOnRampProvider: OnRampProvider? = null,
5557
val tokens: List<TokenWithLocalizedBalance>? = null,
5658
val selectedToken: Mint? = null,
5759
) {
5860
val totalBalance: LocalFiat
59-
get() = tokens.orEmpty().map { it.balance }.sum()
61+
get() {
62+
val set = tokens.orEmpty()
63+
if (set.isEmpty()) {
64+
return LocalFiat.Zero
65+
.copy(
66+
nativeAmount = 0.toFiat(currencyCode = rate.currency),
67+
rate = rate
68+
)
69+
}
70+
71+
return set.map { it.balance }.sum()
72+
}
6073

6174
val aggregateAppreciation: LocalFiat?
6275
get() = tokens?.map { it.appreciation }?.sum()
@@ -66,6 +79,8 @@ class SelectTokenViewModel @Inject constructor(
6679
data class OnPreferredOnRampProviderChanged(val provider: OnRampProvider?) : Event
6780
data class OnReservesEnabled(val enabled: Boolean) : Event
6881

82+
data class OnRateChanged(val rate: Rate): Event
83+
6984
data class OnPurposeChanged(val purpose: TokenPurpose) : Event
7085
data class OnTokensUpdated(val tokens: List<TokenWithLocalizedBalance>) : Event
7186

@@ -106,32 +121,37 @@ class SelectTokenViewModel @Inject constructor(
106121
TokenPurpose.Deposit -> exchange.observeEntryRate()
107122
}
108123
) { state, balances, rate ->
124+
dispatchEvent(Event.OnRateChanged(rate))
109125
balances
110126
.map {
127+
val balance = LocalFiat(
128+
usdf = it.balance,
129+
nativeAmount = it.balance.convertingTo(rate),
130+
)
131+
132+
// USD reserves don't appreciate so we track that as MIN_VALUE internally to avoid confusion
133+
// with true zero's.
134+
val appreciation = if (it.appreciation == Fiat.MIN_VALUE) {
135+
LocalFiat(
136+
usdf = 0.toFiat(),
137+
nativeAmount = 0.toFiat(rate.currency),
138+
)
139+
} else {
140+
LocalFiat(
141+
usdf = it.appreciation,
142+
nativeAmount = it.appreciation.convertingTo(rate),
143+
)
144+
}
145+
111146
TokenWithLocalizedBalance(
112147
token = it.token,
113148
displayName = if (it.token.address == Mint.usdf) {
114149
resources.getString(R.string.title_cashReserves)
115150
} else {
116151
it.token.name
117152
},
118-
balance = LocalFiat(
119-
usdf = it.balance,
120-
nativeAmount = it.balance.convertingTo(rate),
121-
),
122-
// USD reserves don't appreciate so we track that as MIN_VALUE internally to avoid confusion
123-
// with true zero's.
124-
appreciation = if (it.appreciation == Fiat.MIN_VALUE) {
125-
LocalFiat(
126-
usdf = 0.toFiat(),
127-
nativeAmount = 0.toFiat(rate.currency),
128-
)
129-
} else {
130-
LocalFiat(
131-
usdf = it.appreciation,
132-
nativeAmount = it.appreciation.convertingTo(rate),
133-
)
134-
}
153+
balance = balance,
154+
appreciation = appreciation
135155
)
136156
}
137157
.sortedWith(compareByDescending { item ->
@@ -193,6 +213,10 @@ class SelectTokenViewModel @Inject constructor(
193213
state.copy(reservesEnabled = event.enabled)
194214
}
195215

216+
is Event.OnRateChanged -> { state ->
217+
state.copy(rate = event.rate)
218+
}
219+
196220
is Event.OnPurposeChanged -> { state -> state.copy(purpose = event.purpose) }
197221
is Event.OnTokensUpdated -> { state -> state.copy(tokens = event.tokens) }
198222
is Event.OnTokenSelected -> { state -> state.copy(selectedToken = event.mint) }

services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TokenController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class TokenController @Inject constructor(
9898
val tokenBalances: Flow<List<TokenWithBalance>> = _state.map { state ->
9999
state.balances.mapNotNull { (mint, balance) ->
100100
val token = state.tokens[mint] ?: return@mapNotNull null
101-
val appreciation = if (mint == Mint.usdf) Fiat.Zero else state.appreciation[mint] ?: Fiat.Zero
101+
val appreciation = if (mint == Mint.usdf) Fiat.MIN_VALUE else state.appreciation[mint] ?: Fiat.Zero
102102
TokenWithBalance(token, balance, appreciation)
103103
}
104104
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ data class Fiat(
125125
// String representation
126126
override fun toString(): String = formatted()
127127

128+
fun debugInfo(): String = "quarks: $quarks," +
129+
"decimalValue: $decimalValue," +
130+
"currencyCode: $currencyCode," +
131+
"isPositive: $isPositive," +
132+
"isNegative: $isNegative," +
133+
"formatted(): ${formatted()}," +
134+
"rounded(): ${rounded()}"
135+
128136
// Currency conversion
129137
fun convertingTo(rate: Rate): Fiat = Fiat(
130138
fiat = (quarks.toDouble() / MULTIPLIER) * rate.fx,
@@ -208,7 +216,9 @@ data class Fiat(
208216
estimation = {
209217
Estimator.sell(
210218
amountInQuarks = quarks,
211-
marketState = MarketState.FromSupply(token.launchpadMetadata?.currentCirculatingSupplyQuarks ?: 0,),
219+
marketState = MarketState.FromSupply(
220+
token.launchpadMetadata?.currentCirculatingSupplyQuarks ?: 0,
221+
),
212222
mintDecimals = token.decimals,
213223
outputDecimals = 6, // The desired value here is USDF which is 6
214224
feeBps = 0,

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,11 @@ data class LocalFiat(
114114
debug: Boolean = BuildConfig.DEBUG,
115115
trace: Boolean = true,
116116
): LocalFiat {
117+
val usdBalance = balance?.convertingToUsdIfNeeded(rate)
117118
val usdValue = amount.convertingToUsdIfNeeded(rate)
118119
// cap the entered amount as well, since our display rounds HALF_UP
119120
// e,g entered 0.02 USD, but balance is 0.016 USD
120-
val cappedValue = balance?.let { min(it, usdValue) } ?: usdValue
121+
val cappedValue = usdBalance?.let { min(it, usdValue) } ?: usdValue
121122

122123
if (token.address == Mint.usdf) {
123124
// this doesn't need a calculated value exchange since we are USDC
@@ -154,7 +155,7 @@ data class LocalFiat(
154155
rate = rate,
155156
amount = amount,
156157
usdValue = usdValue,
157-
balance = balance,
158+
balance = usdBalance,
158159
cappedValue = cappedValue,
159160
token = token,
160161
supply = supply,
@@ -246,7 +247,6 @@ fun Iterable<LocalFiat>.sum(): LocalFiat {
246247
}
247248

248249
operator fun LocalFiat.minus(other: LocalFiat): LocalFiat {
249-
if (mint != other.mint) throw IllegalArgumentException("Mint is mismatched")
250250
if (rate.currency != other.rate.currency) throw IllegalArgumentException("Currency is mismatched")
251251

252252
return copy(
@@ -256,7 +256,6 @@ operator fun LocalFiat.minus(other: LocalFiat): LocalFiat {
256256
}
257257

258258
operator fun LocalFiat.plus(other: LocalFiat): LocalFiat {
259-
if (mint != other.mint) throw IllegalArgumentException("Mint is mismatched")
260259
if (rate.currency != other.rate.currency) throw IllegalArgumentException("Currency is mismatched")
261260

262261
return copy(

0 commit comments

Comments
 (0)