0

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!

1 Answer 1

3

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));
}
6
  • I'm pretty new to solidity (as you can see) but I fully understood your explanation and the article (thanks for that), but when I apply the first option you gave I get these errors: Index range access is only supported for dynamic calldata arrays The first argument to "abi.decode" must be implicitly convertible to bytes memory or bytes calldata, but is of type bytes memory slice And when I use the second option, I get the same long number: 21923370962747092222049241656982978670225693601166209560647359697270644815409 I'm using ^0.8.0 btw
    – dNyrM
    Aug 12, 2021 at 20:17
  • As a follow-up question, if I may, how did you know that the signature of that Method ID was balanceOf(address) without having the full hex?
    – dNyrM
    Aug 12, 2021 at 21:47
  • I updated my answer, it should work properly now. 0x70a08231 is a common function selector and a quick Google search results in balanceOf(address).
    – Morten
    Aug 13, 2021 at 9:12
  • Still the issue though. On the first option, it doesn't matter how I pass data to getBalance, I always get an error of the sort of Invalid type for argument in function call. Invalid implicit conversion from literal_string.... I tried passing it like "0x70a....", 0x70a..., hex"70a...". It only works when a change calldata to memory on the function signature, but I get the same weird long number: 21923419280131834915887268958100430612526877572263439172946489084502927749168
    – dNyrM
    Aug 13, 2021 at 10:26
  • As for the second option, I get a different weird long number this time: 225558253637158116798355606682701651365356856565
    – dNyrM
    Aug 13, 2021 at 10:28

Your Answer

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

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