Hi @Shadowstep2003,
I’ve deployed and tested your contracts and your transfer() function executes successfully, including the external function call and value transfer to Government.
The most common cause of the transfer() function reverting, with the error message you’ve received, is not changing the Government contract’s address, which is assigned to your governmentInstance. Have a look at this post, which explains the issue and how to resolve it. It also explains why the error message you got isn’t very helpful.
A couple of other observations about your Bank contract …
(1) Notice that the address calling the transfer() function is not sending ether from their external address to the Bank contract (as they do when calling the deposit function). The transfer performed is an internal reallocation of funds between two individual users. A function only needs to be marked payable
when it needs to receive ether. So, unlike the deposit() function, we don’t want to mark transfer() as payable
in its function header.
Within the transfer() function, the external function call to addTransaction() does involve ether being transferred from Bank to the Government contract (as a tax on the transfer transaction, or as a fee for recording it in the Government transaction log). But this value transfer only requires the receiving function (addTransaction in Government) to be marked payable
, and not the sending function (transfer in Bank).
Marking the transfer() function as payable
doesn’t prevent the code from compiling, or the function from executing, but it is bad practice and poor risk management not to restrict a function to non-payable if it doesn’t need to receive ether, because if someone sends ether by mistake, this amount will still be transferred to the contract. For example, if the caller sent an ether value to the transfer() function by mistake (as well as calling it with a transfer amount
and a recipient
address) then this ether would be added to the Bank contract balance and potentially lost to the user, because such a deposit wouldn’t also be added to the user’s individual account balance in the mapping (only the transfer amount is deducted from their balance). However, the function is much securer if we leave it as non-payable, because then, if the caller made the same mistake, the function would revert, and the ether would not be sent.
(2) You’ve applied the onlyOwner modifier to the withdraw() function, but this means that only the contract owner can withdraw funds up to their own individual balance. But the contract allows multiple addresses to deposit funds (we are simulating a bank with bank account holders) and so it only seems fair that all users should be able to withdraw their funds as well, don’t you think?
Let me know if you have any questions about these points, or if you’re still having problems calling the transfer() function.