Issue with sending tokens after performing arithmetic operations

I'm implementing a fundraising contract where a user can create a fundraiser but when creating they must send a `rewardingToken` (ERC20 token) to the contract and the user also specifies a token which is accepted for the fundraiser, called `acceptingToken`, and the `raise` amount which is the number of `acceptingToken` that we are fundraising for.

`acceptingToken ` can be any ERC20 token.

In this example, Lets assume the total supply of `rewardingToken` is 100,000 tokens. When creating a fundraiser the amount of `rewardingToken` deposited is 1000, the raise goal (i.e the number of `acceptingToken` we want to raise) is 100.

When the raise goal is met and an investor wants to withdraw the `rewardToken` then I calculate it by

``````                uint256 rewardTokens = ((rewardingTokenAmount) /
(raise)) * amtInvestorInvested;

IERC20(rewardingToken).transfer(
msg.sender,
rewardTokens
)
``````

The issue here is if there are decimal number which will end up not giving rewards in an accurate manner, which will cause users to get less than what they deserve.

I initially thought to multiply the `rewardingTokenAmount` by 1e18, to have 18 decimal points in accuracy. But then when sending the tokens, I will need to divide by 1e18 which would defeat the purpose of doing that.

Not sure what the best method for this

I'll set some other concerns aside to just focus on the question raised.

When working with integers that represent fixed decimal numbers you do indeed need to scale precision. In order to avoid loss of precision, perform multiplication before division.

Consider:

``````uint256 rewardTokens = rewardingTokenAmount * amtInvestorInvested / raise;
``````

Precision/scale was raised by 1e18 (mul) and then reduced by 1e18 (div) so no further adjustment is necessary.

Also consider truncation of the last digit and what it means in your application. That is to say, account for "dust" and decide what to do with it whenever division is involved.

Hope it helps.

• Thanks @Rob so should my reward reward tokens be calculated like uint256 rewardTokens = rewardingTokenAmount * amtInvestorInvested * 1e18 / raise * 1e18; ? Commented Mar 7, 2023 at 9:38
• You can remove `1e18` from both sides and still land on the same result. Commented Mar 9, 2023 at 3:58
• Thanks that totally makes sense, a final question - will this be the most accurate way to do such a division ? Commented Mar 9, 2023 at 12:58
• Multiplication before division. Account for "dust", a.k.a. the remainder (division truncates). If the remainder does not land naturally in the right place, then use a modulo to account for it and do something. As a rough heuristic, don't have money in the contract that isn't in someone's or something's "account". Commented Mar 9, 2023 at 17:24
• As an example of what you don't want, consider a contract that splits deposits into two accounts for Alice and Bob. The contract uses a simple mapping to record their balances/entitlements. Someone deposits an odd number, say 3 - 1 to Alice, 1 to Bob, and 1 unrecoverable from the contract unless care is taken to avoid overlooking the uneven division. Commented Mar 9, 2023 at 17:26