Use ABI to decode Ethereum Transaction input data to reduce gas free

When writing smart contracts, my previous habit was to record the data that needs to be queried in the event of the contract. Some of the fields of these events are input parameters of the method. Although the gas free of Ethereum log data is relatively small, the accumulation is considerable. After thinking about it, I set some rules for myself:

  1. The fields that need to be indexed, the intermediate results of the calculation, can be kept in the event
  2. DApp without background can reserve more fields in the event
  3. For DApps with complex functions (such as sub-account details), if you need to query large amounts of data multiple times, you can consider using the background to query the blockchain. At this time, there is no need to keep the function input parameters contained in the event, and the data can be restored through the input field of the transaction.

Take a transaction I sent as an example

{
  hash: '0xcc1c866186ff39555936ea007a63ead761aef80d4301eb4e0081e8fc8f6fe18d',
  nonce: 892,
  blockHash: '0xbfff2fc0dd268dfce90417a3ea3b5da3a9e59703d8d4ec6a5be3ba2dce59b924',
  blockNumber: 987,
  transactionIndex: 0,
  from: '0x40FB66078a2e688f83002930B7EbA981323d4bef',
  to: '0x2C71AC97716A17E66D7E524Cfeb28B97A3728250',
  value: '0',
  gas: 5000000,
  gasPrice: '10000000000',
  input: '0x70a1495c00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000003782dace9d900000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000056f70656e31000000000000000000000000000000000000000000000000000000',
  v: '0x1b',
  r: '0xbfbd3aef6c6777598847de0aa1ffcaf50470f785054771a54e2e274b89d1a633',
  s: '0x27aea35dd4d462598ac909b55444ec0131c7977fe2ad244eaac0cc28b70e07f1'
}

You can see a very long input field, this field 0x70a1495cstarts with, this is actually the function signature, and the following data is just splicing data by type. Let's look at the abi of this function

{
  constant: false,
  inputs: [
    { internalType: 'bytes', name: 'name', type: 'bytes' },
    { internalType: 'bool', name: 'isOpen', type: 'bool' },
    { internalType: 'bool', name: 'isCustom', type: 'bool' },
    { internalType: 'uint256', name: 'cusPrice', type: 'uint256' },
    { internalType: 'uint8', name: 'durationInYear', type: 'uint8' }
  ],
  name: 'registerRoot',
  outputs: [],
  payable: false,
  stateMutability: 'nonpayable',
  type: 'function',
  signature: '0x70a1495c'
}

You can see that the signature is also 0x70a1495c
how the signature is generated. It is actually very simple: it
web3.eth.abi.encodeFunctionSignature("registerRoot(bytes,bool,bool,uint256,uint8)")
is a short Hash. 0x70a1495cAfter removing it, we decode the remaining data:

web3.eth.abi.decodeParameters(["bytes","bool","bool","uint256","uint8"],"0x00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000003782dace9d900000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000056f70656e31000000000000000000000000000000000000000000000000000000")
Result {
  '0': '0x6f70656e31',
  '1': true,
  '2': true,
  '3': '4000000000000000000',
  '4': '1',

Finally, spell the field name again.
I wrote an analytical function, as follows:

async function decodeParamsOfTransaction(txHash, func_abi){
    var txData = await web3.eth.getTransaction(txHash);
    var input = txData.input;
    var types = func_abi.inputs.map(x=>x.internalType);
    var _d = "0x"+input.replace(func_abi.signature,"");
    var names = func_abi.inputs.map(x=>x.name);
    var r = web3.eth.abi.decodeParameters(types, _d);
    var dic = {}
    for(var i=0; i<names.length; i++){
        dic[names[i]] = r[i];
    }
    return dic
}

For example, the following results can be obtained:

{
  name: '0x6f70656e31',
  isOpen: true,
  isCustom: true,
  cusPrice: '4000000000000000000',
  durationInYear: '1'
}

Guess you like

Origin blog.csdn.net/weixin_39842528/article/details/108376628