Titanoboa supports an "open" pattern where certain functions can act as both regular calls and context managers to manage state changes.
Permanent Changes
Calling a function directly (e.g., boa.set_env(new_env)) applies changes permanently to the current environment.
Temporary Changes (Reverting)
Using a function as a context manager (e.g., with boa.set_env(env):) ensures that any changes made within the block are reverted when the block exits.
Nested Anchoring
You can use boa.env.anchor() to create nested state checkpoints. When an inner with boa.env.anchor(): block exits, all state changes made within that block are reverted, but the outer anchor remains active.
import boa
# As a context manager - changes revert
original_env = boa.env
with boa.set_env(boa.Env()):
# Temporary environment
assert boa.env != original_env
# Environment reverts to original
assert boa.env == original_env
# Nested state management
contract = boa.loads("""
value: uint256
checkpoint: uint256
""")
with boa.env.anchor():
contract.eval("self.value = 100")
with boa.env.anchor():
contract.eval("self.value = 200")
contract.eval("self.checkpoint = self.value")
assert contract.eval("self.checkpoint") == 200
# Inner anchor reverted
assert contract.eval("self.value") == 100
assert contract.eval("self.checkpoint") == 0
# Outer anchor reverted
assert contract.eval("self.value") == 0