mellow.vault
Documentation for eth_defi.mellow.vault Python module.
Mellow Core Vault adapter.
Mellow Core Vaults are modular asset-management vaults for curated on-chain yield products. They are not ERC-4626 vault contracts, even though the shared scanner stores them in the ERC-4626-flavoured detection envelope for pipeline compatibility.
Backfill scan instructions
Mellow discovery is based on Core Vault factory Created events. The normal
production scanner is incremental, so Mellow vaults created before Mellow support
was deployed are not discovered by later incremental scans unless the historical
lead range is scanned again.
Historical Mellow lead recovery requires a generated, protocol-specific
migration script. The incremental scanner does not re-read old factory events,
and whole-chain lead resets are not supported. See
eth_defi/erc_4626/README-vault-leads.md for the migration requirements.
After the metadata backfill, rescan prices for the known Lido Mellow Core Vaults
with a targeted VAULT_ID run. Targeted price scans clear saved reader state
only for the selected vaults, and parquet deletion is vault-aware, so price data
for unrelated vaults is preserved.
source .local-test.env
VAULT_ID="1-0x277c6a642564a91ff78b008022d65683cee5ccc5,1-0x6a37725ca7f4ce81c004c955f7280d5c704a249e,1-0x014e6da8f283c4af65b2aa0f201438680a004452" START_BLOCK=1 LOG_LEVEL=info JSON_RPC_URL=$JSON_RPC_ETHEREUM poetry run python scripts/erc-4626/scan-prices.py
Run the usual post-processing and export steps after the discovery and targeted price scans complete.
The current Core Vault factory registry follows Mellow’s public Core deployments for Ethereum mainnet, Plasma, Arbitrum and Monad. Base remains configuration-only until a canonical Core factory is published.
The canonical adapter address is the Mellow Vault proxy emitted by the Core
Vault Factory.Created event. This address coordinates the vault, owns the
component graph and is the address stored in VaultSpec and
ERC4262VaultDetection. It is not the ERC-20 share token address.
Mellow splits vault functionality across several contracts:
Vault: the central entry point. It combines access control, share module lifecycle methods and subvault delegation. In scanner terms it is the vault identity.ShareManager: share accounting, allocation, whitelist, lockup and transfer-control contract. Tokenised variants expose ERC-20 metadata andtotalSupply(); this initial adapter only supports those tokenised managers.DepositQueueandSignatureDepositQueue: per-asset deposit entry points. Standard queues are time-buffered and oracle-report settled; signature queues allow trusted off-chain approvals. Deposit events are expected here, not on the canonicalVaultaddress.RedeemQueueandSignatureRedeemQueue: per-asset redemption entry points. Redemptions are asynchronous, oracle-report settled and can involve curator-managed liquidity pulls from subvaults. Redeem events are expected here.Oracle: vault-coupled price-reporting contract. Reports drive queue settlement, fee updates, limits and suspicious-price checks. Mellow reportspriceD18as raw shares per raw asset, so this adapter converts it to the normal asset-per-share price convention used by the shared vault pipeline.FeeManager: deposit, redeem, performance and protocol fee accounting. Fees are configured as D6 rates and paid in vault shares, not in underlying assets. The shared vault schema does not have a separate protocol-fee column, so the adapter maps Mellow’s annual time-basedprotocolFeeD6to the management-fee field and documents it as management-like.RiskManager: asset support, deposit limits, balances and pending asset accounting across the vault and its subvaults.Subvaultand verifiers: controlled execution/custody compartments whose external calls are constrained by verifier contracts and access roles.
This differs from ERC-4626 in the important accounting places. A generic
ERC-4626 reader expects the vault contract to expose asset(),
totalAssets(), convertToAssets() and usually the share-token ERC-20
surface. Mellow instead has a separate share manager, multiple queue contracts
and oracle-driven settlement. Calling ERC-4626 methods on the canonical vault
would either fail or describe the wrong abstraction.
Historical reading is therefore Mellow-specific. The first reader records the
tokenised ShareManager.totalSupply() and reads the latest oracle report for
the denomination asset. Mellow oracle priceD18 is oriented as raw
shares = assets * priceD18 / 1e18; the adapter converts it to our
asset-per-share VaultHistoricalRead.share_price by accounting for the
share-token and denomination-token decimals. The pipeline stores
deposit_count=0 and
redeem_count=0 for initial Mellow leads because the canonical vault address
does not emit user flow events; ERC4626Feature.mellow_like is the explicit
activity-filter exemption that keeps these vaults in downstream scans.
Current scan-record TVL uses the same denomination-token accounting convention
as the historical reader: Mellow oracle share price multiplied by tokenised
ShareManager.totalSupply(). Public API USD TVL is kept as off-chain
diagnostics and is not used for NAV.
Known unsupported cases:
Non-tokenised
BasicShareManagercontracts.Active deposit and redemption transaction execution.
Queue flow accounting from
DepositQueueandRedeemQueuecontracts.Full portfolio composition and subvault-level NAV breakdowns.
Reference material:
Functions
|
Convert Mellow D6 fee rate to fractional percent. |
Convert Mellow |
Classes
Mellow FeeManager configuration snapshot. |
|
Latest Mellow oracle report for an asset. |
|
Mellow Core Vault adapter. |
|
Mellow component graph metadata. |
Exceptions
Raised when a Mellow feature is not implemented by this adapter. |
Convert Mellow
priceD18to denomination-token assets per share.Mellow Core Vault reports use raw-token accounting:
raw_shares = raw_assets * priceD18 / 1e18. Our historical vault price convention is human-readable denomination-token assets per one human-readable share token.- Parameters
- Returns
Human-readable asset amount per one human-readable share, or
Nonefor a zero oracle price.- Return type
- convert_mellow_fee_d6_to_percent(fee_d6)
Convert Mellow D6 fee rate to fractional percent.
Mellow stores fee rates as parts-per-million integers:
10_000means1%. The shared vault fee interface expects fractional values where0.01means1%.
- exception MellowVaultUnsupportedError
Bases:
RuntimeErrorRaised when a Mellow feature is not implemented by this adapter.
- __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 MellowVaultInfo
Bases:
eth_defi.vault.base.VaultInfoMellow component graph metadata.
- vault: eth_typing.evm.HexAddress
Canonical Mellow Vault address.
Tokenised ShareManager address.
- fee_manager: Optional[eth_typing.evm.HexAddress]
FeeManager address, if the call succeeds.
- risk_manager: Optional[eth_typing.evm.HexAddress]
RiskManager address, if the call succeeds.
- oracle: Optional[eth_typing.evm.HexAddress]
Oracle address, if the call succeeds.
- assets: list[eth_typing.evm.HexAddress]
Registered asset addresses.
- deposit_queues: dict[eth_typing.evm.HexAddress, list[eth_typing.evm.HexAddress]]
Deposit queue addresses keyed by asset.
- redeem_queues: dict[eth_typing.evm.HexAddress, list[eth_typing.evm.HexAddress]]
Redeem queue addresses keyed by asset.
- __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 MellowFeeConfiguration
Bases:
objectMellow FeeManager configuration snapshot.
- fee_recipient: eth_typing.evm.HexAddress
Address that receives fee shares.
- base_asset: eth_typing.evm.HexAddress
Base asset configured for this vault.
- __init__(fee_recipient, deposit_fee_d6, redeem_fee_d6, performance_fee_d6, protocol_fee_d6, base_asset, timestamp, min_price_d18)
- Parameters
fee_recipient (eth_typing.evm.HexAddress) –
deposit_fee_d6 (int) –
redeem_fee_d6 (int) –
performance_fee_d6 (int) –
protocol_fee_d6 (int) –
base_asset (eth_typing.evm.HexAddress) –
timestamp (int) –
min_price_d18 (int) –
- Return type
None
- class MellowVault
Bases:
eth_defi.vault.base.VaultBaseMellow Core Vault adapter.
Create a Mellow vault adapter.
- Parameters
web3 – Web3 connection.
spec – Chain/address vault identity. Address must be the Mellow
Vault.token_cache – Token metadata cache.
features – Shared scanner feature set. Expected to contain
mellow_like.default_block_identifier – Block used for metadata reads.
require_denomination_token – Whether missing denomination token should raise through the base cached property.
api_metadata – Optional offchain Mellow metadata enrichment.
- __init__(web3, spec, token_cache=None, features=None, default_block_identifier=None, require_denomination_token=False, api_metadata=None)
Create a Mellow vault adapter.
- Parameters
web3 (web3.main.Web3) – Web3 connection.
spec (eth_defi.vault.base.VaultSpec) – Chain/address vault identity. Address must be the Mellow
Vault.features (Optional[set[eth_defi.erc_4626.core.ERC4626Feature]]) – Shared scanner feature set. Expected to contain
mellow_like.default_block_identifier (Optional[Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]]) – Block used for metadata reads.
require_denomination_token (bool) – Whether missing denomination token should raise through the base cached property.
api_metadata (Optional[eth_defi.mellow.offchain_metadata.MellowApiVaultMetadata]) – Optional offchain Mellow metadata enrichment.
- property address: eth_typing.evm.HexAddress
Canonical Mellow
Vaultaddress.
- property vault_address: eth_typing.evm.HexAddress
Canonical Mellow
Vaultaddress.ERC-4626 adapters expose this convenience property and shared historical scan code still uses it for blacklists and diagnostics. For Mellow this is intentionally the Core
Vaultproxy, not the ShareManager token.
- property vault_contract: web3.contract.contract.Contract
Mellow
Vaultcontract with minimal ABI.
Fetch the ShareManager address from the vault.
Tokenised ShareManager contract with ERC-20 ABI.
- property oracle_address: eth_typing.evm.HexAddress
Fetch the Mellow oracle address from the vault.
- property oracle_contract: web3.contract.contract.Contract
Mellow oracle contract with minimal ABI.
- property fee_manager_address: eth_typing.evm.HexAddress
Fetch the Mellow FeeManager address from the vault.
- property fee_manager_contract: web3.contract.contract.Contract
Mellow FeeManager contract with minimal ABI.
Return the tokenised ShareManager address.
Fetch tokenised ShareManager ERC-20 metadata.
- Returns
Share token details.
- Return type
- fetch_denomination_token_address()
Fetch the base asset used for initial valuation.
The initial adapter uses API/configured base token if present, otherwise falls back to the first registered asset. Mellow can be multi-asset, so all registered assets remain available in
fetch_info().- Returns
Base asset address, or
Noneif unavailable.- Return type
- fetch_denomination_token()
Fetch the denomination token metadata.
- Returns
Token details for the base asset, or
None.- Return type
- fetch_assets()
Fetch registered asset addresses.
- Returns
List of registered assets.
- Return type
- fetch_queues(asset)
Fetch queues for a registered asset.
- Parameters
asset (eth_typing.evm.HexAddress) – Registered asset address.
- Returns
Deposit queues and redeem queues.
- Return type
tuple[list[eth_typing.evm.HexAddress], list[eth_typing.evm.HexAddress]]
- fetch_info()
Fetch Mellow component graph metadata.
- Returns
Component graph metadata.
- Return type
- fetch_total_supply(block_identifier='latest')
Fetch tokenised ShareManager total supply.
- fetch_oracle_report(asset=None, block_identifier='latest')
Fetch the latest Mellow oracle report for an asset.
- Parameters
asset (Optional[eth_typing.evm.HexAddress]) – Asset address. Defaults to
denomination_token.block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) – Block number or tag.
- Returns
Oracle report, or
Noneif the report cannot be read.- Return type
Fetch Mellow share price from the oracle report.
Mellow reports
priceD18as raw shares per raw asset:shares = assets * priceD18 / 1e18. This method converts it to the shared vault pipeline convention, denomination-token assets per one human-readable share token.
- fetch_fee_configuration(block_identifier='latest')
Fetch Mellow FeeManager configuration.
Mellow stores all configured rates in D6 precision.
protocolFeeD6is the annual time-based fee; the adapter maps it to the shared management-fee field because the shared schema has no separate protocol fee column.
- get_fee_data()
Return Mellow fee data.
Mellow fees are configured through
FeeManageras D6 rates and paid in vault shares.protocolFeeD6is an annual time-based fee, so it is mapped to the shared management-fee field.performanceFeeD6maps to the performance-fee field, while deposit and redeem D6 rates map to the shared deposit and withdraw fee fields.- Returns
Fee data, or
BROKEN_FEE_DATAif the FeeManager cannot be read.- Return type
- fetch_scan_record_extra_data()
Fetch Mellow-specific private scan row columns.
_mellow_infopreserves the component graph that the initial Mellow-only scan branch exposed before Mellow was moved to the shared vault scan path.
- fetch_total_assets(block_identifier='latest')
Fetch Mellow denomination-token TVL from on-chain share accounting.
Mellow does not expose ERC-4626
totalAssets()on the canonical vault. For comparable scanner output we use the same on-chain accounting identity as the historical reader: oracle share price in the denomination token multiplied by tokenisedShareManager.totalSupply. The public API USD TVL is not used here.- 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 or tag.
- Returns
Human-readable denomination-token TVL, or
Noneif either price or supply is unavailable.- Return type
Fetch Mellow NAV.
fetch_nav()is kept as theVaultBase-compatible alias for current scanner reads. It returns the same denomination-token value asfetch_total_assets(), not the public API USD TVL.
- fetch_portfolio(universe, block_identifier=None)
Fetch a partial portfolio.
The initial adapter does not reconstruct subvault balances. It returns an empty portfolio instead of pretending to know full Mellow holdings.
- Parameters
universe (eth_defi.vault.base.TradingUniverse) – Trading universe.
block_identifier (Optional[Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]]) – Block number or tag.
- Returns
Empty portfolio placeholder.
- Return type
- has_block_range_event_support()
Whether queue event scanning is implemented.
- Returns
Falseuntil Mellow queue flow reader is implemented.- Return type
- has_deposit_distribution_to_all_positions()
Whether deposits are automatically distributed to positions.
- Returns
Falsebecause Mellow deposits settle through queues and curator/subvault allocation.- Return type
- get_flow_manager()
Get Mellow flow manager.
- Returns
Placeholder flow manager that raises for all read methods.
- Return type
- get_deposit_manager()
Get active deposit manager.
- Returns
Never returns until active queue transaction execution is implemented.
- Return type
- get_historical_reader(stateful)
Get the Mellow historical reader.
- Parameters
stateful (bool) – Whether to use shared adaptive reader state.
- Returns
Mellow historical reader.
- Return type
- has_custom_fees()
Whether Mellow has fees outside the shared fee model.
Mellow FeeManager fees are all represented by
FeeData:protocolFeeD6is management-like,performanceFeeD6is performance-like, anddepositFeeD6/redeemFeeD6map to the standard deposit/withdraw fields.- Returns
Falsebecause no Mellow FeeManager fee is outside the shared fee fields.- Return type
- get_management_fee(block_identifier)
Fetch management-like fee.
Mellow calls this value
protocolFeeD6: an annual time-based fee charged in vault shares. We expose it through the shared management fee column because the generic vault schema has no separate protocol-fee field.
- get_performance_fee(block_identifier)
Fetch performance fee.
Mellow stores performance fees in D6 precision and charges them in vault shares when oracle reports update the FeeManager state.
- get_deposit_fee(block_identifier)
Fetch deposit fee.
Mellow stores deposit fees in D6 precision and charges them in vault shares during deposit queue report handling.
- get_withdraw_fee(block_identifier)
Fetch redeem fee.
Mellow names this value
redeemFeeD6. The shared vault interface uses the withdraw fee field for the same user-facing redemption charge.
- get_link(referral=None)
Get Mellow vault link.
- 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
Noneresults are not cached — the next access will retry the on-chain call. This avoids permanently caching a transient RPC failure.
- property deposit_manager: eth_defi.vault.deposit_redeem.VaultDepositManager
Deposit manager assocaited with this vault
- 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
- 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
- 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)
- 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
- 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)
- 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
- 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
- property flow_manager: eth_defi.vault.base.VaultFlowManager
Flow manager associated 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.
Noneis therefore the safe default for unknown and protocol-specific vaults.- Returns
Adapter-specific capability object, or
Nonewhen unsupported.- Return type
Optional[eth_defi.vault.deposit_redeem.VaultDepositManagerCapability]
- get_estimated_lock_up()
What is the estimated lock-up period for this vault.
- Returns
None if not know
- Return type
- get_fee_mode()
Get how this vault accounts its fees.
- Return type
- get_flags()
Get various vault state flags from the smart contract.
Override to add status flags
Also add flags from our manual flag list in
eth_defi.vault.flag
- Returns
Flag set.
Do not modify in place.
- Return type
- get_notes()
Get a human readable message if we know somethign special is going on with this vault.
- get_risk()
Get risk profile of this vault.
- Return type
- 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
- 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
ERC-20 that presents vault shares.
User gets shares on deposit and burns them on redemption
- property short_description: Optional[str]
One-liner vault summary.
Shorter version of
description()suitable for listings and tablesReturns None if not available
Override in subclasses that support offchain metadata