Skip to content

#99 Medium: Precision Loss in Share Price Calculations#126

Open
coder45oj wants to merge 3 commits into
TrusTrove:mainfrom
coder45oj:issue-99-precision-loss
Open

#99 Medium: Precision Loss in Share Price Calculations#126
coder45oj wants to merge 3 commits into
TrusTrove:mainfrom
coder45oj:issue-99-precision-loss

Conversation

@coder45oj

Copy link
Copy Markdown
Contributor

Description

Fixes precision loss in share price calculations by applying ceiling rounding on withdrawal, minimizing value leakage for liquidity providers. The deposit side remains floor rounding (conservative, benefits existing LPs).

Problem

Two integer division calculations cause silent value loss for LPs due to floor rounding:

  1. Deposit (contracts/pool/src/lib.rs:130): usdc_amount * total_shares / total_deposits — LP receives slightly fewer shares than their deposit entitles them to.
  2. Withdraw (contracts/pool/src/lib.rs:221): shares * total_deposits / total_shares — LP receives slightly less USDC than their shares are worth.

While each individual loss is tiny (often 1 unit), these accumulate over time across all LPs, creating systemic leakage.

Fix

Implemented ceiling division for the withdrawal calculation at contracts/pool/src/lib.rs:208-221:

let product = shares.checked_mul(total_deposits)?;
let floor = product.checked_div(total_shares)?;
let remainder = product % total_shares;
let usdc_to_return = if remainder > 0 {
    floor.checked_add(1)?   // ceiling when fractional
} else {
    floor                   // exact division, unchanged
};

This ensures that when the mathematical value of shares is not an integer number of USDC units, the withdrawing LP receives the ceiling (rounded up) instead of the floor, recovering value that would otherwise be lost.

Example

  1. LP1 deposits 10B USDC → 10B shares
  2. Pool generates 200M yield → share price = 1.02
  3. LP2 deposits 1000 USDC → gets floor(1000 × 10B / 10.2B) = 980 shares (0.39 share lost)
  4. LP2 withdraws 980 shares:
    • Before (floor): floor(980 × 10.2B / 10B) = 999 USDC ← 1 USDC loss
    • After (ceiling): ceil(980 × 10.2B / 10B) = 1000 USDC ← no loss

Precision Tests

Added 5 tests in contracts/pool/src/test.rs:

  • test_precision_withdraw_ceil_recovers_value — single deposit + withdraw after yield, verifies full deposit recovered via ceiling
  • test_precision_ceiling_gt_floor_when_remainder — dynamically confirms ceiling = floor + 1 when remainder exists
  • test_precision_exact_division_unchanged — exact divisions unaffected
  • test_precision_dust_share_gets_1_usdc — dust shares return ≥ 1 USDC instead of 0
  • test_precision_multiple_withdrawals_accumulate — partial withdrawals each benefit from ceiling

Closes #99

…on withdrawal

Problem: Integer floor division in withdraw() silently loses value for LPs.
- Deposit: usdc_amount * total_shares / total_deposits (floor → LP gets fewer shares)
- Withdraw: shares * total_deposits / total_shares (floor → LP gets less USDC)

Fix: Use ceiling division for withdrawal calculations so that remaining
fractional value is returned to the withdrawing LP instead of being lost.
- Deposit stays as floor (conservative, benefits existing LPs)
- Withdraw uses ceiling: (product + total_shares - 1) / total_shares,
  implemented as floor + 1 when remainder > 0 to avoid overflow edge cases

Tests added:
- test_precision_withdraw_ceil_recovers_value: single deposit+withdraw after
  yield recovers 1000 USDC vs 999 with floor
- test_precision_ceiling_gt_floor_when_remainder: dynamically verifies
  ceiling == floor + 1 when remainder exists
- test_precision_exact_division_unchanged: exact division unchanged
- test_precision_dust_share_gets_1_usdc: dust shares return >= 1 USDC
- test_precision_multiple_withdrawals_accumulate: partial withdrawals each
  benefit from ceiling rounding

Closes TrusTrove#99
@drips-wave

drips-wave Bot commented Jun 29, 2026

Copy link
Copy Markdown

@coder45oj Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@K1NGD4VID

K1NGD4VID commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Fix Ci error @coder45oj

coder45oj and others added 2 commits June 29, 2026 16:05
)

Re-wrap three long assert!/assert_eq! statements in precision-rounding tests:
- test_precision_withdraw_ceil_recovers_value: assert_eq! with full deposit message
- test_precision_dust_share_gets_1_usdc: assert! for dust share return >= 1
- test_precision_multiple_withdrawals_accumulate: two ceiling-rounding asserts

Resolves cargo fmt --all --check failure on the issue-99-precision-loss branch.
@K1NGD4VID

Copy link
Copy Markdown
Contributor

resolve Conflict @coder45oj

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Medium: Precision Loss in Share Price Calculations

2 participants