### Install eth-portfolio using pip Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/README.md This command installs the eth-portfolio package from its GitHub repository. Ensure you are using Python version 3.9 to 3.13 and have a virtual environment set up. ```bash pip install git+https://github.com/BobTheBuidler/eth-portfolio ``` -------------------------------- ### Install and Run eth-portfolio CLI Exporter Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This snippet provides instructions for installing the eth-portfolio package via pip, setting required environment variables (wallet addresses and Etherscan token), and running the command-line exporter. The exporter monitors balances and can export metrics to VictoriaMetrics. ```bash # Install the package pip install git+https://github.com/BobTheBuidler/eth-portfolio # Set required environment variables export PORTFOLIO_ADDRESS_0="0x1234567890abcdef1234567890abcdef12345678" export PORTFOLIO_ADDRESS_1="0xabcdef1234567890abcdef1234567890abcdef12" export ETHERSCAN_TOKEN="your_etherscan_api_key" # Run the exporter (requires brownie network configured) eth-portfolio # The exporter will: # 1. Continuously fetch portfolio balances # 2. Export metrics to VictoriaMetrics (if configured) # 3. Support Docker deployment with Grafana dashboards ``` -------------------------------- ### Fetch Protocol Balances (Staking, Lending) (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Demonstrates how to fetch staking and protocol-specific balances for a given address and block using the eth-portfolio protocols module. It includes examples for getting all staking balances, lending collateral, and lending debt. ```python from eth_portfolio import protocols from eth_portfolio.protocols import lending address = "0x1234567890abcdef1234567890abcdef12345678" block = 18000000 # Get all staking balances across protocols staking_balances = protocols.balances(address, block) for protocol_name, token_balances in staking_balances.items(): print(f"\n{protocol_name}:") for token, balance in token_balances.items(): print(f" {token}: {balance.balance} (${balance.usd_value})") # Get lending collateral collateral = lending.collateral(address, block) print("\nLending Collateral:") for protocol, balances in collateral.items(): print(f" {protocol}: ${balances.sum_usd()}") # Get lending debt debt = lending.debt(address, block) print("\nLending Debt:") for protocol, balances in debt.items(): print(f" {protocol}: ${balances.sum_usd()}") ``` -------------------------------- ### Manage Token Balances Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This example illustrates the usage of `Balance`, `TokenBalances`, and `RemoteTokenBalances` classes for managing token balances and their USD values. It shows how to create individual balances, aggregate them, and convert them into DataFrames. ```python from eth_portfolio.typing import Balance, TokenBalances, RemoteTokenBalances from decimal import Decimal # Create individual balances eth_balance = Balance( balance=Decimal("1.5"), usd_value=Decimal("2700.00"), token="0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", block=18000000 ) usdc_balance = Balance( balance=Decimal("1000"), usd_value=Decimal("1000.00"), token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", block=18000000 ) # TokenBalances aggregates balances by token address token_balances = TokenBalances(block=18000000) token_balances["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"] = eth_balance token_balances["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"] = usdc_balance print(f"Total USD Value: ${token_balances.sum_usd()}") # RemoteTokenBalances groups by protocol (for staking, lending) remote_balances = RemoteTokenBalances(block=18000000) remote_balances["Compound"] = token_balances remote_balances["Aave"] = TokenBalances(block=18000000) # Convert to DataFrame df = remote_balances.dataframe print(df) ``` -------------------------------- ### Get assets and debt for addresses Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/README.md Retrieves a detailed breakdown of assets and debt for given addresses within a block range. The output is a dictionary containing 'assets' and 'debt' sections, with token amounts and their USD values. ```python from eth_portfolio import portfolio portfolio.describe(start_block, end_block) >>> { 'assets': { 'wallet0_address': { 'token0': { 'amount': 123, 'value usd': 456, }, 'token1': { 'amount': 123, 'value usd': 456, }, }, 'wallet0_address': { 'token0': { 'amount': 123, 'value usd': 456, }, 'token1': { 'amount': 123, 'value usd': 456, }, }, }, 'debt': { 'wallet0_address': { 'token0': { 'amount': 123, 'value usd': 456, }, 'token1': { 'amount': 123, 'value usd': 456, }, }, 'wallet1_address': { 'token0': { 'amount': 123, 'value usd': 456, }, 'token1': { 'amount': 123, 'value usd': 456, }, }, }, } ``` -------------------------------- ### Get ETH balance for addresses Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/README.md Retrieves the ETH balance and its USD value for a list of addresses. The output is a dictionary where keys are addresses and values are _BalanceItem objects containing balance and usd_value. ```python from eth_portfolio import portfolio portfolio.eth_balance(block) >>> { 0xaddress0: _BalanceItem(balance=1234, usd_value=5678) 0xaddress1: _BalanceItem(balance=1234, usd_value=5678) 0xaddress2: _BalanceItem(balance=1234, usd_value=5678) } ``` -------------------------------- ### Get transactions as DataFrame Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/README.md Retrieves all transactions within a specified block range and formats them as a pandas DataFrame. This provides a structured view of all transaction activities. ```python from eth_portfolio import portfolio txs = portfolio.transactions.get(start_block, end_block) txs.df() >>> [I am a pretend DataFrame] ``` -------------------------------- ### Transaction Data Structure (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Details the fields available in the Transaction struct, which represents a complete on-chain transaction. It provides examples of accessing common properties like hash, block number, sender, receiver, value, gas, and EIP-1559 specific fields. ```python from eth_portfolio.structs import Transaction import evmspec # Transactions are typically created from RPC responses # Example of accessing transaction properties: # Assuming tx is a Transaction object from ledger # tx = transactions[0] # Access transaction properties print(f"Hash: {tx.hash}") print(f"Block: {tx.block_number}") print(f"From: {tx.from_address}") print(f"To: {tx.to_address}") print(f"Value: {tx.value} ETH") print(f"Gas: {tx.gas}") print(f"Gas Price: {tx.gas_price}") print(f"Nonce: {tx.nonce}") print(f"Type: {tx.type}") # 0=legacy, 1=EIP-2930, 2=EIP-1559 # EIP-1559 specific fields if tx.max_fee_per_gas: print(f"Max Fee Per Gas: {tx.max_fee_per_gas}") print(f"Max Priority Fee: {tx.max_priority_fee_per_gas}") # USD value if prices loaded if tx.price: print(f"ETH Price: ${tx.price}") print(f"Value USD: ${tx.value_usd}") ``` -------------------------------- ### Get token transfers for addresses Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/README.md Fetches token transfer data for specified addresses within a block range. The result can be converted to a pandas DataFrame for easier analysis. Each address's transfers are contained within an AddressTokenTransfersLedger object. ```python from eth_portfolio import portfolio token_transfers = portfolio.token_transfers.get(start_block, end_block) token_transfers.df() >>> { 0xaddress0: AddressTokenTransfersLedger(...) # Each of these contains the token transfers for the specified address 0xaddress1: AddressTokenTransfersLedger(...) 0xaddress2: AddressTokenTransfersLedger(...) } ``` -------------------------------- ### Track ERC20 Token Transfers Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This code retrieves and analyzes ERC20 token transfers within a specified block range using the eth-portfolio library. It shows how to get transfers, convert them to a DataFrame, and filter them by token. ```python from eth_portfolio import Portfolio port = Portfolio(addresses=["0x1234567890abcdef1234567890abcdef12345678"]) # Get token transfers in block range start_block = 17000000 end_block = 18000000 transfers = port.token_transfers.get(start_block, end_block) # Convert to DataFrame with token details df = transfers.df() print(df[['blockNumber', 'token', 'token_address', 'from', 'to', 'value', 'value_usd']].head()) # Filter transfers by token usdc_transfers = [t for t in transfers if t.token == "USDC"] for transfer in usdc_transfers[:5]: print(f"Block {transfer.block_number}: {transfer.value} {transfer.token}") print(f" From: {transfer.from_address}") print(f" To: {transfer.to_address}") if transfer.value_usd: print(f" USD Value: ${transfer.value_usd}") ``` -------------------------------- ### Initialize and Describe Portfolio (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Demonstrates how to initialize the Portfolio class with multiple addresses and retrieve a comprehensive balance snapshot at a specific block. It also shows how to access asset, debt, and external balances, and convert the results to a pandas DataFrame. ```python from eth_portfolio import Portfolio # Initialize portfolio with multiple addresses port = Portfolio( addresses=[ "0x1234567890abcdef1234567890abcdef12345678", "0xabcdef1234567890abcdef1234567890abcdef12" ], start_block=15000000, # Optional: start tracking from specific block label="My DeFi Portfolio", load_prices=True, # Fetch USD prices for all assets asynchronous=False # Use synchronous mode ) # Get full portfolio snapshot at a specific block block_number = 18000000 balances = port.describe(block_number) # Access balances by address for address, wallet_balances in balances.items(): print(f"\nWallet: {address}") print(f" Assets: {wallet_balances.assets.sum_usd()} USD") print(f" Debt: {wallet_balances.debt.sum_usd()} USD") print(f" External (staking/collateral): {wallet_balances.external.sum_usd()} USD") print(f" Net Worth: {wallet_balances.sum_usd()} USD") # Convert to DataFrame for analysis df = balances.dataframe print(df.head()) ``` -------------------------------- ### Instantiate and use Portfolio object Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/README.md Demonstrates how to create a `Portfolio` object with a list of addresses for synchronous and asynchronous operations. The `describe` method can then be called on the object. ```python from eth_portfolio import Portfolio port = Portfolio([0xaddress0, 0xaddress1, 0xaddress2]) port.describe(chain.height) # Or for async code async_port = Portfolio([0xaddress0, 0xaddress1, 0xaddress2], asynchronous=True) await port.describe(chain.height) ``` -------------------------------- ### Configure Portfolio via Environment Variables (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Shows how to configure wallet addresses and Etherscan API key using environment variables. This allows for using a pre-configured portfolio singleton instance without explicit initialization. ```python import os # Set environment variables before importing os.environ["PORTFOLIO_ADDRESS_0"] = "0x1234567890abcdef1234567890abcdef12345678" os.environ["PORTFOLIO_ADDRESS_1"] = "0xabcdef1234567890abcdef1234567890abcdef12" os.environ["ETHERSCAN_TOKEN"] = "your_etherscan_api_key" from eth_portfolio import portfolio # Use the pre-configured portfolio singleton block = 18000000 eth_balances = portfolio.eth_balance(block) # Returns: {address: Balance(balance=1.5, usd_value=2700.00)} for address, balance in eth_balances.items(): print(f"{address}: {balance.balance} ETH (${balance.usd_value})") ``` -------------------------------- ### Async Portfolio Operations (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Illustrates how to use the Portfolio class in asynchronous mode for improved performance. It demonstrates awaiting methods like `describe`, `assets`, and `debt` within an async function and calculating net worth. ```python import asyncio from eth_portfolio import Portfolio async def analyze_portfolio(): # Create async portfolio instance port = Portfolio( addresses=["0x1234567890abcdef1234567890abcdef12345678"], asynchronous=True, load_prices=True ) block = 18000000 # All methods work with await in async mode balances = await port.describe(block) assets = await port.assets(block) debt = await port.debt(block) # Calculate net worth total_assets = sum(bal.assets.sum_usd() for bal in balances.values()) total_debt = sum(bal.debt.sum_usd() for bal in balances.values()) net_worth = total_assets - total_debt print(f"Total Assets: ${total_assets}") print(f"Total Debt: ${total_debt}") print(f"Net Worth: ${net_worth}") return balances # Run async function balances = asyncio.run(analyze_portfolio()) ``` -------------------------------- ### Add and Calculate Wallet Balances and Net Worth (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Demonstrates how to add debt and external balances to a wallet object, then calculate and print the total assets, debt, external balances, and net worth. Finally, it exports the wallet's data to a pandas DataFrame. ```python from eth_portfolio.address import PortfolioAddress from eth_portfolio.structs import Balance, TokenBalances from decimal import Decimal # Assuming 'wallet' and 'block' are initialized elsewhere # Example initialization: # wallet = PortfolioAddress(address="0x1234567890abcdef1234567890abcdef12345678") # block = 18000000 # Add debt positions (borrowed tokens) debt_balances = TokenBalances(block=block) debt_balances["0x6B175474E89094C44Da98b954EesddRfF3afd4"] = Balance( balance=Decimal("500"), usd_value=Decimal("500.00"), block=block ) wallet.debt["MakerDAO"] = debt_balances # Add external balances (staked, collateral) staking_balances = TokenBalances(block=block) staking_balances["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] = Balance( balance=Decimal("1.0"), usd_value=Decimal("1800.00"), block=block ) wallet.external["Convex"] = staking_balances # Calculate net worth print(f"Assets: ${wallet.assets.sum_usd()}") print(f"Debt: ${wallet.debt.sum_usd()}") print(f"External: ${wallet.external.sum_usd()}") print(f"Net Worth: ${wallet.sum_usd()}") # Export to DataFrame df = wallet.dataframe print(df) ``` -------------------------------- ### Structure Wallet Balances Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This code snippet demonstrates how to initialize and populate the `WalletBalances` structure, which categorizes a wallet's holdings into assets, debt, and external positions. It shows adding direct token holdings as assets. ```python from eth_portfolio.typing import WalletBalances, TokenBalances, RemoteTokenBalances, Balance from decimal import Decimal block = 18000000 # Create wallet balances structure wallet = WalletBalances(block=block) # Add direct token holdings (assets) wallet.assets["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"] = Balance( balance=Decimal("2.0"), usd_value=Decimal("3600.00"), block=block ) ``` -------------------------------- ### Configure Shitcoin Filtering (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Explains how to use the SHITCOINS set to exclude specific tokens from balance calculations. It shows how to add tokens to the set and check if a token is currently marked for filtering. ```python from eth_portfolio import SHITCOINS # Add tokens to ignore (spam tokens, airdrops, etc.) SHITCOINS.add("0xspamtoken1234567890abcdef1234567890abcd") SHITCOINS.add("0xanotherspamtoken567890abcdef12345678") # Check if token is marked as shitcoin token = "0xspamtoken1234567890abcdef1234567890abcd" if token in SHITCOINS: print(f"{token} is filtered out") ``` -------------------------------- ### PortfolioAddress Class for Wallet Analysis (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Shows how to create and use the PortfolioAddress class to track a specific Ethereum wallet's history and balances. It covers fetching comprehensive descriptions, ETH balance, token balances, collateral, and debt across different blocks. ```python from eth_portfolio.address import PortfolioAddress # Create a single address tracker address = PortfolioAddress( address="0x1234567890abcdef1234567890abcdef12345678", start_block=15000000, load_prices=True, asynchronous=False ) block = 18000000 # Get comprehensive wallet description wallet_balances = address.describe(block) print(f"Assets: ${wallet_balances.assets.sum_usd()}") print(f"Debt: ${wallet_balances.debt.sum_usd()}") # Get specific balance types eth_balance = address.eth_balance(block) print(f"ETH: {eth_balance.balance} (${eth_balance.usd_value})") token_balances = address.token_balances(block) for token, balance in token_balances.items(): if balance.balance > 0: print(f"{token}: {balance.balance} (${balance.usd_value})") # Get collateral in lending protocols collateral = address.collateral(block) for protocol, balances in collateral.items(): print(f"\n{protocol} Collateral:") for token, balance in balances.items(): print(f" {token}: {balance.balance}") # Get debt from lending protocols debt = address.debt(block) for protocol, balances in debt.items(): print(f"\n{protocol} Debt:") for token, balance in balances.items(): print(f" {token}: {balance.balance}") ``` -------------------------------- ### Custom Token Bucket Mapping in ExportablePortfolio (Python) Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/docs/exporter.md Demonstrates how to provide a custom mapping of token addresses to bucket names when initializing ExportablePortfolio. This overrides default bucket logic for specified tokens. Ensure to use the underlying token address after unwrapping. ```python from eth_portfolio_scripts._portfolio import ExportablePortfolio custom_buckets = { "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "My Stablecoin Bucket", "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": "My ETH Bucket" } port = ExportablePortfolio( addresses=[...], custom_buckets=custom_buckets ) # This will override the default bucket for the specified tokens. ``` -------------------------------- ### Combine All Ledger Entries Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This code shows how to retrieve a combined DataFrame of all ledger entries, including transactions, internal transfers, and token transfers, within a specified block range. It also demonstrates filtering by USD value and accessing detailed entries per address. ```python from eth_portfolio import Portfolio port = Portfolio( addresses=["0x1234567890abcdef1234567890abcdef12345678"], load_prices=True ) start_block = 17000000 end_block = 18000000 # Get combined DataFrame of all ledger entries df = port.ledger.df(start_block, end_block, full=False) # Columns include: chainId, blockNumber, hash, from, to, token, # token_address, value, price, value_usd, gas, gasPrice, etc. print(df.head(20)) # Filter for significant value transfers significant = df[df['value_usd'] > 100] print(f"\nTransfers over $100: {len(significant)}") # Get all entries for detailed analysis all_entries = port.ledger.all_entries(start_block, end_block) for address, entries in all_entries.items(): print(f"\n{address}:") print(f" Transactions: {len(entries['transactions'])}") print(f" Internal Transfers: {len(entries['internal_transactions'])}") print(f" Token Transfers: {len(entries['token_transfers'])}") ``` -------------------------------- ### Implement Protocol with Staking Component using ProtocolWithStakingABC in Python Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/docs/new-protocols.md Subclass ProtocolWithStakingABC for protocols that combine lending/borrowing features with an integrated staking component. You must implement the `_balances` method to query both general protocol balances and staking positions for a given address and block. ```python from eth_portfolio.protocols._base import ProtocolWithStakingABC class MyProtocolWithStaking(ProtocolWithStakingABC): async def _balances(self, address, block=None): # Query balances and staking positions ... ``` -------------------------------- ### Track Internal ETH Transfers Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This snippet demonstrates how to fetch and process internal ETH transfers (traces) within a given block range using the eth-portfolio library. It iterates through the transfers and prints details like type, addresses, value, and trace information. ```python from eth_portfolio import Portfolio port = Portfolio(addresses=["0x1234567890abcdef1234567890abcdef12345678"]) # Get internal transfers start_block = 17000000 end_block = 18000000 internal_transfers = port.internal_transfers.get(start_block, end_block) for transfer in internal_transfers[:10]: print(f"Block {transfer.block_number}: {transfer.type}") print(f" From: {transfer.from_address}") print(f" To: {transfer.to_address}") print(f" Value: {transfer.value} ETH") print(f" Trace Address: {transfer.trace_address}") if transfer.call_type: print(f" Call Type: {transfer.call_type}") ``` -------------------------------- ### Enable y.stuck? Debug Logger for Price Lookups (Python) Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/CONTRIBUTING.md This Python code snippet demonstrates how to enable the DEBUG level logging for the 'y.stuck?' logger. This is useful for debugging slow price lookups performed by the ypricemagic library, which eth-portfolio depends on. It configures basic logging and then specifically sets the 'y.stuck?' logger to DEBUG level. ```python import logging logging.basicConfig(level=logging.INFO) logging.getLogger("y.stuck?").setLevel(logging.DEBUG) ``` -------------------------------- ### Iterate Through Transactions Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This snippet demonstrates how to iterate through a list of transactions and print details for each. It assumes a 'transactions' object is available with attributes like block_number, hash, from_address, to_address, value, and gas. ```python for tx in transactions: print(f"Block {tx.block_number}: {tx.hash}") print(f" From: {tx.from_address}") print(f" To: {tx.to_address}") print(f" Value: {tx.value} ETH") print(f" Gas Used: {tx.gas}") ``` -------------------------------- ### Implement Lending/Borrowing Protocol with ProtocolABC in Python Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/docs/new-protocols.md Subclass ProtocolABC to integrate lending, borrowing, or other generic DeFi protocols. The core requirement is to implement the `_balances` method, which should return a TokenBalances mapping including supplied, borrowed, and reward tokens for a given address and block. ```python from eth_portfolio.protocols._base import ProtocolABC class MyLendingProtocol(ProtocolABC): async def _balances(self, address, block=None): # Query supplied and borrowed balances for the address ... ``` -------------------------------- ### Retrieve Transaction Ledger (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Demonstrates how to access and filter transaction history for a portfolio within a specified block range. The results can be easily converted into a pandas DataFrame for further analysis. ```python from eth_portfolio import Portfolio port = Portfolio(addresses=["0x1234567890abcdef1234567890abcdef12345678"]) # Get transactions between block range start_block = 17000000 end_block = 18000000 transactions = port.transactions.get(start_block, end_block) # Convert to DataFrame df = transactions.df() print(f"Found {len(df)} transactions") print(df[['blockNumber', 'hash', 'from', 'to', 'value', 'gasUsed']].head()) ``` -------------------------------- ### Print Token Transfer Details Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This snippet demonstrates how to access and print details of a token transfer, including block number, transaction hash, token address, symbol, sender, receiver, and value. It also shows how to display USD values if price information is available. ```python transfer = token_transfers[0] print(f"Block: {transfer.block_number}") print(f"Transaction: {transfer.hash}") print(f"Log Index: {transfer.log_index}") print(f"Token Address: {transfer.token_address}") print(f"Token Symbol: {transfer.token}") # May be None if unknown print(f"From: {transfer.from_address}") print(f"To: {transfer.to_address}") print(f"Value: {transfer.value}") # Scaled to human-readable decimals # USD values if prices loaded if transfer.price: print(f"Token Price: ${transfer.price}") print(f"Value USD: ${transfer.value_usd}") ``` -------------------------------- ### Calculate net worth Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/README.md Calculates the net worth by subtracting total debt from total assets for a given block. It utilizes the `describe` method and then sums the USD values of assets and debt. ```python from eth_portfolio import portfolio desc = portfolio.describe(block) assets = desc['assets'] # OR you can do `assets = portfolio.assets(block)` debt = desc['debt'] # OR you can do `debt = portfolio.debt(block)` assets = sum(assets.values()) debt = sum(debt.values()) net = assets - debt net.sum_usd() >>> Decimal("123456.78900") ``` -------------------------------- ### Implement Staking Pool Logic with StakingPoolABC in Python Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/docs/new-protocols.md Subclass StakingPoolABC to add support for staking pools with multiple tokens or custom reward logic. Requires implementing the `contract` and `_balances` methods. The `_balances` method should query staked balances and rewards for a given address and block. ```python from eth_portfolio.protocols._base import StakingPoolABC class MyStakingPool(StakingPoolABC): def contract(self): # Return a web3 contract instance for the staking pool ... async def _balances(self, address, block=None): # Query the staked balance and rewards for the address ... ``` -------------------------------- ### Print Internal Transfer Details Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt This snippet shows how to access and print details of an internal ETH transfer (trace), including block number, transaction hash, type, sender, receiver, value, gas, and trace address. It also includes conditional printing for call type and reward type. ```python from eth_portfolio.structs import InternalTransfer # InternalTransfer properties (from ledger entries) # transfer = internal_transfers[0] print(f"Block: {transfer.block_number}") print(f"Transaction: {transfer.hash}") print(f"Type: {transfer.type}") # 'call', 'create', 'reward', 'suicide' print(f"From: {transfer.from_address}") print(f"To: {transfer.to_address}") print(f"Value: {transfer.value} ETH") print(f"Gas: {transfer.gas}") print(f"Gas Used: {transfer.gas_used}") print(f"Trace Address: {transfer.trace_address}") # e.g., [0, 1, 2] print(f"Subtraces: {transfer.subtraces}") if transfer.call_type: print(f"Call Type: {transfer.call_type}") # 'call', 'delegatecall', etc. # For reward transfers if transfer.type == "reward": print(f"Reward Type: {transfer.reward_type}") ``` -------------------------------- ### Implement Single-Token Staking Pool with SingleTokenStakingPoolABC in Python Source: https://github.com/bobthebuidler/eth-portfolio/blob/master/docs/new-protocols.md Subclass SingleTokenStakingPoolABC for staking pools that accept only a single token. Similar to StakingPoolABC, you need to implement the `contract` and `_balances` methods to define the pool's contract interaction and balance querying logic. ```python from eth_portfolio.protocols._base import SingleTokenStakingPoolABC class MySingleTokenStakingPool(SingleTokenStakingPoolABC): def contract(self): ... async def _balances(self, address, block=None): ... ``` -------------------------------- ### TokenTransfer Data Structure (Python) Source: https://context7.com/bobthebuidler/eth-portfolio/llms.txt Describes the TokenTransfer struct, which represents an ERC20 Transfer event. This documentation snippet indicates that the struct contains properties relevant to token transfers, typically obtained from ledger entries. ```python from eth_portfolio.structs import TokenTransfer # TokenTransfer properties (from ledger entries) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.