Solidity – How to Decode Raw Data Using ABI Bytes in Solidity 0.8.x

abibytesdecodingsoliditysolidity-0.8.x

If I only have the raw input data of a contract call, what would be the best way to decode it into readable form within Solidity?

"[INPUT]":"0x70a08231000000000000000000000000278261c4545d65a81ec449945e83a236666b64f5"
"[OUTPUT]":"0x0000000000000000000000000000000000000000000000000000000000000000"
"gas":{
"gas_left":5052320
"gas_used":4814
"total_gas_used":4096237
}

I'm doing this but I get a weird number which I don't think it's the right answer:

bytes memory data = '0x70a08231000000000000000000000000278261c4545d65a81ec449945e83a236666b64f5'; 
(uint num) = abi.decode(data, (uint256));
console.log(num);
// 21923419280131834915887268958100430612526877572263439172946489084502927749168

If I change data to the following, I get:

hex'70a08231000000000000000000000000278261c4545d65a81ec449945e83a236666b64f5'
//50942633119752846454219349998365661925661254240480086959931673327308193899062

Thanks!

Best Answer

You have to remove the first four bytes first. The first four bytes of a contract call is the function selector, which specifies which function you want to call, in this case balanceOf(address). I wrote a more detailed explanation about transaction data, which you can find here.

Assuming you're using Solidity 0.6.0 or newer, you can use data[4:] to slice off the first four bytes of the input, or additionally just remove them from the input if you're hardcoding the data.

function getBalance(bytes calldata data) public pure returns (uint256 balance) {
  (balance) = abi.decode(data, (uint256));
}

// or

function getBalance() public pure returns (uint256 balance) {
  bytes memory data = hex'000000000000000000000000278261c4545d65a81ec449945e83a236666b64f5';
  (balance) = abi.decode(data, (uint256));
}