Solidity – How to Decode abi.encodeWithSignature and Retrieve Encoded Values

abifoundrysolidity

I'm running Foundry and trying to decode the encoded signature, but I'm getting "EvmError: Revert" error when running the below code. It appears to be something I'm doing incorrectly with the abi.decode

uint256 internal constant TOKENS_IN_POOL = 1_000_000e18;
address payable internal attacker;
bytes memory approvePaylaod = abi.encodeWithSignature("approve(address,uint256)",address(attacker),TOKENS_IN_POOL);

address payable addressAttacker;
uint256 num;
(addressAttacker,num) = abi.decode(approvePaylaod, (address,uint256));

Is this the correct way to decode an encoded function signature?

Best Answer

Let's review the payload generated by calling abi.encodeWithSignature. It should contain the following:

[4-byte function selector] [32-byte zero-padded address] [32-byte uint256]

What's special about it is the 4-byte function selector at the beginning. In order to properly decode the payload, you will need to remove the first 4 bytes from it. You will need to use a library in order to be able to perform this on memory-based bytes (bytes memory). But for the sake of demonstration, I will show you how to do this on a calldata-based payload:

pragma solidity 0.8.x;

contract TestArray { 
    uint256 internal constant TOKENS_IN_POOL = 1_000_000e18;
    address internal attacker = 0xBAd0000000000000000000000000000000000Bad;

   function encode() public view returns(bytes memory) {
        bytes memory approvePaylaod = abi.encodeWithSignature("approve(address,uint256)",address(attacker),TOKENS_IN_POOL);
        return approvePaylaod;
   }

   function decode(bytes calldata approvePaylaod) public pure returns(address,uint256) {
        address addressAttacker;
        uint256 num;
        // `approvePaylaod[4:]` basically ignores the first 4 bytes of the payload
        (addressAttacker,num) = abi.decode(approvePaylaod[4:], (address,uint256));
        return (addressAttacker,num);
   }
}

Note that I'm using Solidity v0.8.x, since slicing calldata bytes is a feature that is not available for old versions of Solidity.

Related Topic