Skip to content

Commit e39b400

Browse files
committed
fix(exchange): round Fiat.hasDisplayableValue to currency precision
The buy-sell round-trip through the bonding curve introduces sub-quark truncation, causing 0.01 USD to fall just below smallestUnit (9987 vs 10000 quarks). Round to the currency display digits before comparing so the property matches formatted() semantics. Also removes a debug println from RealVerifiedFiatCalculator.
1 parent 637722b commit e39b400

3 files changed

Lines changed: 22 additions & 2 deletions

File tree

services/opencode/src/main/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ internal class RealVerifiedFiatCalculator @Inject constructor(
114114
val underlyingTokenAmount = Fiat(quarks = quarks.toLong(), currencyCode = CurrencyCode.USD)
115115

116116
val sellEstimate = Fiat.tokenBalance(quarks.toLong(), token, supply).convertingTo(rate)
117-
118117
if (!sellEstimate.hasDisplayableValue) {
119118
return Result.failure(ComputeVerifiedFiatError.AmountBelowMinimum())
120119
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ data class Fiat(
163163

164164
/** Whether this value would format as non-zero in its currency. */
165165
val hasDisplayableValue: Boolean
166-
get() = this >= smallestUnit
166+
get() = rounded(currencyCode.fractionDigits) >= smallestUnit
167167

168168
fun valueLessThan(other: Fiat): Boolean = toDouble() < other.toDouble()
169169
fun valueGreaterThan(other: Fiat): Boolean = toDouble() > other.toDouble()

services/opencode/src/test/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculatorTest.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,27 @@ class RealVerifiedFiatCalculatorTest {
420420
assertIs<ComputeVerifiedFiatError.AmountBelowMinimum>(result.exceptionOrNull())
421421
}
422422

423+
@Test
424+
fun `one cent USD succeeds for established token`() = runTest {
425+
// Regression: $0.01 USD on a high-supply (established) bonding-curve token
426+
// would fail with AmountBelowMinimum due to round-trip precision loss through
427+
// the bonding curve. The sell estimate quarks (e.g. 9987) fell just below the
428+
// smallestUnit (10000) before rounding, even though formatted() shows "$0.01".
429+
val supply = 50_000_000_000_000L // established token with high supply
430+
val token = bondingCurveToken(supply = supply)
431+
stubVerifiedState(CurrencyCode.USD, testMint, supply)
432+
433+
val result = calculator.compute(
434+
amount = Fiat(fiat = 0.01, currencyCode = CurrencyCode.USD),
435+
token = token,
436+
rate = Rate.oneToOne,
437+
trace = false,
438+
)
439+
440+
assertTrue(result.isSuccess, "Expected success but got: ${result.exceptionOrNull()}")
441+
assertTrue(result.getOrThrow().localFiat.underlyingTokenAmount.quarks > 0)
442+
}
443+
423444
// endregion
424445

425446
// region helpers

0 commit comments

Comments
 (0)