0

In my dApp the user sets the entry fee for the game they are creating. The entry fee for games will usually be between $5 USD and $50 USD. What unit should I use for the contract method that accepts payment for the game (i.e. - the type to preface the relevant method parameter with)? Should I use: wei, gwei, eth, etc.?

Also, what Solidity type should I use internally in my contract that does a fair number of numeric calculations when it comes time to pay the players? I assume a fixed point type like uint* is not a good fit? I'm asking this question both for storage and memory variables.

I assume for percentages I can just use uint and divide by 100 internally? But I'm asking the above questions for parameters that will be receiving floating point numbers generally.

3
  • 2
    It's reasonable to use a fixed number of decimals (like 10^18 wei being 1 ether), or you can use an explicit rational number with a separate numerator and denominator (e.g. (7, 100) means 0.07). The latter is the approach taken here: programtheblockchain.com/posts/2018/02/27/….
    – user19510
    Commented Jun 21, 2018 at 20:07
  • 1
    For your first question, you probably want to accept an amount in wei, and the appropriate type for the parameter is uint256.
    – user19510
    Commented Jun 21, 2018 at 20:08
  • @smarx Thanks. Now all I have to do is find a reliable API to give me a quote in USD for Eth, and another one to convert between one fiat currency and another so I can show the user a friendly monetary value. Commented Jun 21, 2018 at 20:19

3 Answers 3

1

In my opinion, it is preferable to adapt to the EVM's use of integers where possible. It is nearly always possible.

For example, here is a simple pattern for handling a percentage with two high-precision integers (one could be an exchange rate and the other a transaction volume). First, convert each input to an 18-decimal integer. So 1.0 would be 1 * 10 ** 18. 87% is 0.870,000,000,000,000,000, or as an integer 870000000000000000.

When you multiply two large integers together you get an even larger integer since ( 10 ** 18 ) * ( 10 ** 18 ) is 10 ** 36. You will have the correct significant digits and you just need to adjust the decimal position for correct interpretation.

Consider this pattern:

pragma solidity ^0.6.6;

contract Precision {
    
    uint constant PRECISION = 10 ** 18;
    uint constant demonstrateRatio = 87 * 10 ** 16;
    
    function percentOf(uint baseValue) public pure returns(uint result) {
        return ( baseValue * demonstrateRatio ) / PRECISION;
    }
}

Tip: Always multiply before dividing to avoid loss of precision.

For example, rewrite the following:

x = ( a / b ) * PRECISION

as

x = ( a * PRECISION ) / b

This is because 100/200 = 0 (with truncation) and 0 * PRECISION = 0. On the other hand, (100 * PRECISION) / 200 gives a non-zero result that can be returned after adjusting the decimal position with / PRECISION.

If you want correct rounding, you can add 5 to the nominator before dividing which will either round up (correctly) or truncate the result (correctly).

x = ( a * PRECISION + 5 ) / b

Hope it helps.

0

Solidity does not support floating point variables because they are harder to be deterministic with and are not the most secure. The most common version of decimals is to have a uint that is not a single ETH or USD, but 1/10^18th of one.

0

You may use ABDK Math 64.64 library. It operates with binary fixed point numbers (64 binary digits after dot) and contains all basic math operations. It uses int128 type to represent fixed point number.

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.