Disbursing rewards

I wish to know if the function given below correctly transfers rewards from the contract caller to the required account or not. Is there anything to consider before calling this function from some source?

I’m assuming that I need to approve an amount that the contract can spend from. Can this be done once at the time of contract deployment? If so, how can I ensure that every address with the DISBURSER_ROLE gets approved, i.e. during role assignment?

:1234: Code to reproduce

function disburseReward(address to, uint256 rewardWei)
    external
    onlyRole(DISBURSER_ROLE)
    returns (bool)
{
    if (msg.sender.balance < gasleft()) revert("native balance < gas");
    if (token.balanceOf(msg.sender) < rewardWei)
        revert("token balance < reward");

    if (!token.transferFrom(msg.sender, to, rewardWei))
        revert("Token transfer failed.");
    emit RewardClaimed(msg.sender, to, rewardWei);

    return true;
}

:computer: Environment

Hardhat 2.8.3

if you transfer native currency, I think that you don’t need to approve anything, only for ERC20 tokens or NFTs you would need to use approve

1 Like

I do need to transfer ERC20 tokens.

in that case, somehow the smart contract that makes that transfer has to be approved to do that transfer

1 Like

I’m using this definition now:

/**
    @dev Disburses `reward` to `claimant`.

    Emits {Approval} events in case {disburserApproveAmount} changes.
    Emits {RewardClaimed}.
    */
function disburseReward(address claimant, uint256 reward)
    external
    onlyRole(DISBURSER_ROLE)
    whenNotPaused
    returns (bool)
{
    address disburser = msg.sender;
    // checks
    require(
        disburser.balance >= gasleft(),
        "RewardClaim: native bal < gas"
    );
    require(
        token.balanceOf(disburser) >= reward,
        "RewardClaim: token bal < reward"
    );

    // interactions
    address tokenAddress = address(token);
    uint256 currentAllowance = token.allowance(disburser, tokenAddress);
    // Will always be true for a first-time disburser
    if (currentAllowance < reward) {
        if (
            !token.increaseAllowance(
                disburser,
                disburserApproveAmount - currentAllowance
            )
        ) {
            revert("RewardClaim: approval failed.");
        }
    }

    if (!token.transferFrom(disburser, claimant, reward))
        revert("RewardClaim: claim failed.");

    emit RewardClaimed(disburser, claimant, reward);

    return true;
}

Public repo: https://gitlab.com/Vivraan/UltraContracts

I want to make it clear that I’m planning to use the disburseReward method implemented here through Moralis Cloud Code, is that possible?

you want to call a contract function from cloud code?

Yes, specifically disburseReward.

and what would be the problem with that?

I was reading up earlier on the docs that Moralis’ Cloud implementation can’t sign messages or something, will that not be a problem?

that is not a problem, you will have to write the code that signs and sends the transaction to a node

I see, any guides for doing that which I can refer to?

you can search on forum, on google, we don’t have a function in Moralis SDK that does that, and it is not recommended to do that as you will have to save the private key

Yes, that was the restriction I read about. I’ll have to consider how this is done I suppose.

I’m quite new to this: does this mean the service must use a wallet address and its private key to sign the messages?