Crypto Flexs
  • DIRECTORY
  • CRYPTO
    • ETHEREUM
    • BITCOIN
    • ALTCOIN
  • BLOCKCHAIN
  • EXCHANGE
  • TRADING
  • SUBMIT
Crypto Flexs
  • DIRECTORY
  • CRYPTO
    • ETHEREUM
    • BITCOIN
    • ALTCOIN
  • BLOCKCHAIN
  • EXCHANGE
  • TRADING
  • SUBMIT
Crypto Flexs
Home»HACKING NEWS»Mastering Wake Printers for Solidity Security Analysis
HACKING NEWS

Mastering Wake Printers for Solidity Security Analysis

By Crypto FlexsNovember 12, 202510 Mins Read
Facebook Twitter Pinterest LinkedIn Tumblr Email
Mastering Wake Printers for Solidity Security Analysis
Share
Facebook Twitter LinkedIn Pinterest Email

introduction

Manually reviewing Solidity code is slow and error-prone. A single overlooked feature can hide costly vulnerabilities. Wake’s printer system automates the search for these dangerous patterns, turning hours of manual review into fast, reliable scans.

Wake Printer combines the simplicity of Python with Wake’s intermediate representation (IR), turning complex static analysis into simple scripts that highlight things like unrestricted withdrawals or missing access controls. This guide walks you through creating a custom printer that highlights security-related patterns in smart contracts.

Prerequisites and setup

This tutorial uses the Workshop repository as an example project.

git clone https://github.com/Ackee-Blockchain/2025-workshop-fuzzing
cd 2025-workshop-fuzzing
npm install

Before continuing, make sure Wake compiles your project successfully by running:

wake up

Understanding Wake Printers

Wake comes with several built-in printers that show different types of analysis. You can list them using:

wake print

Launches a specific printer by name.

wake print storage-layout
Storage layout output

The built-in printer demonstrates the capabilities of the system, but the real power comes from creating a custom printer tailored to your security analysis requirements. Once you understand how the built-in printer works, you’ll see how easy it is to extend Wake using your own analysis tools. By the end of this guide, you will know how to create a printer that detects vulnerability patterns related to your auditing approach.

Tutorial 1: Creating your first printer – listing contracts

Let’s start with a simple printer that lists all the contracts in a project. This example introduces key concepts that will be used in more complex analyses.

Creating the printer structure

To scaffold your first printer, run the following command:

wake up printer list-contracts

Wake creates a new printer directory and startup file with the following structure:

  • printers/ Directory for all custom printers
  • list-contracts.py With basic printer structure

Understanding Templates

The generated template provides the following starting structure:

from __future__ import annotations

import networkx as nx
import rich_click as click
import wake.ir as ir
import wake.ir.types as types
from rich import print
from wake.cli import SolidityName
from wake.printers import Printer, printer


class ListContractsPrinter(Printer):
    def print(self) -> None:
        pass

    @printer.command(name="list-contracts")
    def cli(self) -> None:
        pass

Here’s what each part of the template does:

  • print(): Main execution method in which analysis results are displayed
  • cli(): Command line interface handler for user-defined arguments

Visitor pattern implementation

Wake uses the Visitor pattern to traverse the abstract syntax tree (AST) of the contract. The Visitor pattern allows Wake to automatically navigate your code structure and react to specific elements, such as contracts or function definitions.

to list contracts visit_contract_definition A method called for each contract in the codebase.

this way ListContractsPrinter class:

def visit_contract_definition(self, node: ir.ContractDefinition) -> None:
    print(node.name)

Test your printer.

wake print list-contracts

This command runs the printer and prints all contract names found in the project.

Improved output

The default implementation displays all contracts, including interfaces and inherited contracts. Let’s improve this to only show deployable contracts.

from __future__ import annotations

import networkx as nx
import rich_click as click
import wake.ir as ir
import wake.ir.types as types
from rich import print
from wake.cli import SolidityName
from wake.printers import Printer, printer


class ListContractsPrinter(Printer):

    def visit_contract_definition(self, node: ir.ContractDefinition) -> None:
        print(node.name)

    def print(self) -> None:
        pass

    @printer.command(name="list-contracts")
    def cli(self) -> None:
        pass

Currently the printer lists all contracts, including interfaces and base classes. Let’s improve this to only show deployable items.

Filter deployable contracts

Add conditions to filter interfaces, libraries, and default contracts. This will help you identify contracts that are actually deployable.

def visit_contract_definition(self, node: ir.ContractDefinition) -> None:
    if len(node.child_contracts) != 0:
        return

    if node.kind != ir.enums.ContractKind.CONTRACT:
        return

    print(node.name)

that contract definition The class contains properties that can be used to filter results. For full reference, see https://ackee.xyz/wake/docs/latest/api-reference/ir/declarations/contract-definition/.

complete implementation

Here’s the final version, properly separating the issues of collecting data and displaying it during navigation. print() method:

from __future__ import annotations

import networkx as nx
import rich_click as click
import wake.ir as ir
import wake.ir.types as types
from rich import print
from wake.cli import SolidityName
from wake.printers import Printer, printer


class ListContractsPrinter(Printer):
    contracts: list(ir.ContractDefinition)

    def __init__(self):
        self.contracts = ()

    def visit_contract_definition(self, node: ir.ContractDefinition) -> None:
        if len(node.child_contracts) != 0:
            return

        if node.kind != ir.enums.ContractKind.CONTRACT:
            return

        self.contracts.append(node)

    def print(self) -> None:
        for contract in self.contracts:
            print(contract.name)

    @printer.command(name="list-contracts")
    def cli(self) -> None:
        pass

I just created my first printer. Collect and print deployable contracts, the first step toward automated contract mapping.

Tutorial 2: Analyzing contract functionality

Understanding which functions can be called externally is very important for security. A public ‘revoke’ or ‘transfer’ function often defines the attack surface of a contract. Let’s create a printer that maps the attack surface by listing all public and external functions.

Function Printer Settings

Create a new printer.

wake up printer list-functions

Execution Strategy

Now let’s extend the printer to map the external attack surface of each contract. Our goal: List only the final public/external functions callable for each deployable contract, excluding interfaces and overridden functions.

while we can use it visit_function_definition If you want to iterate through all the functionality, grouping them by contract will provide better context. we will use visit_contract_definition and access functions It is caused by

Start by collecting all your contracts.

class ListFunctionsPrinter(Printer):

    contracts: list(ir.ContractDefinition) = ()

    def visit_contract_definition(self, node: ir.ContractDefinition) -> None:
        self.contracts.append(node)

Inheritance hierarchy handling

at print() Use the method to traverse the inheritance hierarchy from the base contract to the derived contract, displaying the callable functions at each level.

   def print(self) -> None:
        for node in self.contracts:

            # Skip if not a contract (interface, library)
            if node.kind != ir.enums.ContractKind.CONTRACT:
                continue

            #Process leaf contracts only
            if len(node.child_contracts) !=0:
                continue

            # Print the inheritance hierarchy (from base to derived)
            for base_contract in reversed(node.linearized_base_contracts):
                print(f"Contract: base_contract.name")

                functions = self.get_callable_final_functions(base_contract)

                if len(functions) > 0:
                    print("Functions:")
                    for function in functions:
                        print(f"  function.name")
            print("--------------------")

Attack surface feature filtering

that get_callable_final_functions A helper method identifies a function that can actually be called by an external actor. Ensure that the function is the final implementation (not overridden by subcontracts) and has public or external visibility. This is an important feature for security analysis because it represents the actual attack surface of a contract.

    def get_callable_final_functions(self, contract: ir.ContractDefinition) -> list(ir.FunctionDefinition):
        return (
            func for func in contract.functions
            if len(func.child_functions) == 0  # Is final implementation
            and func.visibility in (ir.enums.Visibility.PUBLIC, ir.enums.Visibility.EXTERNAL)
        )

Functions Printer execution

Run the printer to see the inheritance hierarchy and callable functions.

wake print list-functions

calculation:

Contract: Context
Contract: Ownable
Functions:
  owner
  renounceOwnership
  transferOwnership
Contract: SingleTokenVault
Functions:
  constructor
  deposit
  withdraw
  emergencyWithdraw
  balanceOf
  setDepositLimits
--------------------
Contract: EIP712Example
Functions:
  constructor
  DOMAIN_SEPARATOR
  castVoteBySignature
  getVoteCounts
--------------------
Contract: Context
Contract: IERC20
Contract: IERC20Metadata
Contract: IERC20Errors
Contract: ERC20
Functions:
  name
  symbol
  decimals
  totalSupply
  balanceOf
  transfer
  allowance
  approve
  transferFrom
Contract: IERC20Permit
Contract: IERC5267
Contract: EIP712
Functions:
  eip712Domain
Contract: Nonces
Contract: ERC20Permit
Functions:
  permit
  nonces
  DOMAIN_SEPARATOR
Contract: PermitToken
Functions:
  constructor
--------------------
Contract: Token
Functions:
  constructor
  mintTokens
  transfer
  transferWithBytes
  getBalance
--------------------
Contract: Context
Contract: IERC20
Contract: IERC20Metadata
Contract: IERC20Errors
Contract: ERC20
Functions:
  name
  symbol
  decimals
  totalSupply
  balanceOf
  transfer
  allowance
  approve
  transferFrom
Contract: MockERC20
Functions:
  constructor
--------------------

The output provides a quick visual map of each contract’s inheritance and callable entry points.

Tutorial 3: Adding command line options

Practical analysis often requires a focus on specific contracts. Let’s improve the printer to accept command line arguments so that we can target analysis for individual contracts.

Understanding CLI Integration

Wake printers can accept command line options via: @click.option Decorator. This allows dynamic analysis based on user input. we are --contract-name Option to filter results for specific contracts.

Option Implementation

First add a class member to store the contract name, then @click.option To capture command line arguments:

@printer.command(name="list-functions")
@click.option("--contract-name", type=str, required=False)
def cli(self, contract_name: str | None) -> None:
    self.contract_name = contract_name

Conditional filtering logic

that print() Now the method checks if a specific contract has been requested. If no contract name is provided, the printer lists all deployable contracts. Once a name is specified, it will only drill into the hierarchy of that contract, even if it is not a leaf contract.

Complete implementation with CLI option

The final printers with optional contract filtering built-in are:

from __future__ import annotations

import networkx as nx
import rich_click as click
import wake.ir as ir
import wake.ir.types as types
from rich import print
from wake.cli import SolidityName
from wake.printers import Printer, printer


class ListFunctionsPrinter(Printer):

    contracts: list(ir.ContractDefinition) = ()
    contract_name: str | None = None


    def get_callable_final_functions(self, contract: ir.ContractDefinition) -> list(ir.FunctionDefinition):
        return (
            func for func in contract.functions
            if len(func.child_functions) == 0  # Is final implementatione
            and func.visibility in (ir.enums.Visibility.PUBLIC, ir.enums.Visibility.EXTERNAL)
        )

    def visit_contract_definition(self, node: ir.ContractDefinition) -> None:
        self.contracts.append(node)


    def print(self) -> None:
        for node in self.contracts:
            # If contract name is specified, only process that contract
            if self.contract_name is not None and node.name != self.contract_name:
                continue

            # Skip if not a contract (e.g., interface, library)
            if node.kind != ir.enums.ContractKind.CONTRACT:
                continue

            # If no contract name specified, only process leaf contracts
            if self.contract_name is None and len(node.child_contracts) != 0:
                continue

            # Print the inheritance hierarchy (from base to derived)
            for base_contract in reversed(node.linearized_base_contracts):
                print(f"Contract: base_contract.name")

                functions = self.get_callable_final_functions(base_contract)

                if len(functions) > 0:
                    print("Functions:")
                    for function in functions:
                        print(f"  function.name")
            print("--------------------")

    @printer.command(name="list-functions")
    @click.option("--contract-name", type=str, required=False)
    def cli(self, contract_name: str | None) -> None:
        self.contract_name = contract_name
        pass

Printers can now analyze specific contracts as needed. This is a feature that makes targeted audits fast and repeatable.

Use advanced printers

You can now analyze specific contracts.

# Analyze all deployable contracts
wake print list-functions

# Focus on a specific contract
wake print list-functions --contract-name Token

Practical Applications for Security Audits

Using these basic techniques, you can create a printer that visualizes and analyzes your codebase structure. Custom printers allow you to quickly visualize key code relationships. It doesn’t detect vulnerabilities directly, but shows patterns to guide manual review.

Analysis patterns useful for visualization

As you become more comfortable with creating printers, try using these advanced patterns to visualize complex security relationships.

Access Control Mapping: Creates a printer that lists all state change functions along with their access modifiers. This overview will help you quickly identify features that require additional protection.

Call flow visualization: Figure out which contract calls which function. Understanding these relationships helps identify potential attack vectors and prioritize audit focus.

How to use state variables: Tracks how storage variables are accessed throughout the function. This analysis helps identify complex state dependencies that require closer investigation.

inheritance hierarchy: Visualize the entire inheritance tree of a contract. Complex inheritance can hide function implementations and produce unexpected behavior.

Building an analysis toolkit

Start small. Build a printer that solves your immediate needs. Each adds to your personal toolkit. Over time, you will develop reusable scripts that will allow you to perform all your audits faster.

The flexibility of the Wake printer system means that the analysis tools can be applied to a variety of audit scenarios. Whether mapping upgrade patterns, visualizing DeFi protocol interactions, or understanding storage layouts, custom printers transform manual code reading time into seconds of automated analysis and visualization.

next steps

The printer provides maps. Detectors find vulnerabilities. Together, they transform Solidity audits from a manual task to a structured and insightful process. Every printer you write makes complex code clearer and makes smart contracts more secure for review.

For vulnerability detection, Wake provides a separate detection system that goes beyond visualization to identify actual security issues. The printer provides maps. The detector finds the problem.

Donate your printer back to your community. Analysis tools are most powerful when shared, and custom printers can help other auditors understand complex codebases more efficiently.

For advanced topics and full API reference, visit the Wake Static Analysis documentation.

You can also read our beginner’s guide to manually guided fuzzing.

Share. Facebook Twitter Pinterest LinkedIn Tumblr Email

Related Posts

Cryptocurrency Inheritance Update: September 2025

November 10, 2025

Balancer’s $70 Million Breach Exposes DeFi’s Weak Foundation

November 8, 2025

Morpho Network (MORPHO) is experiencing a service outage as users are facing rendering issues.

November 6, 2025
Add A Comment

Comments are closed.

Recent Posts

Mastering Wake Printers for Solidity Security Analysis

November 12, 2025

Cardano Struggles For Breakout — Can EV2’s Sci-Fi Looter-Shooter Presale Steal The Spotlight?

November 12, 2025

EV2 Token Presale Launches As Funtico Targets Mainstream Gamers With ‘Earth Version 2’

November 12, 2025

MEXC Foundation And TRIV Launch F.I.R.E Scholarship To Empower Indonesia’s Next Generation Of Blockchain Innovators

November 12, 2025

MEXC Flip Fest Event Concludes With Over 200,000 Participants And 5 Million USDT In Rewards Distributed

November 12, 2025

The importance of education and awareness in improving public awareness of cryptocurrency

November 12, 2025

RISE Acquires BSX, A Perp DEX On Base, To Accelerate Development Of The First Integrated Orderbooks

November 11, 2025

Threshold Network Simplifies Bitcoin Onchain Access With Direct And Gasless TBTC Minting

November 11, 2025

Domino’s Pizza Partners With XMoney For Fiat And Crypto Payments

November 11, 2025

Phemex Introduces Refreshed Logo And Platform Design, Ushering In A New Brand Era

November 11, 2025

Tapbit Celebrates 4th Anniversary With Global Events, Zero-Fee Trading, And $1 Million Rewards

November 11, 2025

Crypto Flexs is a Professional Cryptocurrency News Platform. Here we will provide you only interesting content, which you will like very much. We’re dedicated to providing you the best of Cryptocurrency. We hope you enjoy our Cryptocurrency News as much as we enjoy offering them to you.

Contact Us : Partner(@)Cryptoflexs.com

Top Insights

Mastering Wake Printers for Solidity Security Analysis

November 12, 2025

Cardano Struggles For Breakout — Can EV2’s Sci-Fi Looter-Shooter Presale Steal The Spotlight?

November 12, 2025

EV2 Token Presale Launches As Funtico Targets Mainstream Gamers With ‘Earth Version 2’

November 12, 2025
Most Popular

Bonk Price Prediction: Top Analyst Warns BONK Collapse After 1000% Surge as Investors Turn to This Crypto Casino for Future Explosive Profits

December 10, 2023

Ethereum Price Consolidation Begins – Why Pullbacks Might Be Limited

March 11, 2024

Casper’s History – Chapter 1

March 28, 2024
  • Home
  • About Us
  • Contact Us
  • Disclaimer
  • Privacy Policy
  • Terms and Conditions
© 2025 Crypto Flexs

Type above and press Enter to search. Press Esc to cancel.