# How to reduce the gas price for complicated smart contracts?

This is my smart contract's calculateReward function:

``````function calculateReward(uint256 _amount, address _sender) internal view returns (uint256) {
uint256 reward = 0;
for (uint256 i= (depositor[_sender].time.sub(startTime)).div(timeWait);
i++){
uint count = penalty[i][0].totalPenaltiesInThisIndex;
while(count != 0){
if(penalty[i][count].time >= depositor[_sender].time && penalty[i][count].time <= now){
if (feePot > 0) {
reward += ((penalty[i][count].amount).mul(_amount)).div(penalty[i][count].deservers); // assuming that if feePot > 0 then also totalSupply > 0
}
}
count = count.sub(1);
}

if(count == 0){
if(penalty[i][count].time >= depositor[_sender].time && penalty[i][count].time <= now){
if (feePot > 0) {
reward += ((penalty[i][count].amount).mul(_amount)).div(penalty[i][count].deservers); // assuming that if feePot > 0 then also totalSupply > 0
}
}
}
}

// if (feePot > 0) {
//     reward = (feePot.mul(_amount)).div((_totalSupply.sub(balances[owner]))); // assuming that if feePot > 0 then also totalSupply > 0
// }
return reward;
}
``````

On withdraw, if tokens are sent to the contract address, contract address calculates his rewards and send back what ever the sender owe.

I am facing an issue that gas price kept increasing as more penalities are there.

Is there a way I can reduce the gas price?

Well, you can obviously change this:

``````while (count != 0) {
...
count = count.sub(1);
}
``````

To this:

``````while (count != 0) {
...
count -= 1;
}
``````

Which will reduce a little bit of gas whenever this loop is executed.

You can also change every occurrence of `div` into a simple `/`.

The `div` function is generally "symbolic", and it is designated just for keeping a certain coding convention. It will act precisely as `/`, except for a preliminary assertion of the denominator being non-zero (hence `div` is slightly more expensive than `/`).

When the denominator is 0, both will act almost the same, throwing either a REVERT or an INVALID opcode (depending on your `SafeMath` library version).

• I applied all the fixes you mentioned and it still didn't reduce the gas significantly.Still gas limit keeps fluctuating between 200000 to 300000 – Fariha Abbasi Aug 25 at 12:13

The only function with a variable loop is calculateReward, having a loop in general not a good idea.

``````/**
* Reward is based on the amount held, relative to total supply of tokens.
*/
function calculateReward(uint256 _amount, address _sender) internal view returns (uint256) {
uint256 reward = 0;
for (uint256 i= (depositor[_sender].time.sub(startTime)).div(timeWait);
i++){
uint count = penalty[i][0].totalPenaltiesInThisIndex;
while(count != 0){
if(penalty[i][count].time >= depositor[_sender].time && penalty[i][count].time <= now){
if (feePot > 0) {
reward += ((penalty[i][count].amount).mul(_amount)).div(penalty[i][count].deservers); // assuming that if feePot > 0 then also totalSupply > 0
}
}
count = count.sub(1);
}

if(count == 0){
if(penalty[i][count].time >= depositor[_sender].time && penalty[i][count].time <= now){
if (feePot > 0) {
reward += ((penalty[i][count].amount).mul(_amount)).div(penalty[i][count].deservers); // assuming that if feePot > 0 then also totalSupply > 0
}
}
}
}

// if (feePot > 0) {
//     reward = (feePot.mul(_amount)).div((_totalSupply.sub(balances[owner]))); // assuming that if feePot > 0 then also totalSupply > 0
// }
return reward;
}
``````
• you are right, can you propose a better alternate to this? This loop is basically used to check that which penalties does a person deserve from a mapping of penalities – Fariha Abbasi Aug 25 at 8:35
• @FarihaAbbasi Without more details is hard to recommend something specific. You usually use a more direct formula that doesn't involve iterating an array, perhaps just two points the begining and the end of the time interval. – Ismael Aug 25 at 18:40
• My use case of the smart contract is that: 1. people deposit their ethers and get back tokens 2. they can send back tokens (all, or partial amount of tokens) to get their ethers back 3. if they send back tokens (withdraw) before 30 days then they will be charged 4% penalty fee 4. if they send back tokens after 30 days then no penalty will be charged 5. the penalty fee will stay in contract and will be distributed to people as reward when they make withdraw. – Fariha Abbasi Aug 25 at 20:42
• 6. if a person withdraw before 30 days then the person will be charged penalty fee but he is still eligible to get reward as he spent time staying inside contract. 7. if a person withdraw after 30 days then the person will get back his ethers along with the reward from the feePot (accumulated portion of all penalty fee) 8. The main idea behind calculating reward is that, we give reward according to the amount of ethers a person has deposited. – Fariha Abbasi Aug 25 at 20:42
• 9. The major part of getting reward is that: lets say wallet A, wallet B and wallet C deposited (1 eth, 0.5 eth and 0.2 eth, respectively) wallet C withdraw his deposit by sending back his tokens before 30 days, so he paid the penalty fee too, now the paid penalty fee by wallet C is only deserved by wallet A and wallet B because they were present when wallet C withdrew. – Fariha Abbasi Aug 25 at 20:43