Learning Instructions
Last updated
Last updated
Instructions can be thought of as individual lines of code within a function. They can include anything from an if statement or a function call to a return statement.
Instructions are the building blocks of Solidity contracts and represent the operations that the EVM (Ethereum Virtual Machine) will execute. This is why we refer to them as instructions.
Let's start by running a simple query to find some instructions:
After running this query in the Glider IDE. You should find 10 instructions returned in the Output panel.
Now that we understand what instructions are, let's walk through our second foundational query in this series, a Glider query designed to look for Solidity instructions that call Solidity's famous transferFrom function. Before we break down the query, let's identify the query goal.
Find Solidity instructions that call the transferFrom() function - an ERC-20 function used to transfer tokens from one address to another.
Extract and inspect the arguments passed to each transferFrom() call.
The query can be found below:
In the first part of our query, we create an instance of the Instructions class:
By initializing this class, we gain access to a variety of Instruction API methods provided by Glider. These methods allow us to further filter and query instructions programmatically.
Next, we use the .with_callee_name() method, which allows us to locate instructions that contain function calls to transferFrom.
This method requires a single argument - the name of the function we want to search for. In our case, we pass "transferFrom" as a string:
Now that we’ve defined a query to search for instructions that call transferFrom, we need to execute it. To do this, we call the .exec() method, which instructs Glider to run the query and return 10 results:
The .exec() method accepts two optional arguments:
Limit – Specifies how many results Glider should return.
Offset (optional) – Defines where Glider should start the search (useful for pagination).
In our case, we pass in 10 which tells Glider to return the first 10 results. The offset argument is optional so for now we ignore it.
Now that we have our query results, we can extract additional info from our instructions. In this case, we want to analyze the arguments passed into the transferFrom function calls.
The .filter() method accepts either a named function or a lambda function. In our query, we pass a lambda function to filter():
Inside the lambda function, we have the following code:
Let’s break it down by ignoring print() for a moment and focusing on:
This expression retrieves the arguments passed to the transferFrom function from each instruction.
To extract the arguments passed into the transferFrom function, we call the following methods in sequence:
get_value() - Every instruction contains a value, which represents what the instruction is doing. There are different types of values. Since we are analyzing function calls, this method returns a value representing the transferFrom function call. We call a Call value.
get_args() - This method is called on the Call value returned by .get_value(). get_args() retrieves the list of arguments passed to the transferFrom function.
expression - This final call converts each argument into its source code representation, allowing us to see how the argument appears in Solidity.
When we check the final output, we see that the query returns an array representing the arguments passed into each transferFrom function call:
Glider IDE provides a useful Debug panel where we can print out query results for inspection. To take advantage of this feature, we use the standard print() function, which allows us to output any number of arguments directly to the Debug panel.
Since our query retrieves a list of function arguments, we can print them as follows:
In the final step, we return the query results so they can be displayed in the Glider IDE Output panel.
Since the query() function is expected to return a list, we ensure it returns our filtered instructions query results (represented as a list):
Now that we’ve reviewed the query, let’s run it in the Glider IDE.
Paste the following query into the Glider IDE, click "Run", and wait for the results:
Once the query completes, Glider returns a series of instructions, each containing:
The instruction source code
The contract address for every instruction
A printed list of transferFrom arguments from the results
Each instruction represents a call to the transferFrom function, and we can now view, in a structured and programmatic way, every argument that was passed into these function calls.
This demonstrates how Glider can efficiently and elegantly analyze function arguments within Solidity smart contracts.
For a full list of available Instructions methods, refer to the .
exec() returns a special type of list called . For now, we won’t focus on the differences between a Python List and APIList, as they won’t impact our use case in this series.
There are multiple ways to achieve this, but for this query, we use the provided by Glider.
We’ve previously discussed using filter to in an earlier section. Here, we’ll use filter again to iterate through our results.
In our query, the instruction variable represents a single instruction from the instructions list. Using the instruction variable, we can apply a to execute a series of methods in sequence.