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 fullu128
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(×tamp).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)
represents1.0
. - Maximum Value: The largest value that can be represented by
Decimal
is approximately340282366920938463463.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
- 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. - Leverage Decimal for Precision: Use
Decimal
for any calculations involving fractions, percentages, or ratios to maintain precision and avoid rounding errors. - Avoid Floating-Point Arithmetic: Stick to
Uint128
,Uint64
, andDecimal
for all arithmetic operations to ensure deterministic and accurate results, as floating-point arithmetic can introduce subtle bugs due to rounding issues. - 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
andDecimal
types.