Skip to content
🌐Network: Mainnet

Math Utilities

Every price and quantity must be scaled up and truncated to respect precision constraints. This section covers the critical math utilities needed for your trading agent.

Why Fixed Point Precision Matters

  • No floats: 2500.50 becomes 2500500000000 (scaled by 10^9)
  • Limited precision: Only 4-5 significant digits allowed

Without proper scaling, your orders will be rejected.

Create Math Utilities

These utilities handle the critical conversion between human-readable decimal values and blockchain-compatible fixed-point integers.

Create the math utilities file:

bash
touch src/utils/numbers.ts

Add the following content to src/utils/numbers.ts:

typescript
import Decimal from 'decimal.js';

/**
 * Scales up a Decimal by a given number of decimals and truncates it
 * according to the maximum precision.
 *
 * @param amount - The Decimal to scale and truncate.
 * @param decimals - The total number of decimals for the asset.
 * @param maxPrecision - The maximum allowed precision.
 * @returns A Decimal instance representing the scaled and truncated value.
 */
export function scaleUpAndTruncateToInt(amount: Decimal, decimals: number, maxPrecision: number): Decimal {
  const priceInt = amount.mul(new Decimal(10).pow(decimals));
  const truncateFactor = new Decimal(10).pow(decimals - maxPrecision);
  return priceInt.div(truncateFactor).floor().mul(truncateFactor);
}

/**
 * Calculates the order quantity respecting the base asset's max_precision and scaling up decimals. We will assume that the quantityInQuote and the price are not scaled up.
 *
 * @param quantityInQuote - The order value in the quote asset in Decimal. Should not be scaled up.
 * @param price - The price of the asset in Decimal. Should not be scaled up.
 * @param baseDecimals - The number of decimals for the base asset.
 * @param baseMaxPrecision - The maximum allowed precision for the base asset.
 * @returns A scaled up base quantity respecting the max precision as Decimal
 */
export function calculateBaseQuantity(
  quantityInQuote: Decimal,
  price: Decimal,
  baseDecimals: number,
  baseMaxPrecision: number
): Decimal {
  // Calculate the quantity in the base asset.
  const quantityInBase = quantityInQuote.div(price);

  // Scale up the base quantity.
  let scaledQuantity = quantityInBase.mul(new Decimal(10).pow(baseDecimals));

  // Truncate the scaled quantity to the allowed max_precision of the base asset.
  const truncateFactor = new Decimal(10).pow(baseDecimals - baseMaxPrecision);
  return scaledQuantity.div(truncateFactor).ceil().mul(truncateFactor);
}

Understanding Scaling

Scaling converts human-readable decimals to blockchain integers while respecting precision limits. This is essential because blockchain contracts don't support floating-point numbers.

Example 1: Price Scaling

This example shows how to convert a price like $2,500.50 to a blockchain-compatible integer.

typescript
// Market: ETH/USDC
// Price: $2,500.50
// Quote decimals: 9
// Quote max_precision: 4

const price = new Decimal(2500.50);
const decimals = 9;
const maxPrecision = 4;

// Step 1: Scale up by multiplying by 10^9
// This converts the decimal price to an integer representation
const scaled = price.mul(new Decimal(10).pow(decimals));
// 2500.50 * 10^9 = 2500500000000

// Step 2: Calculate truncation factor
// We can only keep 4 significant digits, so we need to truncate
const truncateFactor = new Decimal(10).pow(decimals - maxPrecision);
// 10^(9-4) = 10^5 = 100000

// Step 3: Truncate to precision limit
// Divide by truncation factor, floor, then multiply back
const truncated = scaled.div(truncateFactor).floor().mul(truncateFactor);
// floor(2500500000000 / 100000) * 100000
// floor(25005000) * 100000
// 25005000 * 100000
// 2500500000000

// Final result: "2500500000000"
// This represents $2500.50 as a blockchain-compatible integer

Example 2: Quantity Calculation

This example shows how to calculate the order quantity when you know the dollar value you want to trade.

typescript
// Order: $10 worth of ETH
// Price: $2,500/ETH
// Base decimals: 9
// Base max_precision: 5

const orderValue = new Decimal(10);  // $10 order size
const price = new Decimal(2500);     // Current ETH price
const baseDecimals = 9;
const baseMaxPrecision = 5;

// Step 1: Calculate quantity in base asset (ETH)
// How much ETH can we buy with $10?
const quantity = orderValue.div(price);
// $10 / $2500 = 0.004 ETH

// Step 2: Scale up to blockchain integer
const scaled = quantity.mul(new Decimal(10).pow(baseDecimals));
// 0.004 * 10^9 = 4000000

// Step 3: Truncate to precision limit
// We can only keep 5 significant digits for ETH
const truncateFactor = new Decimal(10).pow(baseDecimals - baseMaxPrecision);
// 10^(9-5) = 10^4 = 10000

// Use ceil() instead of floor() to ensure we don't round to zero
const final = scaled.div(truncateFactor).ceil().mul(truncateFactor);
// ceil(4000000 / 10000) * 10000
// ceil(400) * 10000
// 400 * 10000
// 4000000

// Final result: "4000000" (0.004 ETH scaled as blockchain integer)

Precision Reference

Common asset configurations on o2:

AssetDecimalsMax PrecisionExample Scaled Value
ETH951.23456 → 1234500000
USDC942500.50 → 2500500000000
FUEL950.08425 → 84250000