0

UPDATE: I figured it out though is doesn't entirely make sense.

When abi-encoding an "address" as an argument, you use "address" in the hash of the function signature, however you abi-encode the actual argument as if it were uint256, padding the address out with 0's. Or at least you need to do so when using curl POST to an RPC client (geth in my case)

It's odd because an address is really uint160 (and i've seen other libraries treat it as such) but that did't work for me...

If this makes no sense, there's more details below...

I have a deployed contact, built from solidity and deployed. For reasons too detailed to go into, I am using curl POST to call functions within the contract via an instance of geth. This means abi-encoding the function call. I am able to do this successfully for several functions in the contract, but when there is an address as an argument, it fails immediately with a "execution reverted".

I've tried lots of things, but always fails. Here's what I thought should work. the function in solidity is:

function mintWithTokenID(address to, uint256 theTokenID) public virtual { ...

which is compiled into

{
      "inputs": [
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "theTokenID",
          "type": "uint256"
        }
      ],
      "name": "mintWithTokenID",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },

So here's what I thought would work, but doesn't...

I want to do this (note that actual addresses are fake here...) mintWithTokenID('0x7b59C1447800000000c4D059ef3AD600000194F',7) Running the function from truffle works fine, but I need to do the curl POST method.

So... here's the abi encoding: web3.utils.sha3("mintWithTokenID(address,uint256)")
0xb9ae3621e688e2432b598dd4b1f33a482b375a14224e2ec6aa300bd16598e84a

so we need 0xb9ae3621 as the start, then the arguments are 7b59C1447800000000c4D059ef3AD600000194F and 0000000000000000000000000000000000000000000000000000000000000007

resulting in complete abi data: 0xb9ae36217E98D8b036B6A2Ef80770c87145Bd1609D1a25d70000000000000000000000000000000000000000000000000000000000000007

and my curl statement is:

curl localhost:8545 -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from": "0x7b59C1447800000000c4D059ef3AD600000194F", "to": "0x7b500000008E6242a525c4D059ef3AD6511bd194F", "data":"0xb9ae36217E98D8b036B6A2Ef80770c87145Bd1609D1a25d70000000000000000000000000000000000000000000000000000000000000007"},"latest"],"id":1} -H "Content-Type: application/json"

but when run, it immediately returns: {"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"execution reverted"}}

Any ideas? I've tried using uint160 instead of address, but documentation says address should be used in the function signature.

Thank you in advance!

1 Answer 1

1

How parameters in a call are encoded is defined in the Contract ABI Specification.

All fixed size types are first padded to 32 bytes. In you case you have:

  • address: be6fee3756f7be3a0cd492059341cb5b77dd81f9 => 000000000000000000000000be6fee3756f7be3a0cd492059341cb5b77dd81f9
  • unit256: 7 => 0000000000000000000000000000000000000000000000000000000000000007

If the call selector is 0xb9ae3621, then the call will be:

0xb9ae3621000000000000000000000000be6fee3756f7be3a0cd492059341cb5b77dd81f90000000000000000000000000000000000000000000000000000000000000007

One of the reasons to pad everything to 32 bytes is because the decoding code is much simpler and shorter. Decoding is done by the contract so shorter means less gas and cheaper transaction.

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.