Solidity's call
is a low-level interface for sending a message to a contract. It returns false
if the subcall encounters an exception, otherwise it returns true
. There is no notion of a legal call, if it compiles, it's valid Solidity.
nameReg.call("register", "MyName")
is a message that passes certain bytes to nameReg. For the bytes, see: Understanding nameReg.call("register", "MyName") style call between contracts
nameReg.call(bytes4(sha3("fun(uint256)")), a)
is a message that would invoke a function named fun
(if nameReg adheres to the ABI) and pass it the raw, unpadded data a
(you need to correctly pad a
to 32 bytes first if you want behavior to match the ABI. For uint256
use left-padding.).
For 3, contract.call.value(...)(...)
is a way to add Ether when invoking a contract. if(!nameReg.call.value(10)()){throw;}
is an example of handling the failure case of the subcall. Note the extra parentheses value(10)()
which invokes the fallback function.
call
is a low-level interface, and it is simpler to invoke a function directly, nameReg.fun(a)
instead of the second example. The direct invocation is also type-safe, and allows the return value of fun
to be used.
A function selector allows you to perform dynamic invocation of a function, based on the name of the function and the type of each one of the input arguments.
For example, suppose you have:
contract Contract1 {
function func(uint256 x, uint8 y) public returns (uint32, uint32) {...}
}
contract Contract2 {
Contract1 public contract1 = new Contract1();
function func() public returns (uint32, uint32) {...}
}
Then you can call Contract1.func
from Contract2.func
as follows:
function func() public returns (uint32, uint32) {
uint32[2] memory ret;
address dest = address(contract1);
bytes4 selector = contract1.func.selector;
// Or bytes4 selector = bytes4(uint256(keccak256("func(uint256,uint8)") >> 224));
bytes memory data = abi.encodeWithSelector(selector, uint256(789), uint8(123));
assembly {
let success := call(
gas, // pass the remaining gas to the function
dest, // the address of the contract1 instance
0, // pass 0 wei to the function
add(data, 32), // the actual data starts after the length of 'data'
mload(data), // the length of 'data' appears at the first 32 bytes
ret, // the address of the output
8 // the size of the output
)
if iszero(success) {
revert(0, 0)
}
}
return (ret[0], ret[1]);
}
If the invoked function is constant (either pure
or view
), then you can also use staticcall
.
The example above is in assembly, but you can also use call
directly in solidity.
I think that staticcall
should be available starting from solidity v0.5.0.
Best Answer
Here is an example from What is an ABI and why is it needed to interact with contracts?
If we wanted to call
baz()
with the parameters69
andtrue
, we would pass 68 bytes in total, which can be broken down into:The 68 bytes is the
calldata
:0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001
.