This site requires Javascript to be enabled.

Math

In CosmWasm, mathematical operations are crucial for handling token amounts, balances, and other numerical data within smart contracts. While these operations are based on standard Rust math, CosmWasm provides specialized helper functions and types to manage large integers and fixed-point decimals effectively. These helpers are particularly important for ensuring precision and accuracy in financial calculations and when interacting with clients that process JSON numbers as floats, such as JavaScript.

Uint128

Uint128 is a lightweight wrapper around Rust's u128 type, designed for safe and efficient handling of 128-bit unsigned integers. This type is particularly useful when dealing with large token balances and other big integers in smart contracts.

  • String-Based JSON Encoding/Decoding: To ensure compatibility with JSON parsers that treat numbers as floating-point values (which can lose precision for large integers), Uint128 uses string-based encoding and decoding. This approach preserves the full u128 range when interacting with JSON-based clients, such as JavaScript applications.

Example usage

use cosmwasm_std::Uint128;let amount = Uint128::from(1_000_000_000u128);let json = serde_json::to_string(&amount).unwrap();assert_eq!(json, "\"1000000000\"");  // Encoded as a string for JSONlet parsed: Uint128 = serde_json::from_str(&json).unwrap();assert_eq!(parsed, amount);

This example demonstrates how Uint128 ensures that large values are safely encoded and decoded as strings in JSON, avoiding precision issues that can arise with floating-point representations.

Uint64

Uint64 is a thin wrapper around Rust's u64 type, following the same principles as Uint128 but tailored for 64-bit unsigned integers. This type is ideal for scenarios where you need to manage smaller but still substantial numbers, such as timestamps, IDs, or smaller balances.

  • String-Based JSON Encoding/Decoding: Similar to Uint128, Uint64 uses string-based encoding to maintain accuracy when interacting with JSON parsers that convert numbers to floats.

Example usage

use cosmwasm_std::Uint64;let timestamp = Uint64::from(1_620_000_000u64);let json = serde_json::to_string(&timestamp).unwrap();assert_eq!(json, "\"1620000000\"");  // Encoded as a string for JSONlet parsed: Uint64 = serde_json::from_str(&json).unwrap();assert_eq!(parsed, timestamp);

This ensures that Uint64 values are correctly handled in environments where JSON numbers might otherwise be truncated or rounded.

Decimal

Decimal is a fixed-point decimal type that provides precise arithmetic for numbers with up to 18 fractional digits. This is essential for financial calculations where precision is critical, such as calculating interest rates, token exchange rates, or handling fractional token amounts.

  • 18 Fractional Digits: Decimal represents values as integers internally, with 18 digits allocated for the fractional part. For example, Decimal(1_000_000_000_000_000_000) represents 1.0.
  • Maximum Value: The largest value that can be represented by Decimal is approximately 340282366920938463463.374607431768211455, which is derived from (2^128 - 1) / 10^18.

Example usage

use cosmwasm_std::Decimal;let rate = Decimal::percent(150); // 1.5 or 150%let amount = Uint128::from(1000u128);let interest = rate * Decimal::from_ratio(amount, Uint128::from(1u128));assert_eq!(interest.to_string(), "15.0");  // Calculates 1.5% of 1000

This example shows how Decimal can be used for precise calculations involving percentages and other fractional values, making it an essential tool for financial logic in smart contracts.

Best practices for using math types in CosmWasm

  1. Use Uint128 for Large Values: When dealing with token amounts or other large numerical values, prefer Uint128 to avoid potential overflows and ensure compatibility with JSON-based clients.
  2. Leverage Decimal for Precision: Use Decimal for any calculations involving fractions, percentages, or ratios to maintain precision and avoid rounding errors.
  3. Avoid Floating-Point Arithmetic: Stick to Uint128, Uint64, and Decimal for all arithmetic operations to ensure deterministic and accurate results, as floating-point arithmetic can introduce subtle bugs due to rounding issues.
  4. Always Test for Edge Cases: Include unit tests that cover edge cases, such as very large values, very small fractions, and operations near the limits of u128 and Decimal types.