### Install ape-foundry via setuptools Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Install the most up-to-date version by cloning the repository and using setuptools. ```bash git clone https://github.com/ApeWorX/ape-foundry.git cd ape-foundry python3 setup.py install ``` -------------------------------- ### Install Documentation Tooling Source: https://github.com/apeworx/ape-foundry/blob/main/CONTRIBUTING.md Install the necessary tools for building and serving the project documentation. ```bash pip install -e .'[doc]' ``` -------------------------------- ### Clone and Setup Ape Foundry Source: https://github.com/apeworx/ape-foundry/blob/main/CONTRIBUTING.md Clone the repository, set up a virtual environment, and install the project and its development dependencies. ```bash git clone https://github.com/ApeWorX/ape-foundry.git cd ape-foundry python3 -m venv venv source venv/bin/activate python setup.py install pip install -e .'[dev]' ``` -------------------------------- ### Install and Configure Pre-Commit Hooks Source: https://github.com/apeworx/ape-foundry/blob/main/CONTRIBUTING.md Install pre-commit locally to ensure consistent code formatting and linting before committing. ```bash pip install pre-commit pre-commit install ``` -------------------------------- ### Install ape-foundry via pip Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Install the latest release of the ape-foundry plugin using pip. ```bash pip install ape-foundry ``` -------------------------------- ### Install ape-foundry and Foundry Source: https://context7.com/apeworx/ape-foundry/llms.txt Install the plugin via pip and ensure the Foundry binaries are available on your system's PATH. ```bash pip install ape-foundry curl -L https://foundry.paradigm.xyz | bash foundryup ``` -------------------------------- ### Use Mainnet Fork Provider Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Use the mainnet fork provider by specifying '--network :mainnet-fork:foundry' in commands. Ensure the upstream provider plugin is installed. ```bash ape console --network :mainnet-fork:foundry ``` ```bash ape plugins install alchemy ``` -------------------------------- ### Get Account Balance with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Retrieves the balance of an account in wei. Can fetch the current balance or the balance at a specific block. ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: addr = ape.accounts.test_accounts[0].address # Current balance balance = provider.get_balance(addr) print(f"Balance: {balance} wei") # At a specific block balance_at_block = provider.get_balance(addr, block_id=1000) print(f"Balance at block 1000: {balance_at_block} wei") ``` -------------------------------- ### Reset Fork State with FoundryForkProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Use `fork.reset_fork()` to rewind a fork to its original block number or a specified block number. This simulates a fresh node start. ```python import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as fork: # Do some state-changing operations... # Reset to the originally-configured block number fork.reset_fork() # Or reset to a different block number fork.reset_fork(block_number=20_000_000) print(fork.get_block("latest").number) # 20000000 ``` -------------------------------- ### Pytest Fixtures for Foundry Integration Source: https://context7.com/apeworx/ape-foundry/llms.txt Utilize built-in Ape pytest fixtures alongside Foundry-specific capabilities for testing. This includes account fixtures, impersonation, and connected provider setup. ```python # tests/conftest.py import pytest import ape @pytest.fixture(scope="session") def accounts(): return ape.accounts.test_accounts @pytest.fixture(scope="session") def sender(accounts): return accounts[0] @pytest.fixture(scope="session") def owner(accounts): return accounts[2] @pytest.fixture def whale(accounts): # Impersonate a whale — works on mainnet-fork return accounts["0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503"] @pytest.fixture def connected_provider(networks): with networks.ethereum.local.use_provider("foundry") as provider: yield provider # tests/test_contract.py def test_transfer(sender, receiver, connected_provider): snap = ape.chain.snapshot() sender.transfer(receiver, "1 ETH") assert ape.chain.provider.get_balance(receiver.address) > 0 ape.chain.restore(snap) def test_whale_sends(whale, contract_instance): # whale is auto-impersonated; give it gas money ape.chain.provider.set_balance(whale.address, "10 ETH") receipt = contract_instance.deposit(value="1 ETH", sender=whale) assert receipt.status == 1 ``` -------------------------------- ### Manage FoundryProvider Lifecycle Manually Source: https://context7.com/apeworx/ape-foundry/llms.txt Manually connect to and disconnect from an Anvil node using FoundryProvider. The connect() method starts the Anvil subprocess, and disconnect() stops it. Environment variables can override the default host. ```python from pathlib import Path from ape_foundry import FoundryProvider import ape # Manual lifecycle (normally handled by the context manager) local_network = ape.networks.ethereum.local provider = FoundryProvider( name="foundry", network=local_network, request_header={}, data_folder=Path("."), provider_settings={}, ) provider.connect() print(f"Connected at {provider.uri}") # http://127.0.0.1:8545 # ... interact ... provider.disconnect() print("Provider stopped") # Environment variable override — connect to a remote Anvil node import os os.environ["APE_FOUNDRY_HOST"] = "https://anvil.example.com" with ape.networks.ethereum.local.use_provider("foundry") as p: print(p.uri) # https://anvil.example.com ``` -------------------------------- ### Get Transaction Trace with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Retrieve detailed transaction traces using `provider.get_transaction_trace`. This method returns an `AnvilTransactionTrace` object for opcode-level introspection. ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: sender = ape.accounts.test_accounts[0] # After a transaction is mined, retrieve its trace receipt = sender.transfer(ape.accounts.test_accounts[1], "1 ETH") txn_hash = receipt.txn_hash trace = provider.get_transaction_trace(txn_hash) # Show the full call tree trace.show() # Access the decoded return value print(trace.return_value) ``` -------------------------------- ### Impersonate Account Fixture Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Use a pytest fixture to get an impersonated account. This requires the impersonated account to have a balance, which can be achieved by using a forked network or setting fees to zero. ```python import pytest @pytest.fixture def whale(accounts): return accounts["example.eth"] ``` -------------------------------- ### Serve Project Documentation Locally Source: https://github.com/apeworx/ape-foundry/blob/main/CONTRIBUTING.md Serve the project documentation locally for viewing in a web browser. Use the --open flag to automatically open the browser. ```bash sphinx-ape serve . --open ``` -------------------------------- ### Build Project Documentation Source: https://github.com/apeworx/ape-foundry/blob/main/CONTRIBUTING.md Build the project documentation using the sphinx-ape command. ```bash sphinx-ape build . ``` -------------------------------- ### Set Account Balance with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Sets the balance of an account using various input formats. Accepts integers (wei), keyword amounts (e.g., "1000 ETH"), hex strings, or bytes. Can also be set via the account attribute. ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: addr = ape.accounts.test_accounts[0].address # Keyword amount (uses Ape's conversion manager) provider.set_balance(addr, "1000 ETH") print(provider.get_balance(addr)) # 1000000000000000000000 # Wei integer provider.set_balance(addr, 500 * 10**18) # Hex string provider.set_balance(addr, "0x1BC16D674EC80000") # 2 ETH # Via account attribute (same underlying call) account = ape.accounts.test_accounts[1] account.balance = "50 ETH" print(account.balance) # 50000000000000000000 ``` -------------------------------- ### EVM State Snapshots with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Manages EVM state by taking snapshots and restoring to them. `snapshot()` records the current state, and `restore()` reverts the EVM to a previously taken snapshot. ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: sender = ape.accounts.test_accounts[0] receiver = ape.accounts.test_accounts[1] # Take a snapshot before a state-changing operation snap = ape.chain.snapshot() # returns a SnapshotID (str/int) print(f"Snapshot: {snap}") # Make some state changes provider.set_balance(receiver.address, "9999 ETH") print(provider.get_balance(receiver.address)) # 9999 ETH in wei # Restore back to the snapshot ape.chain.restore(snap) # receiver's balance is back to the original value ``` -------------------------------- ### Use FoundryProvider in Python Source: https://context7.com/apeworx/ape-foundry/llms.txt Interact with a local Anvil node programmatically using Ape's network context manager. Access chain properties, accounts, and deploy/interact with contracts. ```python import ape # --- CLI usage --- # ape run script.py --network ethereum:local:foundry # ape console --network ethereum:local:foundry # ape test --network ethereum:local:foundry # --- Programmatic usage --- with ape.networks.ethereum.local.use_provider("foundry") as provider: print(provider.chain_id) # 31337 print(provider.uri) # http://127.0.0.1:8545 print(provider.ws_uri) # ws://127.0.0.1:8545 print(provider.is_connected) # True print(provider.evm_version) # e.g. "shanghai" (from config) print(provider.auto_mine) # True accounts = ape.accounts.test_accounts sender = accounts[0] receiver = accounts[1] # Deploy a contract and call it # contract = sender.deploy(MyContract) # receipt = contract.myMethod(sender=sender) # print(receipt.status) ``` -------------------------------- ### FoundryProvider.snapshot / restore Source: https://context7.com/apeworx/ape-foundry/llms.txt Manages EVM state snapshots. `snapshot()` creates a snapshot and returns an ID, while `restore()` reverts the EVM to a previous snapshot state. ```APIDOC ## FoundryProvider.snapshot / restore — EVM State Snapshots `snapshot()` calls `evm_snapshot` and returns a snapshot ID string. `restore()` calls `evm_revert` to roll the EVM back to that snapshot. ### Methods - **snapshot()**: Creates a snapshot of the current EVM state. - **restore(snapshot_id)**: Reverts the EVM state to the specified snapshot ID. ### Parameters - **snapshot_id** (str | int): The ID of the snapshot to restore. ### Request Example ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: snap = ape.chain.snapshot() provider.set_balance(ape.accounts.test_accounts[1].address, "9999 ETH") ape.chain.restore(snap) ``` ``` -------------------------------- ### Auto-detect EVM Hardfork with FoundryForkProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Inspect the built-in block-to-hardfork mapping or use `fork.detect_evm_version()` to auto-detect the EVM hardfork for a given block number. This detection runs automatically during `build_command`. ```python from ape_foundry.provider import FoundryForkProvider from ape_foundry.constants import EVM_VERSION_BY_NETWORK # Inspect the built-in block→hardfork mapping print(EVM_VERSION_BY_NETWORK["ethereum"]["mainnet"]) # {0: 'frontier', 1150000: 'homestead', 4370000: 'byzantium', # 7280000: 'petersburg', 9069000: 'istanbul', 9200000: 'muirglacier', # 12244000: 'berlin', 12965000: 'london'} # With a connected fork provider, auto-detection runs at build_command time import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as fork: version = fork.detect_evm_version() # For block 21418244 (post-london) → "london" print(version) ``` -------------------------------- ### pytest Integration — Test Fixtures Source: https://context7.com/apeworx/ape-foundry/llms.txt Demonstrates how to integrate ape-foundry with pytest using built-in fixtures for testing Ethereum smart contracts. ```APIDOC ## pytest Integration — Test Fixtures `ape-foundry` integrates natively with `ape test` (pytest-based). Use Ape's built-in fixtures combined with Foundry-specific capabilities. ### Fixtures - **accounts**: Provides access to test accounts. - **sender**: A fixture for the first test account. - **owner**: A fixture for the third test account. - **whale**: A fixture to impersonate a specific address (works on mainnet-fork). - **connected_provider**: A fixture that yields a connected Foundry provider for the local Ethereum network. ### Usage Example ```python # tests/conftest.py import pytest import ape @pytest.fixture(scope="session") def accounts(): return ape.accounts.test_accounts @pytest.fixture(scope="session") def sender(accounts): return accounts[0] @pytest.fixture(scope="session") def owner(accounts): return accounts[2] @pytest.fixture def whale(accounts): # Impersonate a whale — works on mainnet-fork return accounts["0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503"] @pytest.fixture def connected_provider(networks): with networks.ethereum.local.use_provider("foundry") as provider: yield provider # tests/test_contract.py def test_transfer(sender, receiver, connected_provider): snap = ape.chain.snapshot() sender.transfer(receiver, "1 ETH") assert ape.chain.provider.get_balance(receiver.address) > 0 ape.chain.restore(snap) def test_whale_sends(whale, contract_instance): # whale is auto-impersonated; give it gas money ape.chain.provider.set_balance(whale.address, "10 ETH") receipt = contract_instance.deposit(value="1 ETH", sender=whale) assert receipt.status == 1 ``` ``` -------------------------------- ### Configure FoundryProvider in ape-config.yaml Source: https://context7.com/apeworx/ape-foundry/llms.txt Configure Anvil node settings, including host, timeouts, mining behavior, and fork-specific options, under the 'foundry:' key in ape-config.yaml. ```yaml foundry: # Host: explicit URL, "auto" for random ephemeral port, or omit for 127.0.0.1:8545 host: auto # Timeouts (seconds) request_timeout: 30 # default RPC timeout fork_request_timeout: 300 # timeout for fork RPCs (longer due to upstream latency) # Number of startup attempts before raising FoundrySubprocessError process_attempts: 5 # RPC fee/price defaults (set to 0 for gasless local testing) base_fee: 0 priority_fee: 0 gas_price: 0 # Mining behaviour auto_mine: true # mine a block on every transaction block_time: 10 # alternatively, mine on a fixed interval (seconds) # Remove the call.gas_limit <= block.gas_limit constraint disable_block_gas_limit: false # EVM hardfork for local networks evm_version: shanghai # Force Optimism mode (auto-detected for Optimism/Base ecosystems) use_optimism: false # Fork-specific overrides fork: ethereum: mainnet: upstream_provider: alchemy block_number: 21418244 evm_version: london sepolia: upstream_provider: alchemy block_number: 3091950 ``` -------------------------------- ### Connect to Remote Anvil Node via Environment Variable Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Connect to a remote Anvil node by setting the APE_FOUNDRY_HOST environment variable. ```bash export APE_FOUNDRY_HOST=https://your-anvil.example.com ``` -------------------------------- ### Configure Foundry host in ape-config.yaml Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Configure the Foundry network provider's host in your ape-config.yaml. Use 'auto' to select a random port, which is useful for multiprocessing. ```yaml foundry: host: https://127.0.0.1:8555 ``` ```yaml foundry: host: auto ``` -------------------------------- ### Configure Base Fee and Priority Fee Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Configure the node's base fee and priority fee to zero in ape-config.yaml. This is useful for testing or when impersonating accounts. ```yaml foundry: base_fee: 0 priority_fee: 0 ``` -------------------------------- ### Set Account Balance Programmatically Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Programmatically set an account's balance using the 'anvil_setBalance' RPC call via the Ape accounts interface. ```python from ape import accounts account = accounts["example.eth"] account.balance = "1000 ETH" # This calls `anvil_setBalance` under-the-hood. ``` -------------------------------- ### Foundry Exception Classes and Handling Source: https://context7.com/apeworx/ape-foundry/llms.txt Handle specific `ape-foundry` exceptions like `FoundryProviderError`, `FoundrySubprocessError`, and `FoundryNotInstalledError` for robust error management. ```python from ape_foundry.exceptions import ( FoundryProviderError, # Base: any Foundry plugin error (subclass of ProviderError) FoundrySubprocessError, # Anvil subprocess launch/runtime failures FoundryNotInstalledError, # anvil binary not found on PATH ) try: with ape.networks.ethereum.local.use_provider("foundry") as p: pass except FoundryNotInstalledError as e: print(e) # "Missing local Foundry node client. See ape-foundry README for install steps." except FoundrySubprocessError as e: print(f"Subprocess error: {e}") except FoundryProviderError as e: print(f"Provider error: {e}") ``` -------------------------------- ### FoundryProvider.get_balance Source: https://context7.com/apeworx/ape-foundry/llms.txt Retrieves the balance of a given account in wei. This method calls `eth_getBalance`. ```APIDOC ## FoundryProvider.get_balance — Get Account Balance Calls `eth_getBalance` and returns the result as a Python `int` (wei). ### Method ```python provider.get_balance(address, block_id=None) ``` ### Parameters - **address** (str): The address of the account to query. - **block_id** (int, optional): The block number at which to query the balance. Defaults to the latest block. ### Response - **balance** (int): The account balance in wei. ### Request Example ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: addr = ape.accounts.test_accounts[0].address balance = provider.get_balance(addr) print(f"Balance: {balance} wei") balance_at_block = provider.get_balance(addr, block_id=1000) print(f"Balance at block 1000: {balance_at_block} wei") ``` ``` -------------------------------- ### FoundryForkProvider Configuration and Usage Source: https://context7.com/apeworx/ape-foundry/llms.txt Configure forked network settings in `ape-config.yaml` under `foundry.fork`. The `FoundryForkProvider` passes `--fork-url` and optionally `--fork-block-number` to Anvil. ```python import ape # ape-config.yaml must have: # foundry: # fork: # ethereum: # mainnet: # upstream_provider: alchemy # block_number: 21418244 # CLI usage # ape console --network :mainnet-fork:foundry # ape run script.py --network ethereum:mainnet-fork:foundry # Programmatic usage with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as fork: print(fork.fork_url) # e.g. https://eth-mainnet.g.alchemy.com/v2/... print(fork.fork_block_number) # 21418244 print(fork.chain_id) # 1 (real mainnet chain ID on a fork) # Read live mainnet state dai = ape.project.load_contracts() # or load from chain_manager.contracts block = fork.get_block("latest") print(block.number) ``` -------------------------------- ### Set ERC20 Allowance with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Configure a token spending allowance between two accounts using `provider.set_erc20_allowance`. Specify the holder, spender, token address, and the allowance amount. ```python import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as provider: holder = ape.accounts.test_accounts[0].address spender = ape.accounts.test_accounts[1].address usdc = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" allowance = 500_000 * 10**6 # 500,000 USDC provider.set_erc20_allowance(holder, spender, usdc, allowance) ``` -------------------------------- ### Set Block Gas Limit with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Modify the maximum gas per block using `provider.set_block_gas_limit`. This method returns `True` upon successful execution. ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: new_limit = 30_000_000 # 30M gas result = provider.set_block_gas_limit(new_limit) print(result) # True ``` -------------------------------- ### FoundryForkProvider.detect_evm_version Source: https://context7.com/apeworx/ape-foundry/llms.txt Automatically detects the EVM hardfork version based on a given block number by consulting a predefined mapping. ```APIDOC ## FoundryForkProvider.detect_evm_version — Auto-detect EVM Hardfork Given a `fork_block_number`, looks up the correct EVM hardfork in `EVM_VERSION_BY_NETWORK` (sourced from Erigon chain specs) and returns it as a string. ### Method ```python fork.detect_evm_version() ``` ### Parameters This method does not take any parameters. ### Response #### Success Response - **version** (str): The detected EVM hardfork version (e.g., "london"). ### Request Example ```python from ape_foundry.provider import FoundryForkProvider from ape_foundry.constants import EVM_VERSION_BY_NETWORK # Inspect the built-in block→hardfork mapping print(EVM_VERSION_BY_NETWORK["ethereum"]["mainnet"]) # {0: 'frontier', 1150000: 'homestead', 4370000: 'byzantium', # 7280000: 'petersburg', 9069000: 'istanbul', 9200000: 'muirglacier', # 12244000: 'berlin', 12965000: 'london'} # With a connected fork provider, auto-detection runs at build_command time import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as fork: version = fork.detect_evm_version() # For block 21418244 (post-london) → "london" print(version) ``` ``` -------------------------------- ### Deal ERC20 Tokens with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Use `provider.deal_erc20` to assign an ERC20 token balance directly to a recipient without a transfer. Ensure the correct token address and amount (considering decimals) are provided. ```python import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as provider: recipient = ape.accounts.test_accounts[0].address usdc = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" # USDC on Ethereum amount = 1_000_000 * 10**6 # 1,000,000 USDC (6 decimals) provider.deal_erc20(recipient, usdc, amount) # recipient's USDC balance is now 1,000,000 USDC ``` -------------------------------- ### Account Impersonation with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Use `provider.unlock_account` and `provider.relock_account` to impersonate addresses for sending transactions without private keys. This is useful for testing scenarios involving specific accounts. ```python import ape import pytest # Pytest fixture pattern (recommended for tests) @pytest.fixture def whale(accounts): # Impersonate a known mainnet whale return accounts["0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503"] # Programmatic usage with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as provider: whale_addr = "0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503" provider.unlock_account(whale_addr) whale = ape.accounts[whale_addr] # Give the account some ETH for gas (if needed on local) provider.set_balance(whale_addr, "10 ETH") # Now whale can sign and broadcast transactions # receipt = some_contract.someMethod(sender=whale) provider.relock_account(whale_addr) ``` -------------------------------- ### FoundryProvider.set_balance Source: https://context7.com/apeworx/ape-foundry/llms.txt Sets the balance of a given account. Accepts integers (wei), keyword amounts (e.g., "1000 ETH"), hex strings, or bytes. This method calls `anvil_setBalance`. ```APIDOC ## FoundryProvider.set_balance — Set Account Balance Calls `anvil_setBalance` under the hood. Accepts integers (wei), keyword amounts (`"1000 ETH"`), hex strings, or bytes. ### Method ```python provider.set_balance(address, amount) ``` ### Parameters - **address** (str): The address of the account to set the balance for. - **amount** (int | str | bytes): The new balance. Can be in wei (int), a keyword amount (str), a hex string, or bytes. ### Request Example ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: addr = ape.accounts.test_accounts[0].address provider.set_balance(addr, "1000 ETH") provider.set_balance(addr, 500 * 10**18) provider.set_balance(addr, "0x1BC16D674EC80000") ``` ### Response This method does not return a value directly but modifies the state of the blockchain. ``` -------------------------------- ### Set EVM Version for Local Networks Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Change the EVM version for local Foundry networks by setting the 'evm_version' config in ape-config.yaml. ```yaml foundry: evm_version: shanghai ``` -------------------------------- ### Configure Foundry request timeouts Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Adjust the request timeout settings for the Foundry plugin in ape-config.yaml. Defaults are provided. ```yaml foundry: request_timeout: 20 # Defaults to 30 fork_request_timeout: 600 # Defaults to 300 ``` -------------------------------- ### Mine on an Interval Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Configure Anvil to mine a new block every specified number of seconds by setting the 'block_time' config in ape-config.yaml. ```yaml foundry: block_time: 10 # mine a new block every 10 seconds ``` -------------------------------- ### Exception Classes Source: https://context7.com/apeworx/ape-foundry/llms.txt Details the custom exception classes provided by the ape-foundry library for error handling. ```APIDOC ## Exception Classes `ape-foundry` exposes three exception types that propagate through Ape's standard error handling. ### Exception Types - **FoundryProviderError**: Base exception for any Foundry plugin error (subclass of `ProviderError`). - **FoundrySubprocessError**: Raised for Anvil subprocess launch or runtime failures. - **FoundryNotInstalledError**: Raised when the `anvil` binary is not found on the system's PATH. ### Usage Example ```python from ape_foundry.exceptions import ( FoundryProviderError, FoundrySubprocessError, FoundryNotInstalledError, ) import ape try: with ape.networks.ethereum.local.use_provider("foundry") as p: pass except FoundryNotInstalledError as e: print(e) # "Missing local Foundry node client. See ape-foundry README for install steps." except FoundrySubprocessError as e: print(f"Subprocess error: {e}") except FoundryProviderError as e: print(f"Provider error: {e}") ``` ``` -------------------------------- ### Configure Mainnet Fork Upstream Provider Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Specify the upstream archive-data provider for mainnet forking in ape-config.yaml. Defaults to the default mainnet provider plugin if not specified. ```yaml foundry: fork: ethereum: mainnet: upstream_provider: alchemy ``` -------------------------------- ### FoundryForkProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt A forked network provider that extends FoundryProvider by passing `--fork-url` and optionally `--fork-block-number` to Anvil. Fork settings can be configured per-network in `ape-config.yaml`. ```APIDOC ## FoundryForkProvider — Forked Network Provider `FoundryForkProvider` extends `FoundryProvider` and passes `--fork-url` (and optionally `--fork-block-number`) to Anvil. Configure per-network fork settings under `foundry.fork` in `ape-config.yaml`. ### Configuration `ape-config.yaml` example: ```yaml foundry: fork: ethereum: mainnet: upstream_provider: alchemy block_number: 21418244 ``` ### Usage - **CLI**: `ape console --network :mainnet-fork:foundry` or `ape run script.py --network ethereum:mainnet-fork:foundry` - **Programmatic**: Use `ape.networks.ethereum.mainnet_fork.use_provider("foundry")`. ### Properties - **fork_url**: The URL of the upstream provider for the fork. - **fork_block_number**: The block number to fork from. - **chain_id**: The chain ID of the forked network. ### Request Example ```python import ape # ape-config.yaml must have the fork configuration as shown above. # Programmatic usage with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as fork: print(fork.fork_url) # e.g. https://eth-mainnet.g.alchemy.com/v2/... print(fork.fork_block_number) # 21418244 print(fork.chain_id) # 1 (real mainnet chain ID on a fork) # Read live mainnet state dai = ape.project.load_contracts() # or load from chain_manager.contracts block = fork.get_block("latest") print(block.number) ``` ### Response This provider allows interaction with a forked blockchain state. Properties like `fork_url`, `fork_block_number`, and `chain_id` provide information about the fork configuration. ``` -------------------------------- ### Set Contract Storage Slot with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Directly writes a 32-byte value to a specific storage slot of a contract. This allows for precise manipulation of contract state for testing purposes. ```python import ape from eth_pydantic_types import HexBytes with ape.networks.ethereum.local.use_provider("foundry") as provider: contract_addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F" # DAI slot = 2 # e.g. the `totalSupply` storage slot new_value = HexBytes(10**24) # 1,000,000 DAI (18 decimals) provider.set_storage(contract_addr, slot, new_value) # Storage slot is now updated in the forked state ``` -------------------------------- ### FoundryProvider.deal_erc20 Source: https://context7.com/apeworx/ape-foundry/llms.txt Directly assigns an ERC20 token balance to a recipient address without requiring a transfer. This is useful for setting up specific token states in tests. ```APIDOC ## FoundryProvider.deal_erc20 — Deal ERC20 Tokens Calls `anvil_dealERC20` to directly assign an ERC20 token balance without needing a transfer. ### Method ```python provider.deal_erc20(recipient: str, token_address: str, amount: int) ``` ### Parameters - **recipient** (str) - The address to receive the tokens. - **token_address** (str) - The address of the ERC20 token contract. - **amount** (int) - The amount of tokens to assign. ### Request Example ```python import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as provider: recipient = ape.accounts.test_accounts[0].address usdc = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" # USDC on Ethereum amount = 1_000_000 * 10**6 # 1,000,000 USDC (6 decimals) provider.deal_erc20(recipient, usdc, amount) ``` ### Response This method does not return a value directly but modifies the state of the blockchain. ``` -------------------------------- ### Connect to Remote Anvil Node via Config Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Configure the ape-foundry plugin to connect to a remote Anvil node by setting the 'host' in ape-config.yaml. ```yaml foundry: host: https://anvil.example.com ``` -------------------------------- ### Set EVM Version for Forked Networks Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Set the EVM version for specific forked networks by configuring it within the 'fork' section of ape-config.yaml. ```yaml foundry: fork: ethereum: mainnet: evm_version: shanghai ``` -------------------------------- ### AnvilTransactionTrace Class Usage Source: https://context7.com/apeworx/ape-foundry/llms.txt The `AnvilTransactionTrace` class provides Anvil-specific transaction tracing capabilities, extending Ape Ethereum's `TransactionTrace`. It supports `stepsTracing` and memory-enabled `debug_traceTransaction`. ```python from ape_foundry.trace import AnvilTransactionTrace # Construct directly from a transaction hash trace = AnvilTransactionTrace( transaction_hash="0xabc123...", # additional ape trace kwargs accepted ) # Inspect call-tree approach print(trace.call_trace_approach) # TraceApproach.PARITY # Debug parameters sent to the node print(trace.debug_trace_transaction_parameters) # {'stepsTracing': True, 'enableMemory': True} # Decoded top-level return value (lazy, cached on first access) print(trace.return_value) # e.g. (True,) or (1000,) depending on ABI # Render the full call tree to stdout trace.show() ``` -------------------------------- ### Set Contract Bytecode with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Overwrites the bytecode at a specific address. This is useful for mocking contract behavior in tests. Accepts bytecode as a hex string or bytes. ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: target = "0xdAC17F958D2ee523a2206206994597C13D831ec7" # USDT on mainnet fork # Set arbitrary bytecode at the address mock_bytecode = "0x6080604052" result = provider.set_code(target, mock_bytecode) print(result) # True # Also accepts bytes result = provider.set_code(target, bytes.fromhex("6080604052")) print(result) # True ``` -------------------------------- ### Set Next Block Timestamp with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Sets the timestamp for the next mined block. This is useful for testing time-sensitive smart contract logic. ```python import ape import time with ape.networks.ethereum.local.use_provider("foundry") as provider: future_ts = int(time.time()) + 86400 # 1 day in the future provider.set_timestamp(future_ts) provider.mine() latest = ape.chain.blocks[-1] print(latest.timestamp) # approximately future_ts ``` -------------------------------- ### AnvilTransactionTrace Source: https://context7.com/apeworx/ape-foundry/llms.txt An Anvil-specific trace class that extends Ape Ethereum's `TransactionTrace`. It incorporates Anvil's `stepsTracing` and memory-enabled `debug_traceTransaction` parameters, utilizing Parity's `trace_transaction` for efficient return-value extraction. ```APIDOC ## AnvilTransactionTrace — Anvil-specific Trace Class `AnvilTransactionTrace` extends Ape Ethereum's `TransactionTrace` with Anvil's `stepsTracing` + memory-enabled `debug_traceTransaction` parameters and uses Parity `trace_transaction` for efficient return-value extraction. ### Methods - **__init__(transaction_hash: str, **kwargs)**: Initializes the trace object. - **show()**: Renders the full call tree to stdout. ### Properties - **call_trace_approach**: Returns the call trace approach (e.g., `TraceApproach.PARITY`). - **debug_trace_transaction_parameters**: Returns the debug parameters sent to the node. - **return_value**: Returns the decoded top-level return value (lazy, cached on first access). ### Request Example ```python from ape_foundry.trace import AnvilTransactionTrace # Construct directly from a transaction hash trace = AnvilTransactionTrace( transaction_hash="0xabc123...", # additional ape trace kwargs accepted ) # Inspect call-tree approach print(trace.call_trace_approach) # TraceApproach.PARITY # Debug parameters sent to the node print(trace.debug_trace_transaction_parameters) # {'stepsTracing': True, 'enableMemory': True} # Decoded top-level return value (lazy, cached on first access) print(trace.return_value) # e.g. (True,) or (1000,) depending on ABI # Render the full call tree to stdout trace.show() ``` ``` -------------------------------- ### FoundryProvider.set_timestamp Source: https://context7.com/apeworx/ape-foundry/llms.txt Sets the timestamp for the next block to be mined. This method calls `evm_setNextBlockTimestamp`. ```APIDOC ## FoundryProvider.set_timestamp — Set Next Block Timestamp Sets the timestamp of the next mined block via `evm_setNextBlockTimestamp`. ### Method ```python provider.set_timestamp(timestamp) ``` ### Parameters - **timestamp** (int): The Unix timestamp for the next block. ### Request Example ```python import ape import time with ape.networks.ethereum.local.use_provider("foundry") as provider: future_ts = int(time.time()) + 86400 # 1 day in the future provider.set_timestamp(future_ts) provider.mine() latest = ape.chain.blocks[-1] print(latest.timestamp) ``` ``` -------------------------------- ### Mine Blocks with FoundryProvider Source: https://context7.com/apeworx/ape-foundry/llms.txt Manually mines one or more blocks. Useful when auto-mining is disabled. The `auto_mine` attribute controls whether blocks are mined automatically. ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: # Disable auto-mining provider.auto_mine = False # calls anvil_setAutomine print(ape.chain.blocks[-1].number) # e.g. 0 # Mine a single block provider.mine() print(ape.chain.blocks[-1].number) # 1 # Mine 10 blocks at once provider.mine(10) print(ape.chain.blocks[-1].number) # 11 # Re-enable auto-mining provider.auto_mine = True ``` -------------------------------- ### Disable Auto-mining via Provider Instance Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Disable auto-mining on an Anvil node using the provider instance by setting 'anvil.auto_mine = False'. This calls the 'anvil_setAutomine' RPC. ```python from ape import chain anvil = chain.provider anvil.auto_mine = False # calls `anvil_setAutomine` RPC. ``` -------------------------------- ### FoundryProvider.get_transaction_trace Source: https://context7.com/apeworx/ape-foundry/llms.txt Retrieves a detailed trace of a mined transaction, providing opcode-level introspection. This is invaluable for debugging complex transaction execution flows. ```APIDOC ## FoundryProvider.get_transaction_trace — Transaction Tracing Returns an `AnvilTransactionTrace` object that uses Parity-style `trace_transaction` with `stepsTracing` enabled for full opcode-level introspection. ### Method ```python provider.get_transaction_trace(txn_hash: str) -> AnvilTransactionTrace ``` ### Parameters - **txn_hash** (str) - The hash of the transaction to trace. ### Request Example ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: sender = ape.accounts.test_accounts[0] # After a transaction is mined, retrieve its trace receipt = sender.transfer(ape.accounts.test_accounts[1], "1 ETH") txn_hash = receipt.txn_hash trace = provider.get_transaction_trace(txn_hash) # Show the full call tree trace.show() # Access the decoded return value print(trace.return_value) ``` ### Response #### Success Response (200) - **trace** (AnvilTransactionTrace) - An object containing the transaction trace details. ``` -------------------------------- ### Disable Auto-mining via Config Source: https://github.com/apeworx/ape-foundry/blob/main/README.md Disable auto-mining on Anvil node startup by setting 'auto_mine: false' in ape-config.yaml. ```yaml foundry: auto_mine: false ``` -------------------------------- ### FoundryProvider.set_storage Source: https://context7.com/apeworx/ape-foundry/llms.txt Directly writes a 32-byte value to a specific storage slot of a contract. This method calls `anvil_setStorageAt`. ```APIDOC ## FoundryProvider.set_storage — Set Contract Storage Slot Directly writes a 32-byte value to a storage slot via `anvil_setStorageAt`. ### Method ```python provider.set_storage(address, slot, value) ``` ### Parameters - **address** (str): The address of the contract. - **slot** (int): The storage slot index. - **value** (HexBytes | bytes): The 32-byte value to write to the storage slot. ### Request Example ```python import ape from eth_pydantic_types import HexBytes with ape.networks.ethereum.local.use_provider("foundry") as provider: contract_addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F" # DAI slot = 2 # e.g. the `totalSupply` storage slot new_value = HexBytes(10**24) # 1,000,000 DAI (18 decimals) provider.set_storage(contract_addr, slot, new_value) ``` ``` -------------------------------- ### FoundryProvider.set_erc20_allowance Source: https://context7.com/apeworx/ape-foundry/llms.txt Configures a token spending allowance for a spender address. This allows a spender to withdraw tokens from the holder's account up to the specified allowance. ```APIDOC ## FoundryProvider.set_erc20_allowance — Set ERC20 Allowance Calls `anvil_setERC20Allowance` to directly configure a token spending allowance. ### Method ```python provider.set_erc20_allowance(holder: str, spender: str, token_address: str, allowance: int) ``` ### Parameters - **holder** (str) - The address that owns the tokens and grants the allowance. - **spender** (str) - The address that is allowed to spend the tokens. - **token_address** (str) - The address of the ERC20 token contract. - **allowance** (int) - The amount of tokens the spender is allowed to withdraw. ### Request Example ```python import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as provider: holder = ape.accounts.test_accounts[0].address spender = ape.accounts.test_accounts[1].address usdc = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" allowance = 500_000 * 10**6 # 500,000 USDC provider.set_erc20_allowance(holder, spender, usdc, allowance) ``` ### Response This method does not return a value directly but modifies the state of the blockchain. ``` -------------------------------- ### FoundryProvider.set_code Source: https://context7.com/apeworx/ape-foundry/llms.txt Overwrites the bytecode at a specified address. This is useful for mocking contracts in tests and calls `anvil_setCode`. ```APIDOC ## FoundryProvider.set_code — Set Contract Bytecode Overwrites the bytecode at a given address using `anvil_setCode`. Useful for mocking contracts in tests. ### Method ```python provider.set_code(address, bytecode) ``` ### Parameters - **address** (str): The address of the contract whose bytecode is to be set. - **bytecode** (str | bytes): The new bytecode for the contract. Can be a hex string or bytes. ### Response - **result** (bool): True if the operation was successful. ### Request Example ```python import ape with ape.networks.ethereum.local.use_provider("foundry") as provider: target = "0xdAC17F958D2ee523a2206206994597C13D831ec7" # USDT on mainnet fork mock_bytecode = "0x6080604052" result = provider.set_code(target, mock_bytecode) print(result) result = provider.set_code(target, bytes.fromhex("6080604052")) print(result) ``` ``` -------------------------------- ### FoundryForkProvider.reset_fork Source: https://context7.com/apeworx/ape-foundry/llms.txt Resets the fork state to a specified block number using the `anvil_reset` method. This allows rewinding the fork to its original state or a new block. ```APIDOC ## FoundryForkProvider.reset_fork — Reset Fork State Calls `anvil_reset` to rewind the fork back to its original (or a new) block number, as if the node had been freshly started. ### Method ```python fork.reset_fork(block_number=None) ``` ### Parameters #### Path Parameters - **block_number** (int, optional): The block number to reset the fork to. If not provided, it resets to the originally configured block number. ### Request Example ```python import ape with ape.networks.ethereum.mainnet_fork.use_provider("foundry") as fork: # Do some state-changing operations... # Reset to the originally-configured block number fork.reset_fork() # Or reset to a different block number fork.reset_fork(block_number=20_000_000) print(fork.get_block("latest").number) # 20000000 ``` ```