2

I made a small contract test like:


contract Test {

function send() payable public { address payable recipient = 0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C; recipient.transfer(1000000000000000000); // send 1 Ether }

After deploy the contract, I set the "Value" to 2 ether, then called the method "send" which will transfer 1 ether to another address.

Expected result: -1 ether in the sender and +1 in the receiver the "extra" ether (I set in value) is supposed to not be spent, but returned to the sender, right?

The result is: the receiver (0x147...) gets 1 ether, as expected, but the amount discounted from the sender is 2 ether...

why?

where does the unused ether goes?

Thanks in advance

1 ether loss?

2 Answers 2

1

You've overlooked a key principle.

The contract is a full participant. It has a balance. You've disregarded msg.value which is the amount of money received. So, by default, the change stays where it is, in the contract. 2 went in, 1 came out.

You can find the missing funds with a convenience function.

  function myBalance() public view returns(uint) {
      return address(this).balance;
  }

Keep in mind this wouldn't be appropriate for production code. It's unnecessary given that anyone anywhere can inspect any address balance without help from the contract. Still, it's convenient for explorations in Remix.

You could make a betterForwarder() that accepts a recipient argument and forwards all funds received, or even returnTheChange() if you want to achieve the expected behavior. This is not production-ready code. For illustration only.

pragma solidity 0.5.1;

contract Test {

  function send() payable public {
    address payable recipient = 0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C;
    recipient.transfer(1000000000000000000); // send 1 Ether
  }

  function myBalance() public view returns(uint) {
      return address(this).balance;
  }

  function betterForwarder(address payable recipient) public payable {
      recipient.transfer(msg.value);
  }

  function returnTheChange(address payable recipient) public payable {
      require(msg.value >= 1 ether);
      recipient.transfer(1 ether);
      if(msg.value > 1 ether) msg.sender.transfer(msg.value - 1 ether);
  }

}

Hope it helps.

1
  • Thank you for the clarification Rob and @shawn-tabrizi, and yes returnTheChange is the way to go for me. Thanks again.
    – lisandrom
    Dec 22, 2018 at 1:34
1

The unused ether is stored in the contract's balance. Without any functions to access those funds, they are essentially lost. Otherwise, the contract code can transfer any funds it has access to per the code that controls the contract.

Here are a few extra functions that may help you see the balance of ether in the contract, and ways to extract the ether from the contract:

pragma solidity ^0.5.2;

contract Test {

    function send() payable public {
        address payable recipient = 0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C;
        recipient.transfer(1000000000000000000); // send 1 Ether
    }

    function contractBalance() public view returns(uint) {
        return address(this).balance;
    }

    function getContractBalance() public {
        msg.sender.transfer(address(this).balance);
    }

    function destroyContract() public {
        selfdestruct(msg.sender); //remaining funds are sent to msg.sender
    }
}

Obviously, these kinds of functions shouldn't be permissionless, but for testing, this should help.

You can look at some of the common patterns for Solidity development here:

Solidity Docs - Common Patterns - Withdrawal from Contracts

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.