home / skills / multiversx / mx-ai-skills / mvx_defi_math

mvx_defi_math skill

/antigravity/skills/mvx_defi_math

This skill enables precise DeFi math on MultiversX by applying half-up rounding, safe rescaling, and robust percentage calculations for accurate results.

npx playbooks add skill multiversx/mx-ai-skills --skill mvx_defi_math

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
3.6 KB
---
name: mvx_defi_math
description: Financial math for MultiversX DeFi — precision management, half-up rounding, safe rescaling, percentage calculations.
---

# MultiversX DeFi Math Patterns

## Precision Levels

| Level | Decimals | When to Use |
|---|---|---|
| BPS (4) | 10,000 = 100% | Fees, simple percentages |
| PPM (6) | 1,000,000 = 100% | Fine-grained percentages |
| WAD (18) | 1e18 = 1.0 | Token amounts, prices |
| RAY (27) | 1e27 = 1.0 | Interest indices, compounding, high-precision math |

```rust
pub const BPS: u64 = 10_000;
pub const PPM: u64 = 1_000_000;
pub const WAD: u128 = 1_000_000_000_000_000_000;
pub const RAY: u128 = 1_000_000_000_000_000_000_000_000_000;
```

**Rule**: Use lowest precision that avoids rounding errors. Intermediate calculations at higher precision than final result.

## Half-Up Rounding

Standard ManagedDecimal truncates → systematic value loss → exploitable.

### Multiplication
```rust
fn mul_half_up(&self, a: &ManagedDecimal<Self::Api, NumDecimals>, b: &ManagedDecimal<Self::Api, NumDecimals>, precision: NumDecimals) -> ManagedDecimal<Self::Api, NumDecimals> {
    let product = a.rescale(precision).into_raw_units() * b.rescale(precision).into_raw_units();
    let scaled = BigUint::from(10u64).pow(precision as u32);
    let rounded = (product + &scaled / 2u64) / scaled;
    self.to_decimal(rounded, precision)
}
```

### Division
```rust
fn div_half_up(&self, a: &ManagedDecimal<Self::Api, NumDecimals>, b: &ManagedDecimal<Self::Api, NumDecimals>, precision: NumDecimals) -> ManagedDecimal<Self::Api, NumDecimals> {
    let scaled = BigUint::from(10u64).pow(precision as u32);
    let numerator = a.rescale(precision).into_raw_units() * &scaled;
    let denominator = b.rescale(precision).into_raw_units();
    let rounded = (numerator + &denominator / 2u64) / denominator;
    self.to_decimal(rounded, precision)
}
```

## Safe Rescaling

```rust
fn rescale_half_up(&self, value: &ManagedDecimal<Self::Api, NumDecimals>, new_precision: NumDecimals) -> ManagedDecimal<Self::Api, NumDecimals> {
    let old = value.scale();
    if new_precision >= old { return value.rescale(new_precision); }
    let factor = BigUint::from(10u64).pow((old - new_precision) as u32);
    ManagedDecimal::from_raw_units((value.into_raw_units() + &factor / 2u64) / factor, new_precision)
}
```

## Percentage Calculations

### Framework Built-in: `proportion()`

```rust
// Preferred — uses BigUint::proportion(part, total) from the framework
pub const PERCENT_BASE_POINTS: u64 = 100_000;  // 100% = 100_000
let fee = amount.proportion(fee_percent, PERCENT_BASE_POINTS);
```

### Manual BPS / PPM

```rust
pub fn apply_bps(amount: &BigUint, bps: u64) -> BigUint { (amount * bps) / 10_000u64 }
pub fn apply_ppm(amount: &BigUint, ppm: u32) -> BigUint { (amount * ppm) / 1_000_000u64 }
```

## Rounding Attack Vectors

| Attack | Mitigation |
|---|---|
| Dust deposits to steal rounding | Half-up rounding on scaled amounts |
| Repeated small operations | Minimum amounts + half-up on indices |
| Precision loss across conversions | RAY for intermediate math |
| Truncation in fee calculations | Round fees UP (protocol's favor) |

## Anti-Patterns

- Mixing precisions without rescaling
- Truncating division for fees (use ceiling division)
- Intermediate results at low precision (compute at RAY, downscale at end)

## Domain Applications

- **Lending**: Interest models, compound interest, utilization — RAY precision
- **DEX**: Price impact, LP shares — WAD with half-up
- **Staking**: Reward distribution, share ratios — RAY indices
- **Vaults**: Fee calculations, yield — BPS fees with ceiling division

Overview

This skill provides practical financial-math patterns for MultiversX DeFi, focused on precision management, safe rescaling, and predictable rounding. It codifies recommended decimal levels (BPS, PPM, WAD, RAY), half-up rounding for arithmetic, and safe percentage helpers to avoid truncation losses and rounding attacks. The goal is reliable on-chain arithmetic that preserves value and reduces exploit risk.

How this skill works

It inspects numeric operations and prescribes using the lowest precision that still prevents rounding errors, while performing intermediate calculations at higher precision (RAY) when needed. Multiplication, division, and rescaling use half-up rounding on scaled integers to avoid systematic truncation. Percentage helpers use built-in proportion utilities or explicit BPS/PPM formulas, and fee logic favors rounding that protects the protocol against dust attacks.

When to use it

  • Use BPS (4 decimals) for simple fees and coarse percentages.
  • Use PPM (6 decimals) for finer-grained percentage parameters.
  • Use WAD (18 decimals) for token amounts and price arithmetic.
  • Use RAY (27 decimals) for interest indices, compounding, and intermediate math.
  • Apply half-up rounding when multiplying/dividing scaled integers or downscaling precision.

Best practices

  • Always rescale explicitly before mixing numbers of different precisions; avoid implicit mixing.
  • Compute intermediate results at RAY precision for stability, then downscale with half-up rounding.
  • Use framework proportion helpers when available; fallback to BPS/PPM formulas with safe rounding.
  • Round fees in favor of the protocol (ceiling for fees) and apply minimum amounts to deter dust attacks.
  • Avoid repeated low-precision operations; accumulate at high precision and finalize once.

Example use cases

  • Lending: calculate interest indices and compounded balances at RAY precision to prevent accrual drift.
  • DEX: compute prices and LP shares in WAD and rescale with half-up to avoid systematic slippage.
  • Staking: maintain reward indices and share ratios using RAY to preserve tiny rewards across epochs.
  • Vaults: apply BPS-based fees with ceiling or half-up rounding to ensure protocol capture of fee dust.
  • Fee modules: use proportion() helpers or apply_bps/apply_ppm patterns to compute fee transfers safely.

FAQ

Why use half-up instead of truncation?

Half-up prevents systematic downward bias from repeated truncation, reducing exploitable dust accumulation.

When should I use RAY versus WAD?

Use RAY for indices and compounding where tiny errors compound; use WAD for token amounts and price arithmetic where 18 decimals suffice.