Glider Cheatsheet

This cheatsheet brings together a collection of Glider query code snippets, designed to help you write queries more effectively without starting from scratch.

Identify the function from an instruction

Problem:

I want to find the function an Instruction belongs to.

Solution:

def query():
    # If you have an instruction and want to find a function
    instruction = Instructions().exec(1)
    function = instruction.get_parent()

    return function

Check if a variable comes from a function argument

Problem

Given a VarValue, I want to see if the VarValue comes from a function argument.

This type of query is helpful when you want to see if a variable comes from user-input.

Solution

def query():
    # The find_var_value() function is used for demo purposes. VarValues are the only components in Glider that can be sourced from a function argument.
    var_value = find_var_value()
 
    # Here we check if a VarValue comes from a function argument. 
    is_function_argument = isinstance(var_value.get_object_of_var(), ArgumentVariable)

    # If true, the VarValue comes from a function argument. If false, the VarValue doesn't come from a function argument.
    print(is_function_argument)
 
     # For now we don't return any results, but based on the is_function_argument variable above you can choose to keep or remove results.
    return []


# Function is used for demo purposes.
def get_components_recursive(component):
    components = []

    try:
        # Since we are dealing with a call, we get the call arguments as components
        if isinstance(component, Call):
            components = component.get_args()
        else:
            # Get components within components
            components = component.get_components()
    except Exception:
        # This handles cases where the component can't be broken down further
        None

    results = []

    for comp in components:
        results.append(comp)
        for sub in get_components_recursive(comp):
            results.append(sub)
    
    return results


# This function is used for demo purposes only.
def find_var_value():
    # Get some instructions for demo purposes
    instructions = Instructions().exec(10)
 
    # Get components for demo purposes
    components = get_components_recursive(instructions[1])

    var_values = []

    # Iterate through components for demo purposes
    for component in components:
        # Collect VarValues from the components for demo purposes
        if isinstance(component, VarValue):
            var_values.append(component)


    # In Glider, the VarValue represents a value that could come from a function argument.
    if len(var_values):
        return var_values[0]

    return []

Check if require or assert statement is called inside a function

Problem #1

I need to know if a require or assert statement is made inside a function.

Solution #1

def query():
    # The function variable represents a function we are querying
    functions = Functions().exec(100)

    # We can pass has_guard_check into a filter to filter out results.
    functions_with_guard_checks = functions.filter(
        lambda function : 
        any(function.instructions().exec().filter(has_guard_check))
    )

    return functions_with_guard_checks
 
 
# The has_guard_check function can be used to filter out if a function has a require/assert statement.
def has_guard_check(instruction):
    # This will retrieve all of the calls made in the instruction
    callee_names = instruction.callee_names()
    # Checks if require or assert are called in the Instruction.
    return "require" in callee_names or "assert" in callee_names

Problem #2

I want to know if the Instruction I'm working with is a require or assert statement.

Solution #2

def query():
    # The function variable represents a function we are querying
    function = Functions().exec(1)[0]

    # Find some instructions for demo purposes
    instructions = function.instructions().exec()

    # We can pass has_guard_check into a filter to filter out results.
    instructions_with_guard_checks = instructions.filter(has_guard_check)

    return instructions_with_guard_checks
 
 
# The has_guard_check function can be used to filter out if a function has a require/assert statement.
def has_guard_check(instruction):
    # This will retrieve all of the calls made in the instruction
    callee_names = instruction.callee_names()
    # Checks if require or assert are called in the Instruction.
    return "require" in callee_names or "assert" in callee_names

Check if a function is called in another function

Problem

I need to find the functions that call a particular function, where the only information I have is the name of the function being called.

Solution

def query():
    # If we want to find functions that call deposit(), we first set the function_name to deposit.
    function_name = "deposit"

    # Now we search for deposit functions.
    functions = Functions().with_name(function_name).exec(5)

    # By calling caller_functions(), we can find all of the functions that call deposit()
    functions_that_call_deposit = functions.caller_functions().exec()

    return functions_that_call_deposit

Filter out interface functions

Problem

I want to remove interface functions from my results.

Solution

def query():
    # Find some functions for demo purposes
    functions = Functions().exec(10)

    # Identify impl functions via filtering with the is_implementation_function function
    implementation_functions = functions.filter(is_implementation_function)

    return implementation_functions


# This function checks if a function is implemented and not just a function defined in an interface.
def is_implementation_function(function):
    # We can determine if a function is implemented or not by if it has instructions. If a function has instructions, we know it has code.
    return any(function.instructions().exec())

Get all variables used in an instruction

Problem

I want to find all of the variables and components in a given Instruction.

Solution

def query():
    # Find some instructions for demo purposes
    instructions = Instructions().exec(100)
 
    # Iterate through instructions for demo purposes
    for inst in instructions:
        # To get all of the components inside an Instruction, we can use the get_components_recursive function to get all components inside an Instruction
        components = get_components_recursive(inst)   
        
        # Now we can work with the components variable like iterating, filtering, etc.    
 
    return []


# This function accepts a component as an argument whether that's an Instruction or another component. The function returns an array of sub-components.
def get_components_recursive(component):
    components = []

    try:
        # Get components of an IndexAccess
        if "IndexAccess" in str(component): 
            components.append(component.get_sequence()) 
            components.append(component.get_index())

        # If we are dealing with a call, we get the call arguments as components
        if isinstance(component, Call):
            components = component.get_args()
            call_qualifier = component.get_call_qualifier()

            # Get components of an IndexAccess
            if "IndexAccess" in str(call_qualifier): 
                components.append(call_qualifier)
                components.append(call_qualifier.get_sequence()) 
                components.append(call_qualifier.get_index())
        else:
            # Get components within components
            components = component.get_components()
    except Exception:
        # This handles cases where the component can't be broken down further
        None

    results = []

    for comp in components:
        results.append(comp)
        for sub_comp in get_components_recursive(comp):
            results.append(sub_comp)
    
    return results

Identify state variables in a contract

Problem

I want to find every state variable for a contract.

Solution

def query():
    # Find contracts for demo purposes
    contracts = Contracts().with_name("UniswapV3Pool").exec(1)

    contract = contracts[0]

    # To get state variables of a contract, we can call state_variables().exec() against a contract
    state_variables = contract.state_variables().exec()

    # Print the state variable names for convenience
    print(state_variables.name)

    return state_variables

Identify instructions doing arithmetic

Problem

I want to know if a given Instruction contains math arthimetic.

Solution

def query():
    return Instructions().exec(1000).filter(does_arithmetic)


# This function checks if a given instruction does arithmetic.
def does_arithmetic(instruction):
    solidity_arithmetic = ["-", "+", "/", "*", "**", "%", "++", "--", "+=", "-=", "*=", "/=", "%="]
    components = get_components_recursive(instruction)
    
    for component in components:
        if "Operator" in str(component):
            if component.expression in solidity_arithmetic:
                return True
            
    return False
    
    
# This function finds all components within a given instruction and/or component.    
def get_components_recursive(component):
    components = []

    try:
        # Since we are dealing with a call, we get the call arguments as components
        if isinstance(component, Call):
            components = component.get_args()
        else:
            # Get components within components
            components = component.get_components()
    except Exception:
        # This handles cases where the component can't be broken down further
        None

    results = []

    for comp in components:
        results.append(comp)
        for sub_comp in get_components_recursive(comp):
            results.append(sub_comp)
    
    return results    

Identify functions that receives or send ETH

Problem

I want to know if a function receives or sends ETH.

Solution

def query():
    return Functions().exec(10000).filter(calls_other_contract).filter(can_receive_eth)
    
    
# This function is used to identify if a function makes a low-level external call to another contract.
def calls_other_contract(function):
    transfers_eth = function.instructions().low_level_external_calls().exec().filter(sends_eth_in_transfer)

    return any(transfers_eth)


# This function checks if a low-level external call instruction sends ETH to another EOA/contract
def sends_eth_in_transfer(instruction):
    if instruction.get_value():
        for call in instruction.get_value().get_callee_values():
            if call.name == "call" and len(call.get_call_value()) > 0:
                return True

    return False


# This function checks if a function is payable and can receive ETH
def can_receive_eth(function):
    return function.is_payable()  

Find functions without a modifier

Problem

I want to find functions that don't call onlyOwner.

Solution

def query():
    return (
        Functions()
        .without_modifier_name("onlyOwner")
        .exec(10)
    )

Check if a function has a given argument by type

Problem

I want to determine if a function has an argument type like address, uint256, etc.

Solution

def query():
    return (
        Functions()
        .exec(10)
        .filter(has_address_argument)
    )

# Returns true when the function has an address argument
def has_address_argument(function):
    return "address" in function.arguments().list().get_variable().type.name

Check for msg.sender validations

Problem

I want to check if a function does any msg.sender validations.

Solution

def query():
    return (
        Functions()
        .exec(100)
        .filter(missing_msg_sender_validations)
    ) 
 

# Checks if a given function is missing msg.sender validations
def missing_msg_sender_validations(func):
    # instructions() is temporary and in reality we should use instructions_recursive().
    instructions = func.instructions().with_one_of_callee_names(["require", "assert"]).exec()
    if not any(instructions):
        return True

    for inst in instructions:
        if calls_msg_sender(get_components_recursive(inst)):
            return False 

    return True
 

# This function accepts a component as an argument whether that's an Instruction or another component. The function returns an array of sub-components.
def get_components_recursive(component):
    components = []

    try:
        # Get components of an IndexAccess
        if "IndexAccess" in str(component): 
            components.append(component.get_sequence()) 
            components.append(component.get_index())

        # If we are dealing with a call, we get the call arguments as components
        if isinstance(component, Call):
            components = component.get_args()
            call_qualifier = component.get_call_qualifier()

            # Get components of an IndexAccess
            if "IndexAccess" in str(call_qualifier): 
                components.append(call_qualifier)
                components.append(call_qualifier.get_sequence()) 
                components.append(call_qualifier.get_index())
        else:
            # Get components within components
            components = component.get_components()
    except Exception:
        # This handles cases where the component can't be broken down further
        None

    results = []

    for comp in components:
        results.append(comp)
        for sub_comp in get_components_recursive(comp):
            results.append(sub_comp)
    
    return results


# Checks if a given list of components contains a call to msg.sender
def calls_msg_sender(values):
    # Common msg sender functions
    msg_sender_calls = [
        "msg.sender",
        "msgSender",
        "_msgSender",
        "msgSender()",
        "_msgSender()"
    ]

    # Checks if any of the components contain a call to msg.sender.
    return any(value.expression in msg_sender_calls for value in values) 

Last updated