Continuing yesterday’s article, today we’ll talk about the .instruction_data property of an Instruction. I find it very helpful when dealing with instructions, and I use it a lot. The property is quite complex, though; sometimes, it’s not very obvious how to process the information it gives.
instruction_data
The property contains all the low-level information about an instruction’s representation in Glider. This includes IRs, callees, operands, used variables, etc. It helps you visualize and compare several target instructions to abstract your processing logic.
Example
Alright, what can be better than a good sample of code!
Look at the glide below:
from glider import *
def query():
instructions = (
Contracts()
.mains()
.with_compiler_range("0.8.0", "0.9.0")
.functions()
.with_one_property([MethodProp.EXTERNAL, MethodProp.PUBLIC])
.instructions()
.external_calls()
.exec(1)
)
result = []
for instruction in instructions:
print(instruction.instruction_data)
return result
It returns the following JSON:
({
_key: "f10abbeb3ee6e58d99cf116c96ba861f",
_id: "instructions/f10abbeb3ee6e58d99cf116c96ba861f",
_rev: "_hiGMBwS--b",
node: "EXPRESSION erc20token.transferFrom(msg.sender,address(this),9000)",
id: 2,
type: "NodeType.EXPRESSION",
irs: [
{
ir: "TMP_57 = CONVERT this to address",
variables_read: [{ name: "this", canonical_name: "" }],
variables_written: { name: "TMP_57", canonical_name: "" },
contract_name: "",
},
{
ir: "TMP_58(bool) = HIGH_LEVEL_CALL, dest:erc20token(IERC20), function:transferFrom, arguments:['msg.sender', 'TMP_57', '9000']",
variables_read: [
{
name: "erc20token",
canonical_name:
"BlukSender.multisendToken(address,address[]).erc20token",
},
{ name: "msg.sender", canonical_name: "" },
{ name: "TMP_57", canonical_name: "" },
],
variables_written: { name: "TMP_58", canonical_name: "" },
contract_name: "IERC20",
signature: "transferFrom(address,address,uint256)",
args: [
{ name: "msg.sender", canonical_name: "" },
{ name: "TMP_57", canonical_name: "" },
{ name: "9000", canonical_name: "" },
],
},
],
from_asm: False,
is_cmp: False,
source_lines: [175],
start_column: 13,
end_column: 67,
callees: {
internal: [],
high_level: [
{
contract_name: "IERC20",
relative_filepath: "BlukSender.sol",
signature: "transferFrom(address,address,uint256)",
is_static: False,
contract_key: "contracts/281441a46084f0c67385777fd1a781b3",
},
],
library_calls: [],
low_level: [],
solidity: [],
},
dest: [],
operands: [
{
expression: "erc20token.transferFrom(msg.sender,address(this),9000)",
type: "call",
signature: "transferFrom(address,address,uint256)",
contract_name: "IERC20",
call_type: "normal_function",
args: [
{
var_type: { type: "elementary", name: "address" },
expression: "msg.sender",
type: "variable",
},
{
var_type: { type: "elementary", name: "address" },
expression: "this",
type: "variable",
},
{ expression: "9000", type: "constant_number" },
],
special_params: {},
call_qualifier: {
var_type: {
type: "contract",
name: "IERC20",
relative_filepath: "BlukSender.sol",
},
expression: "erc20token",
type: "variable",
},
},
],
variables_read: [
{
name: "erc20token",
canonical_name: "BlukSender.multisendToken(address,address[]).erc20token",
},
{ name: "this", canonical_name: "" },
{ name: "msg.sender", canonical_name: "" },
],
variables_written: [],
dominators: [1, 0, 2],
immediate_dominator: [1],
dominator_successors: [5],
dominance_frontier: [],
});
It’s quite lengthy, I know. Let’s make some sense out of it:
- Check out
nodeandtypeto understand what the instruction looks like and what type it has. callees,operands, anddestarrays contain data equal to the return values of the corresponding.get_*methods inInstruction(e.g.,.get_operands()).- Obviously,
variables_readandvariables_writtencontain the variables this instruction uses. irsdescribes the same instruction but in a more detailed way, step-by-step.
Once again,
.instruction_datais more suitable for debugging purposes, and I encourage you to avoid it in a production glide, but there are values you can’t get with the high-level methods yet.
Also, try to change the glide to something more precise, like getting all MerkleProof.verify() calls, and compare several .instruction_data side to side:

This will help you understand how to generalize your code for different contexts.