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.