The reason it is possible to receive value (more than 0) through âinteractionâ line in the code is because the balance of the user was already checked in the âchecksâ part, and the user initially had something on the balance, before the balance was set to 0. It was required to be equal to the amount in the balances mapping for that msg.sender in the initial line.
uint amountToWithdraw = balances[msg.sender];
next after that, the value for msg.sender in the mapping is set to 0,
balances[msg.sender] = 0;
and then the amount (that must be equal to balance in the mapping when code was ran initially) is sent from the smart contract.
require(msg.sender.call.value(amountToWithdraw)());
The contract caller cant withdraw again because now his amount in mapping is set to 0 and the smart contract will think he doesnt have any right to money on the smart contract. But he was able to withdraw after his balance was set to zero because the smart contract ran the code to give the withdraw amount (required to be equal to balance before it was set to 0) to the msg.sender.