Lets says we have Contract A
that needs to call Contract B
at a certain address which the requirements that Contract A
doesn't know the exact parameter structure the function in that Contract B
needs & assumes the user will provide the correct parameters.
So far I have the following.
function callExternalContractWithPacked(address _contract, address _testAddr) external {
bytes memory arg = abi.encode(_testAddr);
(bool success, bytes memory data) = _contract.call(
abi.encodeWithSignature("setAddr(address)", arg)
);
emit Response(success, data);
}
While testing the abi.encode
theory I passed a test address into the function & encoded it using abi.encode
although there was a serious problem. Once the function ran & called the other contract, the address set on Contract B
was completely different from the address added to the function before encoding.
How can I properly pass a argument of bytes
into abi.encodeWithSignature
without the data becoming corrupt & incorrect than the desired input.
During my search I came across encodeFunctionCall :: Web3js but would like the same result within solidity. What are your thoughts?
Best Answer
Your problem is that you're using
abi.encode
withabi.encodeWithSignature
, and encoding your address twice.abi.encode
takes your address and pads it with zeros to make it 32 bytes long since EVM works with 32 bytes slots only.abi.encodeWithSignature
, on the other hand, takes the signature of the function you're calling, along with its arguments, and encodes them too.In your code, your encoded values look like this:
The first line
0xd1d80fdf
is the function signature. The next three lines represent your double encoded values.What you want is just:
Your address follows the function signature, padded with zeros to fit 32 bytes.
To fix the issue, use only
abi.encodeWithSignature
to encode the function signature and address, don't useabi.encode
before that.