3

I'm working on an application that handles percents of a whole.

1. By definition the total percentage will never exceed 100%

I do not want to leave a bug in the application in which could leave a user in an unsolvable state.

Imagine the following scenario.

  1. I'm a token owner I've created a token with the max supply of Uint256.Max.
  2. I put the full supply into a contract
  3. I would like to move 30% of the supply somewhere.

I have an operation to obtain the percent:

function _getAmountFromPercent(uint256 amount, uint256 percentBips) internal pure returns(uint256) {
    return (amount * percentBips) / BASIS_POINTS_FACTOR;
}

This operation will cause an overflow, however the following operation will normalize it since the percentage will always be below 100.

Swaping the operations, wont work either, if your amount is less than the Denomintor you will always result int having 0.

How can I allow overflow operations?

3 Answers 3

1

Using the lib gnosis/solidity-arithmetic:

import "./path/to/Arithmetic.sol";
...        

function _getAmountFromPercent(uint256 amount, uint256 percentBips) internal pure returns(uint256) {
        return Arithmetic.overflowResistantFraction(amount , percentBips, BASIS_POINTS_FACTOR);
    }
3
  • Will this allow underflow with division?
    – Ritzy Dev
    Jan 23, 2023 at 22:48
  • yes since the operation is (a*b)/b, internally the function create a 512-bit buffer, so there is no overflow, according to documentation
    – Rafael
    Jan 23, 2023 at 23:12
  • this looks more robust then muldiv, ill give you the check
    – Ritzy Dev
    Jan 23, 2023 at 23:15
1

You can allow overflow by using unchecked keyword.

    function _getAmountFromPercent(uint256 amount, uint256 percentBips) internal pure returns(uint256) {
       unchecked { return (amount * percentBips) / BASIS_POINTS_FACTOR; }
    }

NOTE: This is for solidity 0.8.0 and above

1
  • 3
    I don't think this gives the right result since it doesn't underflow back. Jan 23, 2023 at 11:28
0

I ended up using mulDiv from Openzeppelin:

import "@openzeppelin/contracts/utils/math/Math.sol";

function _getAmountFromPercent(uint256 amount, uint256 percentBips) internal pure returns(uint256) {
    return Math.mulDiv(amount, percentBips, BASIS_POINTS_FACTOR);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.