I want to create an RPC call (study purpose) from my app using metamask.
My method on my contract is:
function sayHelloMyName(string memory _name) external pure returns (string memory) {
require(bytes(_name).length != 0, "insert your name");
return string(abi.encodePacked("hello ", _name));
}
its hash is:
$ web3.utils.keccak256("sayHelloMyName(string)").substr(0, 10)
> '0x10a7b27a'
I want to pass my name foo where the hex decimal is 0x666f6f
web3.utils.toHex('foo')
'0x666f6f'
So my call is:
ethereum
.request({
method: 'eth_call',
params: [
{
from: currentAccount,
to: contractAddress,
data: 0x10a7b27a0000000000000000000000000000000000000000000000000000000000666f6f
}, "latest"],
})
.then((txHash) => {
console.log(txHash);
$('#info').html(txHash);
})
.catch((error) => {
console.error;
$('#info').text(JSON.stringify(error.message));
});
where the data is the method signature, and my hex name and padding (total 32 bytes) Unfortunately, I get a revert of it.
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "execution reverted"
}
}
the code works, I can use it with web3 library.
Solidity string
is encoded as a dynamic-length array of bytes including the first 32byte slot pointing to the location of the array beginning and the second 32byte slot containing the length of the string. Meaning: Not just the hex value of the string that you're passing.
It works with web3js
because the JS library decodes the hex back to string (web3 assumes the input is hex as it starts with 0x
), and then encodes it correctly to the byte array while filling the data
field.
See output of this web3js
snippet
const data = web3.eth.abi.encodeFunctionCall({
name: 'sayHelloMyName',
type: 'function',
inputs: [{
type: 'string',
name: '_name'
}]
}, [
'foo',
]);
console.log(data);
that prints
# formatted for readability
0x10a7b27a
0000000000000000000000000000000000000000000000000000000000000020
0000000000000000000000000000000000000000000000000000000000000003
666f6f0000000000000000000000000000000000000000000000000000000000
Solution: This long value (without the newlines) is what you need to pass instead.