0

I'm trying to code a reward pool distribution system and I'm unable to do the following (in that order).

  • A deposits X amount (user_deposit)
  • B deposits Y amount (user_deposit)
  • C deposits Z amount of rewards (depositRewards)

(order doesn't matter on the 2 following steps)

  • A withdraws
  • B withdraws

The second withdrawal always fails with this error: The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance.

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract ETHPool {

mapping(address => bool) internal team_members;
uint256 public poolValue;
uint256 internal rewards;
address internal contractAdmin;
uint256 public rewards_timestamp;
uint256 public claimable_rewards;

struct User_Transactions {
    uint256 amount;
    uint256 deposit_timestamp;
}

mapping(address => User_Transactions[]) internal deposits;

constructor() {
    contractAdmin = msg.sender;
}

function update_team(address _memberAddress, bool _isAllowed) public {
    require(msg.sender == contractAdmin, "Function only callable by contract admin.");
    team_members[_memberAddress] = _isAllowed;
}

function depositRewards() public payable {
    require(team_members[msg.sender] == true, "Only team members are allowed to deposit rewards");
    rewards += msg.value;
    claimable_rewards += msg.value;
    rewards_timestamp = block.timestamp; 
}

function user_deposit() public payable {
    deposits[msg.sender].push(User_Transactions(msg.value, block.timestamp));
    poolValue += msg.value;
}

function withdraw() public {

    require(deposits[msg.sender].length > 0, "You have no deposits on your behalf.");
    uint256 valueAddedUntilNow;
    uint256 totalValueAdded;

    for (uint i=0; i < deposits[msg.sender].length; i++) {
        if (deposits[msg.sender][i].deposit_timestamp < rewards_timestamp) {
            valueAddedUntilNow += deposits[msg.sender][i].amount;                
        }
        totalValueAdded += deposits[msg.sender][i].amount;
    }

    uint256 share_of_pool = (valueAddedUntilNow * 100) / poolValue;
    payable(msg.sender).transfer((rewards / 100) * share_of_pool + valueAddedUntilNow); 
    claimable_rewards -= (rewards / 100) * share_of_pool;
    poolValue -= valueAddedUntilNow;
    delete deposits[msg.sender];
}
}
2
  • Comment unrelated to your question: I would discourage the use of transfer. See consensys.net/diligence/blog/2019/09/…
    – Richard
    Commented Dec 20, 2021 at 21:23
  • Another thing that you should be aware of are rounding errors. If you perform x / 100 on a integer you are losing the decimals
    – Richard
    Commented Dec 20, 2021 at 21:26

1 Answer 1

0

When you perform A withdraws you reduce poolValue. When you then perform B withdraws and calculate the share_of_pool based on this new poolValue it will result in a poll share of 100. This will result in the reward that should be added to the amount that should be transferred to be equal to rewards, but at this point we don't have all of the rewards available anymore, as part as already been claimed by A.

1
  • Thank you! It was the classic error "being blind af". Appreciate it! Commented Dec 20, 2021 at 22:32

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.