Search code examples
web3jsrsk

How to query internal transactions for an RSK transaction?


If I have the transaction hash of an RSK transaction, how can I get its internal transactions - i.e. when the smart contracts invoke functions on other contracts or do RBTC transfers? I'm able to get the main transaction using web3.js, however once obtaining this, I'm unable to parse it to extract the internal transactions that occur. Another thing that I've tried was to use web3.js to query the block that the transaction occurred in, however was unable to parse this either to obtain internal transactions.


Solution

  • To reiterate my original comment:

    The RSK virtual machine (like the EVM) does not define "internal transaction", and hence there's no RPC to query them. You will need to "debug" the transaction execution in order to reconstruct these internals - which is quite difficult to do. Block explorers typically do this for you.

    Fortunately the RSK Block Explorer exposes an API, and thus is programmatically queryable. So while you won't be able to use web3.js for this, as you've asked for in your question, you will be able to get internal transactions nonetheless.

    Let's use an example, with the following transaction 0x01fbd670ea2455d38e83316129765376a693852eca296b3469f18d2a8dde35d8, which happens to have a lot of internal transactions.

    curl \
      -X GET \
      -H  "accept: application/json" \
      "https://backend.explorer.rsk.co/api?module=internalTransactions&action=getInternalTransactionsByTxHash&hash=0x01fbd670ea2455d38e83316129765376a693852eca296b3469f18d2a8dde35d8"
    

    The above command retrieves the internal transactions of this particular transaction. If you wish to do this for a different transaction, simply change the value of the hash query parameter in the request URL.

    This gives you a fairly large JSON response, which I will not copy in full here. You can then parse this using your JS code (since you're already using web3.js).

    On the command line, you can explore the data a bit more using the response filters available in the jq command line utility:

    curl \
      -X GET \
      -H  "accept: application/json" \
      "https://backend.explorer.rsk.co/api?module=internalTransactions&action=getInternalTransactionsByTxHash&hash=0x01fbd670ea2455d38e83316129765376a693852eca296b3469f18d2a8dde35d8" \
      | jq -c '.data[].action.callType'
    

    The above pipes the output of the curl command into jq which then applies a filter that:

    • looks at the data property, and returns all items in the array
    • within each item drills down into the action object, and returns its callType value

    This results in the following output:

    "delegatecall"
    "staticcall"
    "delegatecall"
    "staticcall"
    "delegatecall"
    "staticcall"
    "delegatecall"
    "staticcall"
    "delegatecall"
    "staticcall"
    "delegatecall"
    "staticcall"
    "delegatecall"
    "staticcall"
    "delegatecall"
    "staticcall"
    "delegatecall"
    "call"
    

    So this transaction contains 18 internal transactions, with a mix of delegatecall, staticcall, and call... a fairly complex transaction indeed!

    Now let's very the jq command to use a different filter, such that we gets the full details on only the final internal transaction, which happens to be the only call internal transaction:

    curl \
      -X GET \
      -H  "accept: application/json" \
      "https://backend.explorer.rsk.co/api?module=internalTransactions&action=getInternalTransactionsByTxHash&hash=0x01fbd670ea2455d38e83316129765376a693852eca296b3469f18d2a8dde35d8" \
      | jq -c '.data[17].action'
    

    Note that the only difference from the previous command is that now the filter is .data[17].action. This results in the following output:

    {
      "callType": "call",
      "from": "0x3f7ec3a190661db67c4907c839d8f1b0c18f2fc4",
      "to": "0xa288319ecb63301e21963e21ef3ca8fb720d2672",
      "gas": "0x20529",
      "input": "0xcbf83a040000000000000000000000000000000000000000000000000000000000000003425443555344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f36650548d5c400000000000000000000000000003f7ec3a190661db67c4907c839d8f1b0c18f2fc4000000000000000000000000000000000000000000000000000000000036430c000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000005d6328b4db96469d968348a852e6978d18b7dc9bda776727991b83f171abe4a4040ebab67dee8e9711683af91e05c3970bcb6a29502f9b35b14b7a9225d43f6e3e0cf4ae577be626ae350d8e103df88f55205167eaad7267fdbf247e4b35ec674457ac87e13451d2fa9985c854b2f84982e3b611c3b48f5045f2cdc3c6acff44d1735d2771581dc2cc7477fc846767ad088182fc317424d468477cf3a54724543000000000000000000000000000000000000000000000000000000000000000516a3d4cf7e73d17e2230c87f6ef48f38d82885c64d47fef646987f8d6fbb86405515760c786315cac84d7df048e2ba054868f2b9e2afeec0b63ebf2dcac59c8848f254382abf73cf6ce2d5134b5bc065c0706fb7a2f7886a15e79a8953ed11006c5a7d14b4fbf1bb6ff8d687a82a548dcdbd823ebec4b10e331bee332df1a7ae0e45fdac4f6648e093b90a6b56f33e31f36d4079526f871f51cafa710cdde4c3",
      "value": "0x0"
    }