0

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?

1 Answer 1

1

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.

2
  • Thank you! Any ideas on how I can do this with bytes memory? without using calldata
    – Jason
    Commented Feb 7, 2023 at 2:18
  • You could possibly pass memory params to a function that defines call data inputs, as demonstrated by the following SE answer: ethereum.stackexchange.com/a/103543/51644 Commented Feb 7, 2023 at 4:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.