Arithmetic underflow or overflow in transferFrom

I am a bit puzzled by this error in the function that I will shortly pass on to you.
Debugging I realized that it happens on the line:

require(Contract.transferFrom(msg.sender, address(this), amount));

Of course the amount the user transmits is neither zero nor greater than the number 2^256 - 1.

The user has enough tokens and sends a small amount. But it always returns the arithmetic underflow or overflow error.

When I comment the line it works correctly discarding the other arithmetic operations that would be the logical culprit of this error.

What do you think is happening?

I share with you the function:

   function stake(uint amount) external {
        require(amount > 0, 'amount must be greater than 0');
        require(Contract.balanceOf(msg.sender) >= amount, 'not enough balance');
        require(Contract.approve(address(this), amount));
        require(Contract.transferFrom(msg.sender, address(this), amount));
        if(staked[msg.sender] > 0) {
            require(possibleRechargeTime(), 'Your staking recharge time has elapsed');
        }

        if(staked[msg.sender] == 0) stakedFromTs[msg.sender] = block.timestamp + oneYear;
        staked[msg.sender] += amount;
        totalStakingSupply += amount;

    }

I have added something important.

If I send tokens directly to the contract, i.e. using my metamask, the tokens are sent correctly.
The problem seems to be using the contract as an intermediary. But I can't see where the error could be.

1 Like

Why do you check the balance of the user, the transferFrom will fail if he doesn't have enough funds.
Also why do you approve tokens to the contract itself?

Also did you approve tokens to your contract from the caller?

1 Like

Why do you check the balance of the user?
So that a value of zero is not sent by mistake.

"the transferFrom will fail if he doesn't have enough funds."
I was originally using the transfer function instead of the transferFrom function.

Also did you approve tokens to your contract from the caller?
This is what I intend with the approval. But now that you point it out maybe the approval comes from the contract and is not valid. Anyway with transfer it doesn't work either.
And most importantly, it does not give me an error.

1 Like

Using the transfer function returns the same overflow error.

    function stake(uint amount) external {
        require(amount > 0, 'amount must be greater than 0');
        require(Contract.balanceOf(msg.sender) >= amount, 'not enough balance');
        require(Contract.transfer(address(this), amount));
        if(staked[msg.sender] > 0) {
            require(possibleRechargeTime(), 'Your staking recharge time has elapsed');
        }

        if(staked[msg.sender] == 0) stakedFromTs[msg.sender] = block.timestamp + oneYear;
        staked[msg.sender] += amount;
        totalStakingSupply += amount;

    }
1 Like

no, you need transferFrom.

checking that the amount is bigger than 0 is fine. BUT you don't need to check if the balance is > 0
because if it is not it will fail anyways.

Also you dont fully understand the concept of approvals.
When you call any function of another contract within your contract THEN YOUR contract will be the msg.sender
So let's say we have user 0xA
your contract is 0xB
and the token is 0xC
Now 0xA calls stake() of 0xB.
0xB now calls approve() on 0xC.
So for 0xC, 0xB is msg.sender
for 0xB, 0xA is the msg.sender
This means that your contract is approving tokens for itself, which makes no sense.
This is a safety feature as otherwise you could go to any tokens and approve any amount of it on behalf of any user, which is pretty unsecure.

What does this mean?

The 0xA needs to call approve() on 0xC with 0xB as the spender for the deposit amount.

0xC.approve(0xB, amount)

Your function may look like this

    function stake(uint amount) external {
        require(amount > 0, 'amount must be greater than 0');
        require(Contract.transferFrom(msg.sender, address(this), amount));
        if(staked[msg.sender] > 0) {
            require(possibleRechargeTime(), 'Your staking recharge time has elapsed');
        }

        if(staked[msg.sender] == 0) stakedFromTs[msg.sender] = block.timestamp + oneYear;
        staked[msg.sender] += amount;
        totalStakingSupply += amount;

    }

thanks @Team_X

You are absolutely right about approvals.

However, your corrected function, I still get the overflow error, arithmetic underflow or overflow.
I am still puzzled.

And using the transfer function also continues with the same error.

Effectively the error is that I had to make the approval by calling the token contract.

After doing that I call this function stake.
But the overflow error was throwing me off.
Thank you the solution has been given.

1 Like