Skip to content

Conversation

@dbart01
Copy link
Collaborator

@dbart01 dbart01 commented Dec 9, 2025

Summary

This PR migrates the iOS bonding curve implementation from a continuous exponential formula to a discrete step-based curve using pre-computed lookup tables. This ensures deterministic, consistent pricing across all clients (Solana program, backend, iOS, Android).

Motivation

The Rust flipcash-program migrated to a discrete bonding curve to ensure exact consistency across all platforms. The continuous exponential curve had potential for floating-point drift between different implementations. The discrete curve:

  • Uses pre-computed lookup tables (no runtime exp/ln calculations)
  • Guarantees bit-for-bit identical results across all clients
  • Provides O(1) price lookups and O(log n) binary search for conversions
  • Step size: 100 tokens per step
  • Table precision: 18 decimals (matching Rust u128)

Changes

New Files

File Description
DiscreteBondingCurve.swift New discrete curve implementation (~710 lines)
discrete_pricing_table.bin Pre-computed spot prices (3.4 MB, 210,001 entries)
discrete_cumulative_table.bin Pre-computed cumulative costs (3.4 MB, 210,001 entries)
DiscreteBondingCurveTests.swift Comprehensive test suite (1,489 lines, 101+ tests)
generate_curve_tables.py Script to generate binary tables from Rust source

Modified Files

File Change
ExchangedFiat.swift Migrated to use DiscreteBondingCurve for all token calculations
StoredBalance.swift Updated USDC value calculation to use discrete curve
CurrencyInfoScreen.swift Updated market cap display to use discrete curve
GiveViewModel.swift Minor cleanup
BondingCurve.swift Marked as @available(*, deprecated)
Package.swift Added resource declarations for binary tables

Key Implementation Details

UInt128 Custom Type

Swift doesn't have native UInt128, so we implemented a custom struct with:

  • High/low UInt64 parts matching Rust's u128 storage format
  • String-based initializer with decimal long division for numbers > 2^64
  • Proper comparison operators for binary search

Binary Resource Storage

Tables stored as binary files loaded at runtime to avoid Swift compiler memory issues. The original approach of embedding tables as Swift array literals caused 100GB+ memory usage during compilation.

API Methods

  // Core methods
  func spotPrice(at supply: Int) -> BigDecimal?
  func tokensToValue(currentSupply: Int, tokens: Int) -> BigDecimal?
  func valueToTokens(currentSupply: Int, value: BigDecimal) -> BigDecimal?
  // High-level API  
  func marketCap(for supplyQuarks: Int) -> BigDecimal?
  func buy(usdcQuarks: Int, feeBps: Int, tvl: Int) -> BuyEstimation?
  func sell(quarks: Int, feeBps: Int, tvl: Int) -> SellEstimation?
  // New method for fiat → tokens conversion
  func tokensForValueExchange(fiat: BigDecimal, fiatRate: BigDecimal, tvl: Int) -> Valuation?

Test Coverage

101+ tests across 14 suites:

Suite Tests
Spot Price 8
Tokens To Value 17
Value To Tokens 14
Roundtrip & Consistency 7
Table Validation 9
High-Level API 10
Edge Cases 7
Tokens For Value Exchange 12
Constants 6
ExchangedFiat Tests 3
Real-World Scenarios 11

@dbart01 dbart01 requested review from bmc08gt and jeffyanta December 9, 2025 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants