Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a math library for working with prices #5163

Open
RohanNero opened this issue Aug 25, 2024 · 0 comments
Open

Add a math library for working with prices #5163

RohanNero opened this issue Aug 25, 2024 · 0 comments

Comments

@RohanNero
Copy link

🧐 Motivation

Since handling prices is something almost every smart contract developer must do, why not have a small helper library to make working with them easier?

📝 Details
There are many scenarios when comparing prices becomes necessary, such as when swapping tokens or ensuring Oracle prices from different providers are within some acceptable range. Math libraries already make all of this possible by, for example, being able to accurately multiply and divide, but

  1. This requires the developer to implement the subsequent calculations on their own, which can introduce potential vulnerabilities.
  2. It may be more desirable to directly view a more meaningful value, for example, the relative change between two integers.

Here is an example of a library that includes 5 functions that could be useful when working with prices:

pragma solidity 0.8.26;

library PriceMath {
    /**@notice Returns the absolute change between two unsigned integers */
    function absDiff(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a - b : b - a;
    }

     /**@notice Returns the relative change between two unsigned integers
     * @dev Maximum change = 99.99% (9999 return value) Minimum change(excluding no change) = .01% (1 return value)
     * @param a The base Value
     * @param b The new value
     * @return The percentage change from a to b, scaled by 1e4 (basis points)
     */
     function relChange(uint256 a, uint256 b) internal pure returns (uint256) {
        uint diff = absDiff(a, b);
        return (diff * 1e4) / a;
     }

    /**
     * @notice Returns the signed relative change between two unsigned integers
     * @dev This function returns how much b has changed relative to the value of a
     * @dev A positive result indicates an increase, while a negative result indicates a decrease
     * @dev Maximum positive change = 99.99% (9999 return value) Maximum negative change = -99.99% (-9999 return value)
     * @param a The base value
     * @param b The new value
     * @return The percentage change from a to b, scaled by 1e4 (basis points)
     */
   function signedRelChange(
        uint256 a,
        uint256 b
    ) internal pure returns (int256) {
        if (a == 0) {
            return b > 0 ? int256(type(int256).max) : int256(0);
        }
        int256 diff = int256(b) - int256(a);
        return (diff * 1e4) / int256(a);
    }

    /**
     * @notice Increases an amount by a given percentage
     * @dev The percentage is expressed as basis points (1/100th of a percent)
     * @param a The base amount
     * @param p The percentage to increase by, in basis points (1% = 100, 100% = 10000)
     * @return The amount increased by the specified percentage
     */
    function addPerc(uint256 a, uint256 p) internal pure returns (uint256) {
        if (p == 0) return a;
        return a + ((a * p) / 10000);
    }

    /**
     * @notice Decreases an amount by a given percentage
     * @dev The percentage is expressed as basis points (1/100th of a percent)
     * @dev Can revert/overflow if value of `a * p` exceeds `type(uint256).max`
     * @param a The base amount
     * @param p The percentage to decrease by, in basis points (1% = 100, 100% = 10000)
     * @return The amount decreased by the specified percentage
     */
    function subPerc(uint256 a, uint256 p) internal pure returns (uint256) {
        if (p == 0) return a;
        return a - ((a * p) / 10000);
    }
}
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

No branches or pull requests

1 participant