Solidity – Mitigating SafeMath Dangers in Percentage Calculations in Smart Contracts

safemathsolidity

I'm making a fund manager using solidity and I'd like to calculate the percentage, however I'm wonder whether the use of safeMath is actually incorrect.

using SafeMath for uint256;
uint256 percent = 5
function managePayment(uint256 payment)
    amountToSplit = payment.mul(percent).div(100);
}

In this case, I'm limiting myself to 1/5 of the max supply otherwise multiply will throw when calculating the percent, is there a better approach to doing this, (Granted I could avoid using safe math, if I validate the percentage is less than 100) However, I'd like to avoid this approach

Best Answer

Since solidity 0.8 you dont' need safe math for that. The compiler will inject checking sequences to automatically throw if overflow occurs. (This problem was removed since OP is aware of that)

Update: According to the comment, looks like OP wants to calculate multiplying with the result larger than uint256 and then the division will take back the intermediate result down to uint256. The safeMath library or overflow prevention are not designed for that. You need to implement or use some library that can represent higher bitwidth (e.g. uint512). After searching for a while I think Openzeppellin already have similar library for you, look at function mulDiv(uint256 x, uint256 y, uint256 denominator) source code. Hence the code below will be safe to use:

pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol";
contract Test {
  uint256 percent = 10;
  function managePayment(uint256 payment) public view returns(uint256){
      return  Math.mulDiv(payment, percent, 100);
  }
}

Input: 2**255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968

Output: 2**255/10 = 5789604461865809771178549250434395392663499233282028201972879200395656481996

You can also choose rounding direction : Math.mulDiv(payment, percent, 100, Math.Rounding.Up);

Output: 2**255/10 = 5789604461865809771178549250434395392663499233282028201972879200395656481997

Other Related links :

  1. https://forum.openzeppelin.com/t/best-way-to-handle-uint-256-bit/1487/3
  2. How to define 2048-bit integers on smart contracts?
  3. Synthetic uint512 out of 2 uint256
Related Topic