Install multicall via pip
masterInstall the multicall package using pip to use the Python interface for MakerDAO's multicall.
pip install multicallrepository·master·Indexed 43 days ago
https://github.com/banteg/multicall.pyA Python interface for MakerDAO's multicall and a port of multicall.js. It allows developers to batch multiple Ethereum contract calls into a single request to reduce RPC overhead and improve efficiency. Version 0.16.0 provides abstractions like the Multicall class for aggregating calls, the Call class for individual contract interactions, and the Signature class for handling seth-style function signatures.
Install the multicall package using pip to use the Python interface for MakerDAO's multicall.
pip install multicallThe Multicall implementation uses an internal NotSoBrightBatcher to manage large volumes of calls.
Batching Logic:
batcher.step (defaulting to 10,000).rebatch mechanism automatically reduces the step size (splitting the failed batch in half) and retries.Error Handling:
aiohttp.ClientResponseError with "request entity too large" or "connection reset by peer".requests.HTTPError with "request entity too large", "payload too large", "time-out", or "520 server error".ValueError containing "out of gas" (unless it's a single-call batch).TimeoutError.You can tune the library behavior using the following environment variables:
| Variable | Description | Default |
|---|---|---|
GAS_LIMIT | Sets the overridable default gas limit for Multicall to prevent out of gas errors. | 50,000,000 |
MULTICALL_DEBUG | If set, sets the logging level for all library loggers to logging.DEBUG. | N/A |
AIOHTTP_TIMEOUT | Sets the aiohttp timeout period in seconds for async calls to the node. | 30 |
The Multicall class allows you to batch multiple Call objects into a single request. You can define Call objects with specific return handlers (functions) to process the raw data immediately upon execution. When Multicall is called, it returns a dictionary where keys are the names provided in the returns argument and values are the processed results.
from multicall import Call, Multicall
# Example setup
MKR_TOKEN = '0xaaf64bfcc32d0f15873a02163e7e500671a4ffcd'
MKR_WHALE = '0xdb33dfd3d61308c33c63209845dad3e6bfb2c674'
MKR_FISH = '0x2dfcedcb401557354d0cf174876ab17bfd6f4efd'
def from_wei(value):
return value / 1e18
multi = Multicall([
Call(MKR_TOKEN, ['balanceOf(address)(uint256)', MKR_WHALE], [('whale', from_wei)]),
Call(MKR_TOKEN, ['balanceOf(address)(uint256)', MKR_FISH], [('fish', from_wei)]),
Call(MKR_TOKEN, 'totalSupply()(uint256)', [('supply', from_wei)]),
])
# Executes the batch and returns a dict of processed values
results = multi() # {'whale': 566437.0921992733, 'fish': 7005.0, 'supply': 1000003.1220798912}The Call(target, function, returns) class represents a single contract call.
Parameters:
target: The to address for the eth_call.function: Either a seth-style signature string method(input,types)(output,types) or a list containing [signature, *args].returns: A list of tuples (name, handler) for processing return values.None as the handler.Usage Patterns:
Call(... )() executes the call with arguments provided during initialization.Call(...)(args) allows you to reuse a prepared call object with different arguments.decode_output(output) to decode raw output and apply the returns handlers.The Multicall(calls) class aggregates a list of Call objects.
Parameters:
calls: A list of Call objects that have already had their arguments prepared.Usage:
Multicall(...)() to execute the batch and retrieve the results.The Signature(signature) class handles seth-style function signatures in the format function_name(input,types)(output,types). It supports complex types like structs, provided they are broken down into basic parts (e.g., (address,bytes)[]).
Use the following methods for data manipulation:
encode_data(args): Encodes input arguments into calldata.decode_data(output): Decodes the output data.The multicall package provides a structured way to define and execute multiple blockchain calls using Signature, Call, and Multicall abstractions.
Signature: Defines the cryptographic signature or identity used for the calls.Call: Represents a single target function call, including the target address, the function selector, and the expected return types.Multicall: Orchestrates a collection of Call objects into a single batch execution.from multicall import Signature, Call, Multicall
# Example workflow (conceptual):
signature = Signature("...")
calls = [
Call(target="0x...", function="0x...", returns=["uint256"]),
Call(target="0x...", function="0x...", returns=["bool"])
]
multicall = Multicall(calls)
# Execute using the multicall instance...The setup_logger function initializes a logging.Logger instance for a given name. If the environment variable MULTICALL_DEBUG is set to a truthy value, the logger is automatically configured to output to a StreamHandler (stdout/stderr) and its level is set to logging.DEBUG.
import os
from multicall.loggers import setup_logger
# To enable debug logging, ensure the environment variable is set
os.environ["MULTICALL_DEBUG"] = "True"
logger = setup_logger("my_app")
logger.debug("This will be visible if MULTICALL_DEBUG is set")The Multicall class aggregates multiple Call objects into a single batch request to a Multicall contract (Multicall2 or Multicall3, depending on the chain ID). This reduces the number of RPC calls needed to fetch data from multiple addresses or contracts.
To use it, initialize Multicall with a list of Call objects. You can then await the instance directly to execute the batch.
Key Parameters:
calls: A list of Call objects to execute.block_id: An optional integer representing the block number to query.require_success: If True (default), uses the aggregate method. If False, uses tryBlockAndAggregate to allow individual calls within the batch to fail without reverting the whole batch.gas_limit: The gas limit for the multicall execution._w3: An instance of Web3 (defaults to the imported w3).origin: An optional AnyAddress to use for state overrides if supported by the chain.from multicall.multicall import Multicall
from multicall.call import Call
# Define your calls
calls = [
Call(target="0x...", function="balanceOf(address)", params=["0x..."]),
# ... more calls
]
# Initialize and execute
multicall = Multicall(calls=calls, require_success=True)
results = await multicallOnce a Call object is instantiated, you can execute it using several methods:
call() (via __call__). This method includes automatic retries using eth_retry.await call.coroutine() for non-blocking execution. This also supports automatic retries and respects semaphore limits for concurrency control.Both methods allow you to override the Web3 instance or the block_id at runtime.
# Synchronous
result = call()
# Asynchronous
result = await call.coroutine(block_id=12345)The Multicall class provides helper methods to easily add common blockchain state queries to your batch. These methods append a new Call to the existing self.calls list using the appropriate Multicall contract signature.
Available helper methods:
add_base_fee(return_signature=('base_fee', None))add_block_hash(block_number, return_signature=('block_hash', None))add_block_number(return_signature=('block_number', None))add_chain_id(return_signature=('chain_id', None))add_block_coinbase(return_signature=('coinbase', None))add_block_difficulty(return_signature=('difficulty', None))add_block_gas_limit(return_signature=('gas_limit', None))add_block_timestamp(return_signature=('timestamp', None))add_eth_balance(address, return_signature=('eth_balance', None))add_last_block_hash(return_signature=('last_block_hash', None))calls = []
m = Multicall(calls=calls)
# Add metadata calls to the batch
m.add_chain_id()
m.add_block_number()
m.add_eth_balance("0x...")
# Execute the combined batch
results = await m