Skip to content

feat(contracts): rounding direction protection for fractional asset math - #616

Merged
github-actions[bot] merged 1 commit into
Sahara-Pay:mainfrom
godwinishaku506-hub:feat/rounding-direction-protection
Aug 19, 2026
Merged

feat(contracts): rounding direction protection for fractional asset math#616
github-actions[bot] merged 1 commit into
Sahara-Pay:mainfrom
godwinishaku506-hub:feat/rounding-direction-protection

Conversation

@godwinishaku506-hub

@godwinishaku506-hub godwinishaku506-hub commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements on-chain rounding direction protection for secure and deterministic fractional asset management in the Soroban smart contract, as required by the Wave 4 grant specification.

New module: src/rounding.rs

  • RoundingDirection enumFloor / Ceiling / Truncate variants. Every division that touches token amounts now carries an auditable, grep-able rounding intent at the call site.
  • safe_div(env, n, d, direction) — checked integer division handling all four sign combinations correctly; panics with PrinceError::RoundingOverflow on zero denominator or arithmetic overflow.
  • safe_mul_div(env, a, b, d, direction) — fused multiply-then-divide over i128 checked arithmetic, preventing overflow at Stellar-scale pool sizes (~5×10¹⁷ stroops).
  • dust_remainder(env, pool, distributed) — explicit helper so undistributed dust is carried forward rather than silently lost.

11 proptest invariants (2000 cases each)

# Invariant
1 Floor never exceeds exact value (floor * d ≤ n)
2 Ceiling never undercounts (ceil * d ≥ n)
3 Floor ≤ Truncate ≤ Ceiling for positive inputs
4 Exact division — all three modes agree
5 Ceiling − Floor gap is at most 1
6 safe_mul_div Floor never over-allocates
7 Sum of N floored allocations never exceeds pool
8 Monotonicity in numerator
9 No panic for any non-zero denominator (adversarial i128::ANY inputs)
10 Commutativity of a × b / d
11 Dust is always < number of projects

Integration

QF distribution (qf_preview_distribution): replaced raw pool * weight / total_weight integer division with safe_mul_div(..., RoundingDirection::Floor). Undistributed dust is now explicitly tracked via dust_remainder and carried forward to the next round in qf_distribute.

Pre-existing bug fixes (required for compilation)

The repository had a broken Cargo.lock (git merge conflict markers) that prevented any build. Fixed alongside the following compile errors:

  • Removed 4 duplicate PrinceError discriminants (values 41/42/43 appeared twice each)
  • Removed duplicate DataKey::Vault enum variant
  • Fixed unclosed delimiter in flash_loan event publish call
  • Fixed get_token(&env)get_token(env.clone()) type errors in create_vault / claim_vault
  • Replaced undefined get_org_admin_requirement call in register_bls_signer
  • bls_verifier.rs: updated to bls12_381_plus 0.8.x API
  • token_interface.rs: sac_burn switched from StellarAssetClient to TokenClient
  • Cargo.lock: resolved merge conflict markers; regenerated clean lockfile

Verification

cargo check → 0 errors, 4 pre-existing dead-code warnings (unrelated files)

Note: the test runner has a pre-existing transitive rand_core version conflict in soroban-env-host v22.1.3 that prevents cargo test from building; this exists in the repo independently of this PR.

closes #511

…et math

Implements on-chain rounding direction protection as required for secure
and deterministic fractional asset management in the Soroban contract.

## New module: src/rounding.rs

- RoundingDirection enum with Floor / Ceiling / Truncate variants; each
  call site now carries an auditable, grep-able rounding intent.
- safe_div(env, n, d, direction) — checked integer division that handles
  all four sign combinations correctly and panics with RoundingOverflow
  on zero denominator or arithmetic overflow.
- safe_mul_div(env, a, b, d, direction) — fused multiply-then-divide over
  i128 checked arithmetic; prevents overflow at Stellar-scale pool sizes.
- dust_remainder(env, pool, distributed) — explicit helper that returns
  undistributed dust so callers can carry it forward rather than losing it.

## 11 proptest invariants (2000 cases each)

1.  Floor never exceeds exact value (floor * d <= n)
2.  Ceiling never undercounts (ceil * d >= n)
3.  Floor <= Truncate <= Ceiling for positive inputs
4.  Exact division — all three modes agree
5.  Ceiling - Floor gap is at most 1
6.  safe_mul_div Floor never over-allocates
7.  Sum of N floored allocations never exceeds pool
8.  Monotonicity in numerator
9.  No panic for any non-zero denominator (adversarial i128::ANY inputs)
10. Commutativity of a * b / d
11. Dust is always < number of projects

## Integration into lib.rs

- QF distribution (qf_preview_distribution): replaced raw
  pool * weight / total_weight with safe_mul_div(..., Floor).
  Undistributed dust is now explicitly tracked via dust_remainder and
  carried forward to the next round in qf_distribute.

## Pre-existing bug fixes (required for compilation)

- Fixed 4 duplicate PrinceError discriminants (41/42/43 conflicts):
  FlashLoanRepaymentFailed -> 45, FlashLoanInsufficientLiquidity -> 46.
- Removed duplicate DataKey::Vault enum variant.
- Fixed unclosed delimiter in flash_loan event publish call.
- Fixed get_token(&env) -> get_token(env.clone()) in create_vault /
  claim_vault (mismatched type errors).
- Replaced undefined get_org_admin_requirement with inline org existence
  check in register_bls_signer.
- bls_verifier.rs: updated to bls12_381_plus 0.8.x API (G1Projective::hash,
  Gt::IDENTITY, G2Projective::IDENTITY, elliptic_curve::hash2curve::ExpandMsgXmd).
- token_interface.rs: sac_burn switched from StellarAssetClient (no burn
  method) to TokenClient.
- Cargo.lock: resolved merge conflict markers; regenerated clean lockfile.

cargo check: 0 errors, 4 pre-existing dead-code warnings (unrelated files).
@github-actions
github-actions Bot merged commit dac0f3d into Sahara-Pay:main Aug 19, 2026
2 checks passed
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.

Implement rounding direction protection for tokenized fractional assets

1 participant