Skip to content

Commit a8a5840

Browse files
committed
pow
1 parent cb8a089 commit a8a5840

1 file changed

Lines changed: 34 additions & 8 deletions

File tree

  • content/stellar-contracts/utils/math

content/stellar-contracts/utils/math/wad.mdx

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,32 @@ impl Div for Wad {
178178
}
179179
```
180180

181+
## Exponentiation
182+
183+
WAD supports raising a value to an **unsigned integer exponent** via `pow`.
184+
185+
- `pow(&e, exponent)` is optimized using **exponentiation by squaring** (O(log n) multiplications).
186+
- Each multiplication keeps WAD semantics (fixed-point multiplication and truncation toward zero).
187+
- Overflow is reported via Soroban errors.
188+
189+
In addition to `pow`, WAD also provides `checked_pow`, which returns `None` on overflow.
190+
191+
```rust
192+
// Compound interest multiplier: (1.05)^10
193+
let rate = Wad::from_ratio(&e, 105, 100); // 1.05
194+
let multiplier = rate.pow(&e, 10);
195+
```
196+
197+
### Notes on `pow` and Phantom Overflow
198+
199+
`pow` / `checked_pow` are implemented using exponentiation by squaring and rely
200+
on Soroban fixed-point helpers that can automatically scale intermediate products
201+
to `I256` when needed.
202+
203+
This avoids **phantom overflow** cases where an intermediate multiplication would
204+
overflow `i128`, but the final scaled result would still fit in `i128`.
205+
206+
181207
## Token Conversions
182208

183209
Different tokens have different decimal places (USDC: 6, ETH: 18, BTC: 8). WAD handles these conversions:
@@ -305,7 +331,7 @@ fn safe_multiply(e: &Env, a: i128, b: i128) -> Result<i128, Error> {
305331

306332
// Use checked variant
307333
let result_wad = a_wad
308-
.checked_mul(b_wad)
334+
.checked_mul(e, b_wad)
309335
.ok_or(Error::Overflow)?;
310336

311337
Ok(result_wad.to_token_amount(e, 6))
@@ -351,10 +377,11 @@ fn safe_multiply(e: &Env, a: i128, b: i128) -> Result<i128, Error> {
351377
|--------|---------|-------------|
352378
| `checked_add(rhs)` | `Option<Wad>` | Addition with overflow check |
353379
| `checked_sub(rhs)` | `Option<Wad>` | Subtraction with overflow check |
354-
| `checked_mul(rhs)` | `Option<Wad>` | Multiplication with overflow check |
380+
| `checked_mul(e, rhs)` | `Option<Wad>` | Multiplication with overflow check (handles phantom overflow internally) |
355381
| `checked_div(rhs)` | `Option<Wad>` | Division with overflow/zero check |
356382
| `checked_mul_int(n)` | `Option<Wad>` | Integer multiplication with overflow check |
357383
| `checked_div_int(n)` | `Option<Wad>` | Integer division with zero check |
384+
| `checked_pow(e, exponent)` | `Option<Wad>` | Exponentiation with overflow check |
358385

359386
## Utility Methods
360387

@@ -363,16 +390,15 @@ fn safe_multiply(e: &Env, a: i128, b: i128) -> Result<i128, Error> {
363390
| `abs()` | Absolute value |
364391
| `min(other)` | Minimum of two values |
365392
| `max(other)` | Maximum of two values |
393+
| `pow(e, exponent)` | Raises WAD to an unsigned integer power (panics with Soroban error on overflow) |
366394

367395
## Error Handling
368396

369-
WAD uses Soroban's contract error system:
397+
WAD uses Soroban's contract error system via `SorobanFixedPointError`:
370398

371399
```rust
372-
#[contracterror]
373-
pub enum WadError {
374-
Overflow = 1600, // Arithmetic overflow
375-
DivisionByZero = 1601, // Division by zero
376-
InvalidDecimals = 1602, // Invalid decimal conversion
400+
pub enum SorobanFixedPointError {
401+
Overflow = 1500,
402+
DivisionByZero = 1501,
377403
}
378404
```

0 commit comments

Comments
 (0)