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's a database of mappings from the functions to the function signatures - https://www.4byte.directory/. Note that the server has been returning 'Server Error (500)' intermittently.
Some further information about this service: Ethereum Function Signature Database - database of 4-Btye function signatures to their human readable counterparts.