The Precision Challenge

Cosmos SDK and Ethereum use different decimal precisions for their native tokens:
  • Cosmos SDK: 6 decimals (1 ATOM = 10^6 uatom)
  • Ethereum: 18 decimals (1 ETH = 10^18 wei)
This 12-decimal difference creates challenges when bridging the two ecosystems. Simply scaling values would lose precision or create rounding errors.

Mathematical Foundation

Balance Representation

Any account balance can be decomposed into integer and fractional components:
Total Balance = Integer Part × Conversion Factor + Fractional Part
For an account with balance a(n) in smallest units (18 decimals):
a(n) = b(n) × C + f(n)
Where:
  • a(n) = Total balance in 18-decimal units (aatom)
  • b(n) = Integer balance in 6-decimal units (uatom)
  • f(n) = Fractional balance (remainder)
  • C = Conversion factor (10^12)
  • Constraint: 0 ≤ f(n) < C

Example Decomposition

Consider a balance of 1,234,567,890,123,456,789 aatom:
1,234,567,890,123,456,789 = 1,234,567 × 10^12 + 890,123,456,789

Where:
- b(n) = 1,234,567 uatom (stored in bank)
- f(n) = 890,123,456,789 aatom (stored in precisebank)
- Total = 1.234567890123456789 ATOM

The Reserve Account

To maintain supply consistency, a reserve account holds backing for all fractional balances:

Reserve Equation

Reserve Balance × C = Sum of All Fractional Balances + Remainder
Formally:
b(R) × C = Σf(n) + r
Where:
  • b(R) = Reserve balance in uatom
  • Σf(n) = Sum of all account fractional balances
  • r = Remainder (fractional amount not in circulation)
  • Constraint: 0 ≤ r < C

Supply Invariant

This ensures the fundamental invariant:
Total_aatom = Total_uatom × 10^12 - remainder
The remainder represents sub-uatom amounts that exist in the system but aren’t assigned to any specific account.

Operation Algorithms

Transfer Algorithm

Transferring between accounts requires careful handling of carries and borrows: From account 1 to account 2, amount a:
  1. Calculate new fractional balances:
    f'(1) = (f(1) - a) mod C
    f'(2) = (f(2) + a) mod C
    
  2. Handle integer updates with carry/borrow:
    b'(1) = b(1) - ⌊a/C⌋ - (f'(1) > f(1) ? 1 : 0)
    b'(2) = b(2) + ⌊a/C⌋ + (f'(2) < f(2) ? 1 : 0)
    
  3. Update reserve based on carry conditions:
    • Both carry/borrow: No reserve change
    • Only sender borrows: Reserve decreases by 1
    • Only receiver carries: Reserve increases by 1

Mint Algorithm

Creating new tokens while maintaining backing:
  1. Update account:
    f'(n) = (f(n) + a) mod C
    b'(n) = b(n) + ⌊a/C⌋ + (f'(n) < f(n) ? 1 : 0)
    
  2. Update remainder:
    r' = (r - a) mod C
    
  3. Adjust reserve for consistency

Burn Algorithm

Removing tokens from circulation:
  1. Update account:
    f'(n) = (f(n) - a) mod C
    b'(n) = b(n) - ⌊a/C⌋ - (f'(n) > f(n) ? 1 : 0)
    
  2. Update remainder:
    r' = (r + a) mod C
    
  3. Adjust reserve for consistency

Proof: Remainder Unchanged in Transfers

A critical property is that transfers don’t change the global remainder: Proof:
  1. Start with transfer affecting fractional balances
  2. Take modulo C of the balance equation
  3. Since reserve changes are multiples of C, they vanish mod C
  4. Fractional changes sum to zero (amount subtracted equals amount added)
  5. Therefore: r' = r
This elegant property means transfers are purely redistributive - they don’t create or destroy fractional amounts.

Precision Hierarchy

The system manages three precision levels:
UnitPrecisionDecimalsUsage
ATOM10^00Human display
uatom10^-66Cosmos native
aatom10^-1818EVM native

Conversion Examples

1 ATOM = 1,000,000 uatom = 1,000,000,000,000,000,000 aatom
0.000001 ATOM = 1 uatom = 1,000,000,000,000 aatom
0.000000000000000001 ATOM = 0.000000000001 uatom = 1 aatom

Edge Cases and Limits

Minimum Transferable Amount

  • In Cosmos: 1 uatom (0.000001 ATOM)
  • In EVM: 1 aatom (0.000000000000000001 ATOM)

Maximum Precision

  • Cosmos operations: Limited to uatom granularity
  • EVM operations: Full aatom precision
  • Cross-system: Automatic precision handling

Dust Amounts

Amounts smaller than 1 uatom but larger than 0 aatom:
  • Tracked in fractional balances
  • Accumulate until reaching 1 uatom
  • Never lost or rounded away

Implementation Strategy

Storage Optimization

Rather than storing 18-decimal balances directly:
  1. Store 6-decimal amounts in existing bank module
  2. Store only the fractional remainder separately
  3. Reconstruct full precision on demand
This approach:
  • Maintains backward compatibility
  • Minimizes storage overhead
  • Preserves full precision

Query Performance

When querying balances:
fullBalance = bankBalance * 10^12 + fractionalBalance
This single multiplication and addition reconstructs the full 18-decimal balance efficiently.

Why This Matters

For Users

  • No precision loss: Every aatom is accounted for
  • Seamless experience: Automatic handling across systems
  • Fair transactions: No rounding advantages or disadvantages

For Developers

  • Standard interfaces: Use familiar decimals for each system
  • Automatic conversion: No manual precision management
  • Predictable behavior: Mathematical guarantees on operations

For the Ecosystem

  • True interoperability: Native precision for both ecosystems
  • Future proof: Extensible to other precision requirements
  • Efficient design: Minimal overhead for maximum capability

Comparison with Alternatives

Simple Scaling

// Naive approach - loses precision
evmAmount = cosmosAmount * 10^12
Problems: Loses sub-uatom amounts, rounding errors accumulate

Fixed-Point Arithmetic

// Complex fixed-point math
amount = FixedPoint{mantissa: 123456, exponent: -18}
Problems: Complex implementation, performance overhead, compatibility issues

Separate Balances

// Maintain two separate balance systems
cosmosBalance: 1000000 uatom
evmBalance: 1000000000000000000 aatom
Problems: Synchronization issues, double accounting, complexity

PreciseBank Solution

// Elegant decomposition
totalBalance = integerPart * 10^12 + fractionalPart
Advantages: Simple, efficient, precise, compatible

Future Extensions

Multi-Precision Support

The mathematical framework extends to any precision:
  • 8 decimals for certain tokens
  • 27 decimals for high-precision applications
  • Variable precision based on token type

Cross-Chain Precision

Standardized precision handling for:
  • IBC transfers with different precisions
  • Bridge protocols with varying decimals
  • Universal precision abstraction layer