0

Currently have this smart contract written in Remix.

I deploy the contract using the JavaScript VM on the topmost account

Then I switch accounts and then call the function like so:

enter image description here

To send 4 ether from the account to the smart contract. However, my transaction fails.

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

/**
 * @title PayableContract
 * @dev send ether to a smart contract 
 */
contract PayableContract {
    constructor() {} 

    event PaymentReceived(address indexed _sender, uint _before, uint _after);

    function getContractBalance() public view returns (uint256) {
        return address(this).balance; 
    }

    function sendPaymentToContract(uint _amount) payable external 
    {
        uint beforeBalance = getContractBalance();
        payable(address(this)).transfer(_amount);
        uint afterBalance = getContractBalance();
        emit PaymentReceived(msg.sender, beforeBalance, afterBalance);
    }
    
    receive() payable external {}
}

After I call the function, I expect to see my balance go from 100 ether on the left part of the Remix IDE to 95.999... (100 ether - 4 - gas costs). However, the 4 ether does not get withdrawn, but only the gas costs.

I get that the transfer() function is bad for safety reasons. I just did it for clarity. I also understand that this is suboptimal and bad code since I can just use msg.value instead. However, I am wondering why exactly this doesn't work. It seems like it should.

2 Answers 2

0

Well, what you pass is an argument to the function only. It has no value in solidity. As you mentioned, you can remove the argument and use msg.value. If you want to represent the value in your argument, you have to use the same amount both in your argument and the "VALUE" section of the remix.

If you don't use the pass VALUE, your function argument will not have a value.

Here is an example.

5
  • Regarding your first point, then if the function has no value in solidity, is it even possible to use stuff like transfer(), send(), call{value: _amount}(“”) with parameters to a function? Does this somehow relate to calldata?
    – hacker
    Commented Apr 7, 2022 at 4:15
  • To be clear, the argument you pass to the function is just a variable. It does not represent any monetery value in solidity, which is why you dont see any deduction in your account balance. If you want see a change, you need to use "VALUE" section.
    – Emrah
    Commented Apr 7, 2022 at 4:17
  • Is there a way to design some external or public function so it works the way I want? In the case a user may send a transaction calling the function with some value (in wei) as the parameter and have it be withdrawn from their account to the contract without msg.value? Is this question just kind of a non-question in the sense that it’s something that would never be implemented in any production grade smart contracts? If so, why? Do we always need to rely on msg.value for any monetary amounts?
    – hacker
    Commented Apr 7, 2022 at 4:35
  • Without using msg.value, I don't think it is possible. You can use the method I descrived in answer; however, it still requires msg.value. I updated the answer and gave an example. Its funny, I asked the same question of yours a year ago. ethereum.stackexchange.com/questions/90658/…
    – Emrah
    Commented Apr 7, 2022 at 14:16
  • I see! I think it makes sense intuitively since all external and public function calls (e.g. the ones that will prompt a transaction) are essentially a fancy transaction with the "value" field populated. No data that you pass within the calldata of the transaction will ever change the "value" field in the transaction. Hence, msg.value is the key. Seeing that you asked the same question a year ago and you answering it now is so funny :) says a lot about if you stick with something long enough, you'll get it and more. Thanks for your detailed answers and comments!
    – hacker
    Commented Apr 7, 2022 at 21:09
0

this is not an answer my question is i am having same problem , i cannot design frontend for this problem,i dont want to use Value Textbox. how to send ether as an argument and decrease the same from main account balance. id id something like msg.sender.balance - = amount , but i get error Lvalue required . is there any solution to transfer ether as argument rather than passing from Value text Box. Thanking you

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.