Fixed-point Math

Solidity supports integers but not decimals

Solidity scales up decimals into integers, to sidestep its ability to offer floats. The number of decimals in ERC20 determines the factor by which decimals are scaled up.

For instance, 18 means that the value is stored in an uint as decimalValue * 10**18

  • 1 unit of token is represented as 1e18.

  • 10 units of token is represented as 10e18.

  • 0.5 units of token is represented as 5e17.

  • 100.103 => stored as uint 100103000000000000000 (100.103 *10**18)

  • 0.000340 => stored as uint 340000000000000 (0.00034*10**18)

Converting 1 DAI to WETH (18 dp -> 18 dp)

Both DAI and WETH are of 18 decimal precision. Let us assume 1 DAI = 0.00039472576 ether.

Exchange rate on contract => DAI/ETH: 394725760000000 (0.00039472576 * 1e18)

Conversion

  • 1 DAI * DAI/ETH = Qty of Ether

  • 1e18 DAI x 394725760000000 = 394725760000000...0(18 more '0's)

  • 1e18 x [0.00039472576 * 1e18] = 0.00039472576 *1e18 *1e18

When multiplying two integers, and the resulting value is scaled up twice. Which is why we divide, to remove the extra scaling factor, after multiplication.

  • 1e18 x [394725760000000] / decimal_precision

  • 1e18 x [394725760000000] / 1e18 = 394725760000000

  • 394725760000000 represents 0.00039472576

Converting between different decimal representations

  • TokenA is set up with 18 decimals

  • TokenB is set up with 6 decimals

If you want to convert between different representations you have to multiply or divide depending on the difference in decimals count:

To convert valueA to valueB: (18 dp -> 6 dp)
    valueB = valueA / 10**(A.decimals - B.decimals)
    valueB = valueA / (10**(18-6))

Normalize the from_token by stripping it of its decimal places.

Then we scale up by the TokenB (to token) decimals

Vice versa

**To convert valueB to valueA: (6 dp -> 18 dp)
    valueA = valueB * 10**(B.decimals - A.decimals)
    valueA = valueB * (10**(18-6))

    valueA = (valueB / 10**6) * 10**18

Last updated