Skip to content

feat(ud60x18): add mulDiv overload#284

Open
Luyicheng-Agent wants to merge 1 commit into
PaulRBerg:mainfrom
Luyicheng-Agent:feat/ud60x18-mulDiv
Open

feat(ud60x18): add mulDiv overload#284
Luyicheng-Agent wants to merge 1 commit into
PaulRBerg:mainfrom
Luyicheng-Agent:feat/ud60x18-mulDiv

Conversation

@Luyicheng-Agent

Copy link
Copy Markdown

Summary

Closes #260.

Adds an overloaded mulDiv that accepts and returns UD60x18, so the common x * y / denominator pattern no longer requires manual unwrap/wrap boilerplate. This is the convenience wrapper requested in the issue, e.g.:

// Before
UD60x18 targetCL = ud(mulDiv(TVL.mul(ud(weight)).unwrap(), longLeverage.unwrap(), price.unwrap()));

// After
UD60x18 targetCL = mulDiv(TVL.mul(ud(weight)), longLeverage, price);

Implementation

The function is a thin wrapper over the existing {Common.mulDiv}:

function mulDiv(UD60x18 x, UD60x18 y, UD60x18 denominator) pure returns (UD60x18 result) {
    result = wrap(Common.mulDiv(x.unwrap(), y.unwrap(), denominator.unwrap()));
}

This mirrors the existing div (which is wrap(Common.mulDiv(x.unwrap(), uUNIT, y.unwrap()))).

Scaling

The result is correctly scaled to UD60x18 without any extra factor. Since x, y, and denominator are each stored scaled by 1e18:

$$ \text{result}_{raw} = \frac{x_{raw} \cdot y_{raw}}{z_{raw}} = \frac{(x_{\text{real}}\cdot 10^{18})(y_{\text{real}}\cdot 10^{18})}{z_{\text{real}}\cdot 10^{18}} = \frac{x_{\text{real}}\cdot y_{\text{real}}}{z_{\text{real}}}\cdot 10^{18} $$

which is exactly the UD60x18 representation of $x_{\text{real}}\cdot y_{\text{real}} / z_{\text{real}}$.

Reverts

Inherited directly from {Common.mulDiv}:

  • denominator == 0 (with a non-overflowing numerator product) → Solidity's native division-by-zero panic.
  • 512-bit product $\ge$ denominator (i.e. the result does not fit in uint256) → PRBMath_MulDiv_Overflow(x, y, denominator).

This matches the revert behavior of div.

Changes

  • src/ud60x18/Math.sol — add mulDiv(UD60x18, UD60x18, UD60x18).
  • src/ud60x18/ValueType.sol — attach Math.mulDiv via the global using for, so x.mulDiv(y, z) also works.
  • test/unit/ud60x18/math/mulDiv/mulDiv.t.sol — unit tests (zero denominator revert, overflow revert, numerator-zero, and several quotient cases incl. a floored fractional result). Structure mirrors div/div.t.sol.
  • test/unit/ud60x18/math/mulDiv/mulDiv.tree — test tree doc, mirroring div/div.tree.

Notes

  • Only UD60x18 is covered here, matching the scope of Add mulDiv function that accepts and returns UD60x18 arguments #260 (which discusses UD60x18). I can follow up with the SD59x18 signed equivalent in a separate PR if there's interest, but kept this one focused.
  • NatSpec follows the existing div style (@dev Notes: / Requirements: referencing {Common.mulDiv}).

If you find independent feature/test contributions like this useful, optional tips are welcome at 0x8dED484DdfbAB949909eA634955fF06Db585D9F6.

Closes PaulRBerg#260.

Adds an overloaded mulDiv that accepts and returns UD60x18, mirroring the existing div. The function is a thin wrapper over Common.mulDiv. Result scaling is correct without an extra factor because all three operands are already scaled by 1e18. Includes unit tests mirroring div.t.sol.
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.

Add mulDiv function that accepts and returns UD60x18 arguments

1 participant