Get Started
Welcome to the introduction tutorial on how to use State Space. This tutorial is based on the OpenZeppelin ERC20 implementation and the Pausable feature. Read the test objective below, and follow the steps to understand how State Space works. Objective: Determine who should be able tomint()
tokens after the contract has been paused.
1
Open the ERC20 playground
Login or create your account hereFrom the “Home” menu, open the pre-loaded ERC20 Workbench project.
You will see a folder tree containing the ERC20 project and a canvas with a pre-designed transaction sequence.Expand the folder tree to view all the externally visable functions as components. These components can be dragged onto the canvas to create multi-contract test scenarios and transaction sequences (e.g. end-to-end flows, integration tests, etc).There are four types of components:Blue =
Purple =
Green =
Gray =

CALL
- function callPurple =
VIEW
- view functionGreen =
CREATE
- constructorGray =
DEPLOY
- a deployment script
2
Design a test scenario
The transaction sequence
Since the objective is to determine whether any EOA can mint tokens after the contract has been paused, we created a sequence of transactions that calls first deploys the contract, and then callspause()
and mint()
in succession:Deployment
→ constructor(...)
→ pause(...)
→ mint(...)
It should look like this:
Pause-->Mint Transaction Sequence
You can use your existing deployment scripts (if you have one in Foundry or Hardhat) to create custom deployment nodes for deeper testing.
Configure symbolic input parameters
State Space supports the use of both symbolic and concrete input values, or any combination thereof for both transaction values and function parameters.For values set to symbolic, State Space will automatically search for and generate structured dynamic inputs that will satisfy the conditions of the entire transaction sequence.What if we’re not sure what parameters to set? Rather than manually figuring out all combinations to test, we can use symbolic values to explore all possible inputs for any field.Let’s assume that Alice is the contract deployer andBob
is the initialOwner
. In our test setup, we configure the following:- Set the transaction
From
field for theconstructor()
function call toAlice
. - Set the
initialOwner
parameter in theconstructor()
toBob
. - Leave the transaction
From
field forpause()
set to symbolic to consider all EOAs preconfigured in the deployment (Alice
andBob
).

Configure deployment and mint() parameters
mint()
transaction:- We leave the transaction
From
field formint()
set to symbolic. Symbolic means it represents all possible EOAs (limited to the accounts configured in the deployment) rather than being fixed to a specific account (a concrete input). This allows State Space to autonomously discover which accounts can trigger unique execution paths. - We also leave the function parameters of
mint()
symbolic (to
andamount
), allowing State Space to explore all possible input values to determine which concrete inputs and conditions (if any) would result in a successful mint operation afterpause
has been called.

Final Parameter Configuration
3
Explore the state space
Select the icon to start exploring and generating the execution state space.State Space will autonomously explore code paths, automatically taking into consideration all multi-contract interactions for your test scenario. For each unique code path it discovers, it will generate the verified concrete input conditions that trigger their execution.Because State Space models the full EVM semantics, the symbolic execution can reason about every operation with bit level precision, uncover obscure edge cases manual testing misses, and maximize coverage and path exploration.
Discovered execution paths, input conditions, and resulting contract state, will appear dynamically during execution. Once completed, detailed coverage metrics will be displayed for each run.The results should display 14 test cases (execution paths) and 46% health coverage.Run times can vary depending on the number of sequences, transaction depth, the amount of symbolic parameters, compute, and more. Complex codebases will require increased allocation of compute resources. If you’re curious about what performance to expect, reach out to us and we’ll help you estimate it.Feel free to experiement with different sequences to analyze different behaviors.

Resulting execution paths, input conditions, and coverage.
4
Analyze and validate behavior
As you review the results, you’ll notice that every execution path results in a revert, with no successful
Mark the state value as valid by clicking the shield icon. You can click through the shield icon to mark it as invalid or back to unreviewed as well.
mint()
transaction occurring.We determine that we could not find any path or combination of inputs that will successfully lead to a mint transaction, and provide the test cases for each executed path.This outcome matches our expectations because after invoking the pause()
function, the _paused
contract value should be set to true
preventing any minting operation from successfully completing.Let’s confirm that the _paused
state value was indeed updated, and visually validate all other states and state changes are correct.Select and open the test case (execution path) with the following input conditions:
-
Alice
deploys the contract andBob
is set as theinitialOwner
-
Bob
calls thepause()
function -
Transaction reverts with an
EnforcedPause
error afterBob
attempts to mint1
token toAlice
.
constructor()
—> pause()
—> mint()
transactions. You can examine the storage layout, values, changes, account balances, and emitted events that occurred throughout the execution of the transaction sequence.Locate the _paused
storage value, and validate it was correctly set to true
after the pause()
transaction and that it remained unchanged after the mint()
transaction (which reverted). Source code is also highlighted for lines and branch coverage:- Green shield: Valid state
- Red shield: Invalid state
- Grey shield: Not reviewed
History
tab.If you added any other team members to your project, their reviews will be visable to everyone in your team. If one team member flags a state as invalid, it will appear as invalid (red) to all other collaborators. This is especially useful when working with auditors or extended teams to make code and security reviews easier.5
Exporting to Hardhat or Foundry

6
Optional: remove the `pause` function
Return to the canvas, and delete the
You’ll see the 
pause
function from the transaction sequence, and reconnect the mint(..)
function to the constructor()
.Run the analysis again.
Mint
mint(..)
transaction completing successfully.Select a path where a successful mint
operation occurs, and analyze the contract state and changes.Find the _totalSupply
state value, and evaluate its behavior. Has _totalSupply
increased as expected by the amount
? Have the balances correctly updated as well? Toggle through the transactions to become familiar with the process.
Contract state analysis