Socket
Socket
Sign inDemoInstall

@prb/math

Package Overview
Dependencies
0
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @prb/math

Solidity library for advanced fixed-point math


Version published
Maintainers
1
Install size
123 kB
Created

Changelog

Source

[3.2.0] - 2022-12-13

Added

  • Add assertions for array comparisons (@PaulRBerg)

Removed

  • Delete assertions that have an "err" argument (@PaulRBerg)

Fixed

  • Match types for SD1x18 and UD2x18 assertions (@PaulRBerg)

Readme

Source

PRBMath GitHub Actions Foundry Styled with Prettier License: MIT

Solidity library for advanced fixed-point math that operates with signed 59.18-decimal fixed-point and unsigned 60.18-decimal fixed-point numbers. The name of the number format is due to the integer part having up to 59/60 decimals and the fractional part having up to 18 decimals. The numbers are bound by the minimum and the maximum values permitted by the Solidity types int256 and uint256.

  • Operates with signed and unsigned denary fixed-point numbers, with 18 trailing decimals
  • Offers advanced math functions like logarithms, exponentials, powers and square roots
  • Provides type safety via user defined value types
  • Gas efficient, but still user-friendly
  • Ergonomic developer experience thanks to using free functions instead of libraries
  • Bakes in overflow-safe multiplication and division
  • Reverts with custom errors instead of reason strings
  • Well-documented with NatSpec comments
  • Built and tested with Foundry

I created this because I wanted a fixed-point math library that is at the same time intuitive, efficient and safe. I looked at ABDKMath64x64, which is fast, but it uses binary numbers which are counter-intuitive and non-familiar to humans. Then, I looked at Fixidity, which operates with denary numbers and has wide precision, but is slow and susceptible to phantom overflow. Finally, I looked at Solmate, which checks all the boxes mentioned thus far, but it doesn't offer type safety.

Install

Foundry

First, run the install step:

forge install --no-commit paulrberg/prb-math@v3

Then, add this to your remappings.txt file:

@prb/math/=lib/prb-math/src/

Node.js

yarn add @prb/math
# or
npm install @prb/math

Usage

PRBMath comes in two flavors:

  1. SD59x18 (signed)
  2. UD60x18 (unsigned)

If you don't need negative numbers, there's no point in using the signed flavor. The unsigned flavor is more gas efficient.

Importing

It is recommended that you import PRBMath in the global scope, because you will often need multiple symbols:

pragma solidity >=0.8.13;

import "@prb/math/SD59x18.sol";
import "@prb/math/UD60x18.sol";

Note that PRBMath can only be used in Solidity v0.8.13 or above.

SD59x18

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13;

import "@prb/math/SD59x18.sol";

contract SignedConsumer {
  /// @notice Calculates 5% of the given signed number.
  /// @dev Try this with x = 400e18.
  function signedPercentage(SD59x18 x) external pure returns (SD59x18 result) {
    SD59x18 fivePercent = sd(0.05e18);
    result = x.mul(fivePercent);
  }

  /// @notice Calculates the binary logarithm of the given signed number.
  /// @dev Try this with x = 128e18.
  function signedLog2(SD59x18 x) external pure returns (SD59x18 result) {
    result = log2(x);
  }
}

UD60x18

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13;

import "@prb/math/UD60x18.sol";

contract UnsignedConsumer {
  /// @notice Calculates 5% of the given signed number.
  /// @dev Try this with x = 400e18.
  function unsignedPercentage(UD60x18 x) external pure returns (UD60x18 result) {
    UD60x18 fivePercent = ud(0.05e18);
    result = x.mul(fivePercent);
  }

  /// @notice Calculates the binary logarithm of the given signed number.
  /// @dev Try this with x = 128e18.
  function unsignedLog2(UD60x18 x) external pure returns (UD60x18 result) {
    result = log2(x);
  }
}

Features

There's significant overlap between the functions available in SD59x18 and UD60x18, so I did not duplicate the functions tables below. If in doubt, refer to the source code, which is well-documented with NatSpec comments.

Mathematical Functions

NameDescription
absAbsolute value
avgArithmetic average
ceilSmallest whole number greater than or equal to x
divFixed-point division
expNatural exponential e^x
exp2Binary exponential 2^x
floorGreatest whole number less than or equal to x
fracFractional part
gmGeometric mean
invInverse 1÷x
lnNatural logarithm ln(x)
log10Common logarithm log10(x)
log2Binary logarithm log2(x)
mulFixed-point multiplication
powPower function x^y
powuPower function x^y with y simple integer
sqrtSquare root

Conversion Functions

NameDescription
fromSD59x18Converts an SD59x18 number to a simple integer by dividing it by 1e18
fromUD60x18Converts an UD60x18 number to a simple integer by dividing it by 1e18
sdAlias for wrap, wraps a simple integer into SD59x18
sd59x18Alias for wrap, wraps a simple integer into SD59x18
toSD59x18Converts a simple integer to SD59x18 by multiplying it by 1e18
toUD60x18Converts a simple integer to UD60x18 by multiplying it by 1e18
udAlias for wrap, wraps a simple integer into UD60x18
ud60x18Alias for wrap, wraps a simple integer into UD60x18
unwrapUnwrap an SD59x18 or UD60x18 number into a simple integer
wrapWraps a simple integer into either SD59x18 or UD60x18

Helper Functions

In addition to the mathematical and the conversion functions, PRBMath provides many other helpers for the user-defined value types, such as add,eq, and rshift. These functions are not part of the core API and are frequently updated, so I invite you to take a look at the source code to see the full list.

The goal with these helpers is not have to always unwrap and re-wrap variables to perform such basic operations as addition and equality checks. However, you should note that using these functions instead of the vanilla operators (e.g. +, ==, and >>) will result in a higher gas cost.

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13;

import "@prb/math/UD60x18.sol";

function addRshiftEq() pure returns (bool result) {
  UD60x18 x = ud(1e18);
  UD60x18 y = ud(3e18);
  y = y.add(x);
  y = y.rshift(2);
  result = eq(x, y);
}

Adjacent Value Types

PRBMath provides adjacent value types that serve as abstractions over other vanilla types such as int64. The types currently available are:

Value TypeUnderlying Type
SD1x18int64
UD2x18uint64

These are useful if you want to save gas by using a lower bit width integer, e.g. in a struct.

Note that these types don't have any mathematical functionality. For that, you will have to unwrap them into a simple integer and then to the core types SD59x18 and UD60x18.

Assertions

PRBMath is shipped with typed assertions that you can use for writing tests with PRBTest, which is based on Foundry. This is useful if, for example, you would like to assert that two SD59x18 or UD60x18 numbers are equal.

pragma solidity >=0.8.13;

import "@prb/math/UD60x18.sol";
import { Assertions as PRBMathAssertions } from "@prb/math/test/Assertions.sol";
import { PRBTest } from "@prb/math/test/PRBTest.sol";

contract MyTest is PRBTest, PRBMathAssertions {
  function testAdd() external {
    UD60x18 x = ud(1e18);
    UD60x18 y = ud(2e18);
    UD60x18 z = ud(3e18);
    assertEq(x.add(y), z);
  }
}

Gas Efficiency

PRBMath is faster than ABDKMath for abs, exp, exp2, gm, inv, ln, log2, but it is slower than ABDKMath for avg, div, mul, powu and sqrt.

The main reason why PRBMath lags behind ABDKMath's mul and div functions is that it operates with 256-bit word sizes, and so it has to account for possible intermediary overflow. ABDKMath, on the other hand, operates with 128-bit word sizes.

Note: I did not find a good way to automatically generate gas reports for PRBMath. See the #134 discussion for more details about this issue.

PRBMath

Gas estimations based on the v2.0.1 and the v3.0.0 releases.

SD59x18MinMaxAvgUD60x18MinMaxAvg
abs687270n/an/an/an/a
avg95105100avg575757
ceil82117101ceil787878
div431483451div205205205
exp3827972263exp187427422244
exp26326782104exp2178426522156
floor82117101floor434343
frac232323frac232323
gm26892690gm26893691
inv404040inv404040
ln46373064724ln41969023814
log1010490744337log1050386954571
log237772414243log233068253426
mul455463459mul219275247
pow64113388518pow64106376635
powu293247455681powu83245355471
sqrt140839716sqrt114846710

ABDKMath64x64

Gas estimations based on the v3.0 release of ABDKMath. See my abdk-gas-estimations repo.

MethodMinMaxAvg
abs889290
avg414141
div168168168
exp7737802687
exp27736002746
gavg166875719
inv157157157
ln707471647126
log2697270627024
mul111111111
pow30347401792
sqrt129809699

Contributing

Feel free to dive in! Open an issue, start a discussion or submit a PR.

Pre Requisites

You will need the following software on your machine:

In addition, familiarity with Solidity is requisite.

Set Up

Clone this repository including submodules:

$ git clone --recurse-submodules -j8 git@github.com:paulrberg/prb-math.git

Then, inside the project's directory, run this to install the Node.js dependencies:

$ yarn install

Now you can start making changes.

Syntax Highlighting

You will need the following VSCode extensions:

Security

While I set a high bar for code quality and test coverage, you should not assume that this project is completely safe to use. PRBMath has not been audited by a security researcher.

Caveat Emptor

This is experimental software and is provided on an "as is" and "as available" basis. I do not give any warranties and will not be liable for any loss, direct or indirect through continued use of this codebase.

Contact

If you discover any bugs or security issues, please report them via Telegram.

Acknowledgements

License

MIT

Keywords

FAQs

Last updated on 13 Dec 2022

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc