vault.base

Documentation for eth_defi.vault.base Python module.

Generic Vault adapter base classes.

  • Create unified interface across different vault protocols and their investment flows

  • Helps to create automated trading agents against any vault easily

  • Handle both trading (asset management role) and investor management (deposits/redemptions)

  • See VaultBase to get started

  • See RawVaultPriceRow for the raw scanner parquet row schema and CleanedVaultPriceRow for the enriched cleaned format

Module Attributes

DEPOSIT_CLOSED_EPOCH_WINDOW

Deposit closed reason constants

REDEMPTION_CLOSED_EPOCH_WINDOW

Redemption closed reason constants

Functions

verify_parquet_file(path[, expected_rows, ...])

Read back a parquet file after writing and verify its integrity.

Classes

ParquetVerificationResult

Result of verifying a parquet file after writing.

RawVaultPriceRow

Schema for a single row in the uncleaned vault price parquet file.

TradingUniverse

Describe assets vault can manage.

VaultBase

Base class for vault protocol adapters.

VaultFlowManager

Manage deposit/redemption events.

VaultHistoricalRead

Vault share price and fee structure at the point of time.

VaultHistoricalReader

Support reading historical vault share prices.

VaultInfo

Vault-protocol specific intormation about the vault.

VaultPortfolio

Track assets and balances in a vault.

VaultReadCondition

VaultReadCondition()

VaultSpec

Unique id for a vault.

Exceptions

ParquetVerificationError

Raised when a parquet file fails post-write verification.

DEPOSIT_CLOSED_EPOCH_WINDOW = 'Epoch deposit window closed'

Deposit closed reason constants

REDEMPTION_CLOSED_EPOCH_WINDOW = 'Epoch redemption window closed'

Redemption closed reason constants

exception ParquetVerificationError

Bases: Exception

Raised when a parquet file fails post-write verification.

This is a hard failure — the operator must investigate and restore from backup. Never catch and swallow this exception.

__init__(*args, **kwargs)
__new__(**kwargs)
add_note(note, /)

Add a note to the exception

with_traceback(tb, /)

Set self.__traceback__ to tb and return self.

class ParquetVerificationResult

Bases: object

Result of verifying a parquet file after writing.

Returned by verify_parquet_file() on success.

path: pathlib.Path

Path to the verified file.

row_count: int

Number of rows read back from the file metadata.

column_count: int

Number of columns in the file schema.

file_size: int

File size in bytes on disk.

column_names: list[str]

Column names found in the file schema.

__init__(path, row_count, column_count, file_size, column_names)
Parameters
Return type

None

verify_parquet_file(path, expected_rows=None, expected_schema=None, required_columns=None)

Read back a parquet file after writing and verify its integrity.

Performs a metadata read-back (not a full table load) to check:

  1. The file can be opened and its metadata read without errors

  2. Row count matches expected_rows if provided

  3. All columns in expected_schema are present with correct types (extra columns are permitted — e.g. native protocol columns)

  4. All required_columns are present

Uses pq.read_metadata() and pq.read_schema() instead of pq.read_table() to avoid loading the full dataset into memory.

This function should be called on a temp file before the atomic replace so that the previous good file is preserved when verification fails.

Parameters
  • path (Union[pathlib.Path, str]) – Path to the parquet file to verify.

  • expected_rows (Optional[int]) – If set, assert the file contains exactly this many rows.

  • expected_schema (pyarrow.Schema | None) – If set, verify that all columns in this schema are present with the correct types. Extra columns are permitted.

  • required_columns (Optional[list[str]]) – If set, verify these column names are present.

Returns

Verification result with metadata about the file.

Raises

ParquetVerificationError – If any verification check fails or the file cannot be read.

Return type

eth_defi.vault.base.ParquetVerificationResult

class VaultSpec

Bases: object

Unique id for a vault.

  • Each vault can be identified by smart contract address by one of the contracts, related to its deployment. Usually this contract is vault contract itself.

  • We need both chain and address to specify vault we mean.

chain_id: int

Ethereum chain id

vault_address: Union[eth_typing.evm.HexAddress, str]

Vault smart contract address or whatever is the primary address for unravelling a vault deployment for a vault protocol.

Always forced to lowercase.

static parse_string(spec, separator='auto')

Parse vault spec from a string.

Parameters
  • spec (str) – String in the format of “chain_id,address” or “chain_id-address”

  • separator – Either “auto” or “-” or “,”

Returns

VaultSpec instance

Return type

eth_defi.vault.base.VaultSpec

__init__(chain_id, vault_address)
Parameters
Return type

None

class VaultInfo

Bases: TypedDict

Vault-protocol specific intormation about the vault.

  • A dictionary of data we gathered about the vault deployment, like various smart contracts associated with the vault

  • Not standardised yet

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class TradingUniverse

Bases: object

Describe assets vault can manage.

  • Because of brainrotten and awful ERC-20 token standard, the vault does not know what tokens it owns and this needs to be specific offchain

__init__(spot_token_addresses)
Parameters

spot_token_addresses (set[str]) –

Return type

None

class VaultPortfolio

Bases: object

Track assets and balances in a vault.

  • Offchain method to track what assets a vault contains

  • Takes TradingUniverse as an input and resolves all relevant balances the vault holds for this trading universe

  • Because of brainrotten and awful ERC-20 token standard, the vault does not know what tokens it owns and this needs to be specific offchain

  • See VaultBase.fetch_portfolio()

spot_erc20: eth_defi.vault.lower_case_dict.LowercaseDict

List of tokens and their amounts

Addresses not checksummed

dex_hints: dict[eth_typing.evm.HexAddress, list[str]]

For route finding, which DEX tokens should use.

Token address -> DEX id string mapping

property tokens: set[eth_typing.evm.HexAddress]

Get list of tokens held in this portfolio

is_spot_only()

Do we have only ERC-20 hold positions in this portfolio

Return type

bool

get_raw_spot_balances(web3)

Convert spot balances to raw token balances

Parameters

web3 (web3.main.Web3) –

Return type

eth_defi.vault.lower_case_dict.LowercaseDict

__init__(spot_erc20, dex_hints=<factory>)
Parameters
Return type

None

class RawVaultPriceRow

Bases: TypedDict

Schema for a single row in the uncleaned vault price parquet file.

This is the format produced by VaultHistoricalRead.export() and written to vault-prices-1h.parquet by the historical scanner (scan_historical_prices_to_parquet()).

The canonical columns are defined by VaultHistoricalRead.to_pyarrow_schema(). Native protocol merges (Hyperliquid, GRVT, Lighter, Hibachi) may add extra columns (e.g. account_pnl, leader_fraction) that are preserved across schema migrations but are not part of this TypedDict.

See CleanedVaultPriceRow in eth_defi.research.wrangle_vault_prices for the enriched schema produced by the cleaning pipeline.

chain: int

EVM chain id (e.g. 1 for Ethereum, 8453 for Base).

Native (non-EVM) protocols use synthetic in-house chain ids:

The full mapping lives in CHAIN_NAMES.

address: str

Vault contract address, lowercase.

Address formats vary by protocol:

  • EVM vaults: 0x-prefixed hex (e.g. "0xabcd...")

  • Hypercore: 0x-prefixed hex (Hyperliquid vault addresses)

  • GRVT: platform-specific id (e.g. "vlt:xxx")

  • Lighter: synthetic id (e.g. "lighter-pool-281474976710654")

  • Hibachi: synthetic id (e.g. "hibachi-vault-2")

See is_good_multichain_address() for the validation function that accepts all these formats.

block_number: int

Block number of the on-chain read. For native protocols without blocks this is a synthetic sequence number.

timestamp: ForwardRef('pd.Timestamp', module='eth_defi.vault.base')

Naive UTC timestamp of the block.

share_price: float

Share price in denomination token units.

For ERC-4626 vaults this is read directly from the contract (convertToAssets(1e decimals)). GRVT, Lighter, and Hibachi provide native share prices from their respective APIs. Hypercore (native Hyperliquid vaults) does not expose a share price; it is internally calculated as total_assets / total_supply from reconstructed equity curves and deposit/withdrawal histories. See eth_defi.hyperliquid.combined_analysis for the Hypercore share price derivation.

total_assets: float

Total assets under management (TVL) in denomination token units.

total_supply: float

Total supply of vault share tokens.

performance_fee: float

Performance fee at time of read (e.g. 0.20 = 20%). NaN if unknown.

management_fee: float

Management fee at time of read (e.g. 0.02 = 2%). NaN if unknown.

errors: str

Comma-separated RPC error messages, or empty string if no errors.

Example values: "total_supply call failed", "total_assets zero: 0", "total_supply call missing".

vault_poll_frequency: str

Dynamic poll frequency used when taking this sample. Empty string if not set.

Example values: "1h", "4h", "24h". The scanner adjusts frequency based on vault TVL and activity; low-TVL vaults may be polled less frequently.

max_deposit: float

Maximum deposit amount allowed (ERC-4626 maxDeposit), in denomination token units. NaN if unknown. ERC-4626 vaults only.

max_redeem: float

Maximum redeem amount allowed (ERC-4626 maxRedeem), in share token units. NaN if unknown. ERC-4626 vaults only.

deposits_open: str

Whether deposits were open: "true", "false", or "" (unknown). Stored as string for legacy reasons; see deposit_closed_reason in CleanedVaultPriceRow. ERC-4626 vaults only.

redemption_open: str

Whether redemptions were open: "true", "false", or "" (unknown). ERC-4626 vaults only.

trading: str

Whether the vault was actively trading: "true", "false", or "" (unknown). Currently only supported for D2 Finance vaults.

available_liquidity: float

Available liquidity for immediate withdrawal in denomination token units. Lending protocol vaults only (IPOR, Euler, Morpho, Gearbox, etc.). NaN otherwise.

utilisation: float

Utilisation ratio (0.0–1.0) for lending vaults. NaN if not applicable. Lending protocol vaults only.

Warning

This metric measures capital deployment efficiency (how much of the vault’s AUM is lent out), not redeemable liquidity. For single-market vaults (Euler EVK, Gearbox, Silo) high utilisation does mean low available liquidity. For multi-market aggregators (Morpho, Euler Earn, IPOR) a vault can show 95% utilisation yet have substantial instantly redeemable liquidity in low-utilisation underlying markets. See README-vault-redeemable.md and README-utilisation.md in eth_defi.erc_4626.vault_protocol for details.

written_at: ForwardRef('pd.Timestamp | None', module='eth_defi.vault.base')

When this row was actually written/fetched (naive UTC). None until stamped at write time.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class VaultHistoricalRead

Bases: object

Vault share price and fee structure at the point of time.

vault: eth_defi.vault.base.VaultBase

Vault for this result is

block_number: int

block number of the reade

timestamp: datetime.datetime

Naive datetime in UTC

share_price: Optional[decimal.Decimal]

What was the share price in vault denomination token

None if the read failed (call execution reverted)

total_assets: Optional[decimal.Decimal]

NAV / Assets under management in denomination token

None if the read failed (call execution reverted)

total_supply: Optional[decimal.Decimal]

Number of share tokens

None if the read failed (call execution reverted)

performance_fee: Optional[float]

What was the vault performance fee around the time

management_fee: Optional[float]

What was the vault management fee around the time

errors: Optional[list[str]]

Add RPC error messages and such related to this read

Exported as empty string in Parquet if no errors, otherwise concat strings

vault_poll_frequency: Optional[str]

What dynamic read frequency was used at the time of taking this sample

Useful for diagnostics of scanning process

max_deposit: Optional[decimal.Decimal]

Maximum deposit amount allowed at this point in time (ERC-4626 maxDeposit).

In denomination token units.

max_redeem: Optional[decimal.Decimal]

Maximum redeem amount allowed at this point in time (ERC-4626 maxRedeem).

In share token units.

deposits_open: Optional[bool]

Whether deposits were open at this point in time (protocol-specific logic)

redemption_open: Optional[bool]

Whether redemptions were open at this point in time (protocol-specific logic)

trading: Optional[bool]

Whether the vault was actively trading at this point in time.

Currently only supported for D2 Finance vaults.

available_liquidity: Optional[decimal.Decimal]

Available liquidity for immediate withdrawal.

Only applicable to lending protocol vaults (IPOR, Euler, Morpho, Gearbox, etc.) In denomination token units.

utilisation: Optional[float]

Utilisation percentage of the lending vault.

Only applicable to lending protocol vaults. Value between 0.0 and 1.0 (0% to 100%).

is_almost_equal(other, epsilon=0.001)

Check if the read statistics match.

  • Throttle with epsilon relative difference to get rid of small increment rows

Parameters
Return type

bool

export()

Convert historical read for a Parquet/DataFrame export.

The returned dict conforms to RawVaultPriceRow.

Return type

eth_defi.vault.base.RawVaultPriceRow

classmethod to_pyarrow_schema()

Get parquet schema for writing this data.

  • Write multiple chains, multiple vaults, to a single Parquet file

  • Column semantics are documented in RawVaultPriceRow

Return type

pyarrow.Schema

static migrate_parquet_schema(existing_table)

Migrate an existing Parquet table to the current schema.

When new columns are added to to_pyarrow_schema(), existing parquet files still have the old schema. This function adds missing columns as null arrays so incremental scans can write new data without losing columns.

Non-canonical columns (e.g. account_pnl, leader_fraction added by native protocol merges) are preserved so that the EVM scanner does not destroy data written by Hyperliquid/GRVT/Lighter.

Parameters

existing_table (pyarrow.Table) – Table read from an older parquet file.

Returns

Table with all canonical columns present (missing ones filled with nulls), legacy columns removed, extra columns preserved.

Return type

pyarrow.Table

static write_uncleaned_parquet(df, path, compression='zstd')

Write a DataFrame to the uncleaned parquet using proper PyArrow types.

Native protocol merge functions (Hyperliquid, GRVT, Lighter) must use this instead of pandas.DataFrame.to_parquet() to avoid type promotion (e.g. timestamp[ms]timestamp[us]) that breaks migrate_parquet_schema() on the next EVM scan run.

Columns present in the canonical schema are cast to their canonical types. Extra columns (from native protocols) are kept with their pandas-inferred types. No pandas index is written.

Parameters
  • df (pd.DataFrame) – Combined DataFrame to write.

  • path (pathlib.Path) – Output parquet file path.

  • compression (str) – Parquet compression codec.

Return type

None

static write_uncleaned_arrow_table(table, path, compression='zstd')

Write a pre-aligned raw-price Arrow table with atomic verification.

Both the EVM-compatible pandas writer and the direct PyArrow native merge path use this method. The caller is responsible for aligning canonical column types before calling this method; the output is stamped with the current Docker metadata.version provenance, written beside the target, verified, and atomically replaced only on success.

Parameters
  • table (pyarrow.Table) – Raw price table with its final canonical and native-only schema.

  • path (pathlib.Path) – Target uncleaned parquet path.

  • compression (str) – Parquet compression codec.

Return type

None

__init__(vault, block_number, timestamp, share_price, total_assets, total_supply, performance_fee, management_fee, errors, vault_poll_frequency=None, max_deposit=None, max_redeem=None, deposits_open=None, redemption_open=None, trading=None, available_liquidity=None, utilisation=None)
Parameters
Return type

None

class VaultReadCondition

Bases: object

VaultReadCondition()

__init__()
class VaultHistoricalReader

Bases: abc.ABC

Support reading historical vault share prices.

  • Allows to construct historical returns

__init__(vault)
Parameters

vault (eth_defi.vault.base.VaultBase) –

abstract construct_multicalls()

Create smart contract calls needed to read the historical state of this vault.

  • Multicall machinery will call these calls at a specific block and report back to process_result()

Return type

Iterable[eth_defi.event_reader.multicall_batcher.EncodedCall]

abstract process_result(block_number, timestamp, call_results)

Process the result of mult

Parameters
Return type

eth_defi.vault.base.VaultHistoricalRead

class VaultFlowManager

Bases: abc.ABC

Manage deposit/redemption events.

  • For some vault structures, we need to know how much redemptions there are in the queue, so we can rebalance to have enough cash

  • Create a replay of flow events that happened for a vault within a specific block range

  • Not implemented yet

abstract fetch_pending_redemption(block_identifier)

Get how much users want to redeem from the vault.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) – Block number

Returns

Number of share tokens the users want to redeem from the vault.

Shares must be valued separately.

Return type

decimal.Decimal

abstract fetch_pending_deposit(block_identifier)

Get how much users want to redeem from the vault.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) – Block number

Returns

Number of underlying tokens the users want to redeem from the vault.

Return type

decimal.Decimal

abstract fetch_pending_deposit_events(range)

Read incoming pending deposits.

Parameters

range (Tuple[eth_typing.evm.BlockNumber, eth_typing.evm.BlockNumber]) –

Return type

None

abstract fetch_pending_redemption_event(range)

Read outgoing pending withdraws.

Parameters

range (Tuple[eth_typing.evm.BlockNumber, eth_typing.evm.BlockNumber]) –

Return type

None

abstract fetch_processed_deposit_event(range)

Read incoming pending deposits.

Parameters

range (Tuple[eth_typing.evm.BlockNumber, eth_typing.evm.BlockNumber]) –

Return type

None

abstract fetch_processed_redemption_event(vault, range)

Read outgoing pending withdraws.

Parameters
Return type

None

class VaultBase

Bases: abc.ABC

Base class for vault protocol adapters.

  • Allows automated interaction with different vault protocols.

  • Contains various abstract methods that the implementation class must override

Supported protocols include

Code exists, but does not confirm the interface yet:

Vault covered functionality

  • Fetching the current balances, deposits or redemptions

  • Get vault information with fetch_info()
    • No standardised data structures or functions yet

  • Build a swap through a vault
    • No standardised data structure yet

  • Update vault position valuations
    • No standardised data structure yet

Integration check list

Integration tests needed for:

  • ☑️ read vault core info

  • ☑️ read vault investors

  • ☑️ read vault share price

  • ☑️ read vault share token

  • ☑️ read all positions

  • ☑️ read NAV

  • ☑️ read pending redemptions to know how much USDC we will need for the next settlement cycles

  • ☑️ deposit integration test

  • ☑️ redemption integration

  • ☑️ swap integration test

  • ☑️ re-valuation integration test

  • ☑️ only asset manager allowed to swap negative test

  • ☑️ only valuation commitee allowed to update vault valuations (if applicable)

  • ☑️ can redeem if enough USDC to settle

  • ☑️ cannot redeem not enough USDC to settle

For code examples see tests/lagoon and tests/velvet on the Github repository.

Parameters
  • token_cache

    Token cache for vault tokens.

    Allows to pass eth_defi.token.TokenDiskCache to speed up operations.

  • require_denomination_token

    If True, accessing denomination_token will raise RuntimeError when the on-chain lookup returns None.

    Use for deployment scripts and operational contexts where a missing denomination token is always a hard error.

__init__(token_cache=None, require_denomination_token=False)
Parameters
  • token_cache (Optional[dict]) –

    Token cache for vault tokens.

    Allows to pass eth_defi.token.TokenDiskCache to speed up operations.

  • require_denomination_token (bool) –

    If True, accessing denomination_token will raise RuntimeError when the on-chain lookup returns None.

    Use for deployment scripts and operational contexts where a missing denomination token is always a hard error.

first_seen_at_block: Optional[int]

Block number hint when this vault was deployed.

Must be set externally, as because of shitty Ethereum RPC we cannot query this. Allows us to avoid unnecessary work when scanning historical price data.

abstract property chain_id: int

Chain this vault is on

abstract property address: eth_typing.evm.HexAddress

Vault contract address.

  • Often vault protocols need multiple contracts per vault, so what this function returns depends on the protocol

abstract property name: str

Vault name.

abstract property symbol: str

Vault share token symbol

property description: Optional[str]

Human-readable vault strategy description.

  • Fetched from protocol-specific offchain sources (e.g. Euler GitHub labels, Lagoon web app API)

  • Returns None if the protocol does not provide descriptions or the vault is not in the metadata source

  • Override in subclasses that support offchain metadata

property short_description: Optional[str]

One-liner vault summary.

  • Shorter version of description() suitable for listings and tables

  • Returns None if not available

  • Override in subclasses that support offchain metadata

property manager_name: Optional[str]

Protocol-supplied vault manager or curator display name.

  • Used when the vault name itself does not contain the curator brand

  • Returns None if the protocol does not expose separate manager metadata

  • Override in subclasses that support manager or operator metadata

fetch_scan_record_extra_data()

Fetch protocol-specific private scan row columns.

Some vault protocols expose structured metadata that is useful for the raw scanner output but does not fit the shared human-readable columns. Override this hook in protocol-specific subclasses instead of adding a separate branch to eth_defi.erc_4626.scan.create_vault_scan_record().

Returns

Mapping of private scan-row column names, usually prefixed with _. The default implementation returns no extra data.

Return type

dict[str, object]

property flow_manager: eth_defi.vault.base.VaultFlowManager

Flow manager associated with this vault

property deposit_manager: eth_defi.vault.deposit_redeem.VaultDepositManager

Deposit manager assocaited with this vault

get_deposit_manager_capability()

Return static public transaction-adapter support, if any.

This method deliberately does not attempt to construct a manager or query live pause, cap, epoch, balance, allow-list, or liquidity state. Adapters opt in only after their complete deposit and redemption lifecycles have focused coverage. None is therefore the safe default for unknown and protocol-specific vaults.

Returns

Adapter-specific capability object, or None when unsupported.

Return type

Optional[eth_defi.vault.deposit_redeem.VaultDepositManagerCapability]

is_whitelisted_deposit()

Determine whether this vault applies a deposit whitelist policy.

Protocol adapters override this predicate only when their deployed contract version exposes a reliable vault-wide policy read. True means the vault requires account permission; False means its policy is permissionless. This is independent of a caller’s current balance, allowance, pause state, capacity, and request lifecycle.

Returns

True for a whitelist-restricted vault and False for a permissionless vault.

Raises

NotImplementedError – If the adapter cannot safely determine the policy.

Return type

bool

is_account_whitelisted(address)

Determine whether an account belongs to the vault deposit policy.

The result concerns policy membership only. A protocol may still require scheduling, an allowance, available capacity, or an open epoch before a deposit can be submitted. Callers must use the relevant deposit manager pre-flight before broadcasting a transaction.

Parameters

address (eth_typing.evm.HexAddress) – Account whose deposit-policy membership is queried.

Returns

True when the account belongs to the applicable policy.

Raises

NotImplementedError – If the adapter cannot safely query account membership.

Return type

bool

abstract has_block_range_event_support()

Does this vault support block range-based event queries for deposits and redemptions.

  • If not we use chain balance polling-based approach

Return type

bool

abstract has_deposit_distribution_to_all_positions()

Deposits go automatically to all open positions.

  • Deposits do not land into the vault as cash

  • Instead, smart contracts automatically increase all open positions

  • The behaviour of Velvet Capital

Return type

bool

abstract fetch_portfolio(universe, block_identifier=None)

Read the current token balances of a vault.

  • SHould be supported by all implementations

Parameters
Return type

eth_defi.vault.base.VaultPortfolio

abstract fetch_info()

Read vault parameters from the chain.

Use info() property for cached access.

Return type

eth_defi.vault.base.VaultInfo

abstract get_flow_manager()

Get flow manager to read indiviaul settle events.

Return type

eth_defi.vault.base.VaultFlowManager

abstract get_deposit_manager()

Get deposit manager to deposit/redeem from the vault.

Return type

eth_defi.vault.deposit_redeem.VaultDepositManager

abstract get_historical_reader(stateful)

Get share price reader to fetch historical returns.

Parameters

stateful (bool) – If True, use a stateful reading strategy.

Returns

None if unsupported

Return type

eth_defi.vault.base.VaultHistoricalReader

fetch_denomination_token_address()

Get the address for the denomination token when one exists.

Synthetic accounting units used by some tokenised funds do not have an ERC-20 denomination token and return None.

This may trigger an RPC call.

Returns

ERC-20 denomination token address, or None for a synthetic accounting unit.

Return type

Optional[eth_typing.evm.HexAddress]

abstract fetch_denomination_token()

Read denomination token from onchain.

Use denomination_token() for cached access.

Return type

eth_defi.token.TokenDetails

abstract fetch_nav()

Fetch the most recent onchain NAV value.

Returns

Vault NAV, denominated in denomination_token()

Return type

decimal.Decimal

property denomination_token: Optional[eth_defi.token.TokenDetails]

Get the token which denominates the vault valuation

  • Used in deposits and redemptions

  • Used in NAV calculation

  • Used in profit benchmarks

  • Usually USDC

Returns

Token wrapper instance.

Maybe None for broken vaults like https://arbiscan.io/address/0x9d0fbc852deccb7dcdd6cb224fa7561efda74411#code

Note

None results are not cached — the next access will retry the on-chain call. This avoids permanently caching a transient RPC failure.

abstract fetch_share_token()

Read share token details onchain.

Use share_token() for cached access.

Return type

eth_defi.token.TokenDetails

property share_token: eth_defi.token.TokenDetails

ERC-20 that presents vault shares.

  • User gets shares on deposit and burns them on redemption

property info: eth_defi.vault.base.VaultInfo

Get info dictionary related to this vault deployment.

  • Get cached data on the various vault parameters

Returns

Vault protocol specific information dictionary

get_protocol_name()

Return the name of the vault protocol.

Return type

str

get_management_fee(block_identifier)

Get the current management fee as a percent.

Internal: Use get_fee_data().

Returns

0.1 = 10%

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) –

Return type

float

get_performance_fee(block_identifier)

Get the current performance fee as a percent.

Internal: Use get_fee_data().

Returns

0.1 = 10%

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) –

Return type

float

has_custom_fees()

Does this vault have fees outside the shared fee model.

Custom fees cause risk in vault comparison because the shared management/performance/deposit/withdraw fee fields cannot describe the full fee structure.

Do not return True merely because a vault implements custom accessors for ordinary management, performance, deposit, or withdraw fees. Return True only when some vault fee cannot be reflected in those standard fields as a fee-like value.

Returns

True if the vault has fees outside the shared fee model.

Return type

bool

get_deposit_fee(block_identifier)

Deposit fee is set to zero by default as vaults usually do not have deposit fees.

Internal: Use get_fee_data().

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) –

Return type

Optional[float]

get_withdraw_fee(block_identifier)

Withdraw fee is set to zero by default as vaults usually do not have withdraw fees.

Internal: Use get_fee_data().

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) –

Return type

float

get_risk()

Get risk profile of this vault.

Return type

Optional[eth_defi.vault.risk.VaultTechnicalRisk]

get_fee_mode()

Get how this vault accounts its fees.

Return type

Optional[eth_defi.vault.fee.VaultFeeMode]

get_fee_data()

Get fee data structure for this vault.

Raises

ValueError – In the case of broken or unimplemented fee reading methods in the smart contract

Return type

eth_defi.vault.fee.FeeData

get_estimated_lock_up()

What is the estimated lock-up period for this vault.

Returns

None if not know

Return type

Optional[datetime.timedelta]

fetch_deposit_closed_reason()

Get human-readable reason why deposits are closed.

  • Override in protocol-specific subclasses

  • Default behaviour: assume deposits are always open (return None)

Returns

Human-readable string explaining why deposits are closed, or None if deposits are open.

Example reasons:

  • ”Epoch redemption window closed (opens in 14h)”

  • ”Vault paused by admin”

  • ”Max deposit cap reached”

  • ”Vault utilisation too high”

Return type

Optional[str]

fetch_redemption_closed_reason()

Get human-readable reason why redemptions are closed.

  • Override in protocol-specific subclasses

  • Default behaviour: assume redemptions are always open (return None)

Returns

Human-readable string explaining why redemptions are closed, or None if redemptions are open.

Example reasons:

  • ”Epoch funding phase in progress (opens in 2d 5h)”

  • ”Vault paused by admin”

  • ”Vault utilisation too high - insufficient liquidity”

Return type

Optional[str]

fetch_deposit_next_open()

Get when deposits will next be open.

  • For epoch-based vaults (Ostium, D2), return calculated window open time

  • For non-epoch vaults (Plutus, IPOR, Morpho), return None

  • Override in protocol-specific subclasses

Returns

Naive UTC datetime when deposits will next be available, or None if:

  • Deposits are currently open

  • Timing is unpredictable (manually controlled)

  • Protocol does not support timing information

Return type

Optional[datetime.datetime]

fetch_redemption_next_open()

Get when withdrawals/redemptions will next be open.

  • For epoch-based vaults (Ostium, D2), return calculated window open time

  • For non-epoch vaults (Plutus, IPOR, Morpho), return None

  • Override in protocol-specific subclasses

Returns

Naive UTC datetime when withdrawals will next be available, or None if:

  • Withdrawals are currently open

  • Timing is unpredictable (manually controlled)

  • Protocol does not support timing information

Return type

Optional[datetime.datetime]

fetch_available_liquidity(block_identifier='latest')

Get the amount of denomination token available for immediate withdrawal.

Only applicable to lending protocol vaults (IPOR, Euler, Morpho, Gearbox, etc.). Non-lending protocols should leave this method unimplemented.

Note: maxRedeem(address(0)) does NOT work as a proxy for available liquidity because it requires a specific address that has already deposited shares. For address(0), balanceOf is always 0, so maxRedeem returns 0 regardless of actual liquidity.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) – Block to query. Defaults to “latest”.

Raises

NotImplementedError – For non-lending protocol vaults.

Returns

Amount in denomination token units (human-readable Decimal).

Return type

Optional[decimal.Decimal]

fetch_utilisation_percent(block_identifier='latest')

Get the percentage of assets currently lent out.

Only applicable to lending protocol vaults (IPOR, Euler, Morpho, Gearbox, etc.). Non-lending protocols should leave this method unimplemented.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) – Block to query. Defaults to “latest”.

Raises

NotImplementedError – For non-lending protocol vaults.

Returns

Utilisation as float between 0.0 and 1.0 (0% to 100%).

Return type

Optional[float]

get_flags()

Get various vault state flags from the smart contract.

Returns

Flag set.

Do not modify in place.

Return type

set[eth_defi.vault.flag.VaultFlag]

get_notes()

Get a human readable message if we know somethign special is going on with this vault.

Return type

Optional[str]

Get a link to the vault dashboard on its native site.

  • By default, give RouteScan link

Parameters

referral (Optional[str]) – Optional referral code to append to the URL.

Returns

URL string

Return type

str