0

This is a simple storage contract:

contract SimpleStorage {
    uint public data;

    function set(uint x) public {
        data = x;
    }
}

The ABI is:

[
    {
        "constant": false,
        "inputs": [
            {
                "name": "x",
                "type": "uint256"
            }
        ],
        "name": "set",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "data",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
]

The function signatures is:

{
    "73d4a13a": "data()",
    "60fe47b1": "set(uint256)"
}

I know how to compute the function signatures. My question is if I have only a contract ABI and I want to get function signature from the ABI, what is a good way to implement it? What library can I use?

  • What do you actually want to do? Please describe your use case. If you want to call a Solidity function from JavaScript or query a value then you should look at web3.js. It's rare that you need to work with low level function signatures directly. – SCBuergel.eth Feb 12 '18 at 7:44
  • A function selector is the first 4 bytes of the function signature (e.g. "set(uint256)"). The function signature is the name of the function, followed by the parameter types, comma separated, enclosed in parentheses. That's pretty straightforward to derive from the ABI JSON. But if you're using a library, like web3.js, web3.py, the library can just do this for you. – user19510 Feb 12 '18 at 8:20
  • As I said, I know how to compute the function signatures, and I know how to use web3. What I want to do is to get the function signatures "directly form ABI through a program". – Anderson Feb 13 '18 at 3:55
1

I already has some working code samples for a dummy smart contract. No doubt you can adapt them fairly easily to your case.

Here is my dummy smart contract:

pragma solidity ^0.4.18;

contract AdditionContract {
  uint public state = 0;

  function add(uint value1, uint value2) public {
    state = value1 + value2;
  }

  function getState() public constant returns (uint) {
      return state;
  }
}

and some python code to parse the abi and compute your function selectors (compile your smart contract with truffle to create the abi, or with solcjs)

### parse your abi from truffle
import json

truffleFile = json.load(open('/path/to/your/truffle/workspace' + '/build/contracts/AdditionContract.json'))
abi = truffleFile['abi']

functionSelector = []
for fields in abi:
    if(fields['type'] == 'function'):
        functionName = fields['name']
        print(functionName)
        functionInputs = []
        for inputs in fields['inputs']:
            functionInputs.append(inputs['type'])
            print(inputs)
        functionSelector.append([functionName, functionInputs])

print(functionSelector)

### prepare the data field of the transaction
# function selector and argument encoding
# https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding

import web3 # Release 4.0.0-beta.9
w3 = web3.Web3()

value1, value2 = 10, 32 # your input value here
function = 'add(uint256,uint256)'
methodId = w3.sha3(text=function)[0:4].hex()
param1 = (value1).to_bytes(32, byteorder='big').hex()
param2 = (value2).to_bytes(32, byteorder='big').hex()
data = '0x' + methodId + param1 + param2

print(data)

### example of transaction dict
transaction_dict = {'from':myAddress,
                    'to':myContractAddress,
                    'chainId':CHAINID,
                    'gasPrice':myGasPrice,
                    'nonce':myNonce,
                    'data':data}

terminal prints :

getState
add
{'name': 'value1', 'type': 'uint256'}
{'name': 'value2', 'type': 'uint256'}
state
[['getState', []], ['add', ['uint256', 'uint256']], ['state', []]]

0x771602f7000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000020

if you want rock solid parsing I suggest that you give a look at the web3py source code (or web3js).

UPDATE

I don't know how much you know about python so I give you the way to build "add(uint256,uint256)" from the code above. But please also spend some time trying as this is fairly straightforward...

for functions in functionSelector:
    functionName = functions[0]
    functionType = functions[1]
    s = functionName + '('
    for i in range(len(functionType)):
        s += functionType[i]
        if(i+1 < len(functionType)):
            s += ','
    s += ')'
    print(s)

prints:

getState()
add(uint256,uint256)
state()
| improve this answer | |
  • Thank you! Is is possible to get "add(uint256,uint256)" from ABI? – Anderson Feb 13 '18 at 3:49
  • I've edited my post to answer your question – salanfe Feb 13 '18 at 8:27
  • Does the term "dummy smart contract" remind anyone else of the term "very stable genius?" – WBT Feb 20 at 19:00
0

Using JavaScript, the following example will give an output similar to the one in your question:

const ABI = [
    {
        "constant": false,
        "inputs": [
            {
                "name": "x",
                "type": "uint256"
            }
        ],
        "name": "set",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "data",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
]

// Concatenate function name with its param types
const prepareData = e => `${e.name}(${e.inputs.map(e => e.type)})`

// Encode function selector (assume web3 is globally available)
const encodeSelector = f => web3.sha3(f).slice(0,10)

// Parse ABI and encode its functions
const output = ABI
    .filter(e => e.type === "function")
    .flatMap(e => `${encodeSelector(prepareData(e))}: ${prepareData(e)}`)

console.log(output)

This should work with any ABI and any number of function params or types, it is easy to extend to also encode constructor if needed.

| improve this answer | |
0

This question was asked a while ago, perhaps before the rich libraries were in the scene. I found the web3-eth-abi package to be perfect. Since the ABI is a JSON file, there will be a bit of parsing. For this script let's assume the variable you get from the JSON is the hardcoded string:

const Web3EthAbi = require('web3-eth-abi');
let encodedFunctionSignature = Web3EthAbi.encodeFunctionSignature('adopt(uint256)');
| improve this answer | |
New contributor
mikeDOTexe is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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