0

I am getting a syntax error in the following code:

pragma solidity ^0.5.1;
contract C {          
  function pay(uint n, address payable d)public { 
    d.send(n);  
  } 
}

contract D1 {
  uint public bal = 0;
  function() external { 
    bal+n; 
  }        
}

Syntax error is:

two_send.sol:16:29: Error: Undeclared identifier. function() external { bal+n; }

In the call:

d.send(n);

Q1:I am sending 'n' to D1's fallback function. How can we add 'n' to 'bal'?

Q2:Also I am not calling 'pay()' explicitly in contract 'C', is it not necessary? How the pay would execute if we won't call it explicitly?

Somebody please guide me.

1 Answer 1

1

I fiddled with code formatting in the original question. The first issue is this line:

bal+n;

It should be bal = bal + n; to do something, or the shorthand, bal += n; but we will still have a problem.

What is n? That's the complaint.

In C you send(n). n has meaning in that context but the variable name is not transmitted. It's an amount of ether attached to the message. On the receiving side, that would be msg.value. The receiver is indifferent to how the sender computed the amount or what it was called (so, not n).

That leads to another problem. We would be using msg.value like this: bal += msg.value; but the receiving fallback function not payable which it needs to be because all functions reject unwanted ether (as a safety measure) by default. If we intend this function to accept funds (we do) then it needs to be marked payable like this: function() external payable {

There is another issue.

The compiler will complain about the "unchecked" send. This is because send returns true or false depending on success and this value should always be checked, like this: if(d.send(n)) { } else { }. The compiler is warning about this oversight.

It is better to use d.transfer(n) because it reverts everything if the transfer fails for some reason, otherwise processing might blissfully carry on even though no funds were transferred (that could be bad). Avoid send unless you know what you are doing.

Finally, there is a problem with transfer. It will only send 2,300 gas (the "gas stipend") and that is not enough for the state change on the receiving side where you write to bal (50-20K gas). This is an intentional limitation of fallback functions and send and transfer methods.

You can avoid that with some funky syntax to force the gas through:

pragma solidity ^0.5.1;
contract C {          
  function pay(uint n, address payable d) public returns(bytes memory theMessage) { 
    (bool success, bytes memory returnMessage)  = d.call.value(n)("");  
    require(success, "D1 did not accept the funds."); // checking the result
    return returnMessage;  // doing "something" with this variable so the compiler doesn't complain
  } 
}

contract D1 {
  uint public bal = 0;
  function() external payable { 
    bal+=msg.value; 
  }        
}

I assume this is a learning project and we are straying into some confusing territory because of the security precautions that are unique to fallback functions. The 2,300 gas stipend is insufficient to write to storage, by design, but you can still create a simple experiment that you should be able to see working in Remix (highly recommended for experimentation).

There is really no need to add to bal because the protocol already does that. D1's ether balance will increase even if we do nothing. There is sufficient gas to emit an event, so let's do that. And, we can make a little function to conveniently inspect D1's balance.

I think you will find testing a little more convenient if C relays funds sent to it so you don't have to work out where the funds came from (it can't send what it doesn't have). Altogether:

pragma solidity ^0.5.1;

contract C { 

  function pay(address payable d) public payable { 
    d.transfer(msg.value);
  } 

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

}

contract D1 {

  event LogDeposit(address sender, uint amount);

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

  function() external payable {
      emit LogDeposit(msg.sender, msg.value);
  }  

}

Hope it helps.

2
  • (bool success, bytes memory returnMessage)? 'call' returns true/false, so success is fine, but what would go into 'returnMessage', you mean it is just to avoid compiler complain (if this is true then its OK). Thanks a lot.
    – zak100
    Commented Jun 21, 2019 at 2:06
  • That form of call returns the ABI-encoded response if the function returns something (it doesn't). Returning it is just a way to make the compiler stop complaining about declaring a variable that isn't subsequently used for anything. We were only interested in the success/fail response. Commented Jun 21, 2019 at 6:50

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.