erc_4626.vault_protocol.royco.vault

Documentation for eth_defi.erc_4626.vault_protocol.royco.vault Python module.

Royco Protocol WrappedVault support.

Classes

RoycoAssetClaims

Royco tranche asset claims.

RoycoTrancheHistoricalReader

Read Royco tranche vault history with tuple-aware accounting.

RoycoTrancheVault

Royco senior/junior tranche vault support.

RoycoVault

Royco Protocol WrappedVault support.

class RoycoAssetClaims

Bases: object

Royco tranche asset claims.

Royco tranche vaults return this struct from totalAssets(), convertToAssets(uint256), previewRedeem(uint256) and redeem(...).

__init__(st_assets, jt_assets, nav)
Parameters
  • st_assets (int) –

  • jt_assets (int) –

  • nav (int) –

Return type

None

convert_jt_assets_to_decimal(tranche_unit_token)

Convert junior tranche asset claims to a decimal value.

Royco’s AssetClaims struct stores tranche asset claims as raw token-like units. Use eth_defi.token.TokenDetails for the conversion so the caller chooses the correct unit precision instead of hardcoding decimals.

Parameters

tranche_unit_token (eth_defi.token.TokenDetails) – Token details that define the junior tranche asset unit precision.

Returns

Junior tranche asset claims as a decimal value.

Return type

decimal.Decimal

convert_nav_to_decimal(nav_unit_token)

Convert Royco raw NAV units to a decimal value.

Royco’s ABI exposes NAV values as NAV_UNIT instead of a plain ERC-20 asset amount. For the currently deployed tranche contracts, this unit uses the tranche share token precision, while the denomination token may have a different number of decimals. Use eth_defi.token.TokenDetails for the conversion so the reader does not hardcode token precision.

Parameters

nav_unit_token (eth_defi.token.TokenDetails) – Token details that define the NAV unit decimal precision.

Returns

Decimal NAV value.

Return type

decimal.Decimal

convert_st_assets_to_decimal(tranche_unit_token)

Convert senior tranche asset claims to a decimal value.

Royco’s AssetClaims struct stores tranche asset claims as raw token-like units. Use eth_defi.token.TokenDetails for the conversion so the caller chooses the correct unit precision instead of hardcoding decimals.

Parameters

tranche_unit_token (eth_defi.token.TokenDetails) – Token details that define the senior tranche asset unit precision.

Returns

Senior tranche asset claims as a decimal value.

Return type

decimal.Decimal

class RoycoTrancheHistoricalReader

Bases: eth_defi.erc_4626.vault.ERC4626HistoricalReader

Read Royco tranche vault history with tuple-aware accounting.

Royco senior/junior tranche vaults return AssetClaims from totalAssets() and convertToAssets(uint256). The generic ERC-4626 reader silently decodes only the first word of the tuple, which is stAssets and not necessarily the vault NAV. This reader decodes the whole tuple and uses claims.nav for value and share price.

__init__(vault, stateful)
Parameters
construct_core_erc_4626_multicall()

Polling endpoints defined in ERC-4626 spec.

  • Does not include fee calls which do not have standard

Return type

Iterable[eth_defi.event_reader.multicall_batcher.EncodedCall]

construct_multicalls()

Get the onchain calls that are needed to read the share price.

Return type

collections.abc.Iterable[eth_defi.event_reader.multicall_batcher.EncodedCall]

dictify_multicall_results(block_number, call_results, allow_failure=True)

Convert batch of multicalls made for this vault to more digestible dict.

  • Assert that all multicalls succeed

Returns

Dictionary where each multicall is keyed by its EncodedCall.extra_data["function"]

Parameters
Return type

dict[str, eth_defi.event_reader.multicall_batcher.EncodedCallResult]

get_warmup_calls()

Yield (function_name, callable, contract_call) tuples for warmup testing.

Each callable should execute a single contract call. If it raises, the function is marked as broken.

The optional contract_call is used for gas estimation to detect expensive calls before executing them. If provided, calls using excessive gas (>1M gas) will be marked as broken without execution.

Override in subclasses to add protocol-specific calls.

Returns

Iterable of (function_name, test_callable, contract_call) tuples. contract_call may be None if gas estimation is not needed.

Return type

Iterable[tuple[str, callable, Any]]

process_core_erc_4626_result(call_by_name)

Decode common ERC-4626 calls.

Parameters

call_by_name (dict[str, eth_defi.event_reader.multicall_batcher.EncodedCallResult]) –

Return type

tuple

process_result(block_number, timestamp, call_results)

Process the result of mult

  • Calls are created in construct_multicalls()

  • This method combines result of this calls to a easy to manage historical record VaultHistoricalRead

Parameters
Return type

eth_defi.vault.base.VaultHistoricalRead

should_skip_call(function_name)

Check if a specific function call should be skipped.

Uses the reader state’s call_status map if available.

Parameters

function_name (str) – The function name to check

Returns

True if the call should be skipped

Return type

bool

class RoycoTrancheVault

Bases: eth_defi.erc_4626.vault_protocol.royco.vault.RoycoVault

Royco senior/junior tranche vault support.

Royco tranche vaults are nearly ERC-4626, but use a custom accounting interface:

  • totalAssets() returns AssetClaims(stAssets, jtAssets, nav)

  • convertToAssets(uint256) returns the same AssetClaims tuple

  • redeem(...) returns AssetClaims and emits Redeem instead of the standard ERC-4626 Withdraw event

  • TRANCHE_TYPE() returns 0 for senior and 1 for junior

The canonical value for vault price history is AssetClaims.nav in Royco NAV_UNIT precision. The standard ERC-4626 reader only decodes the first tuple word, so this class provides tuple-aware current and historical readers and converts raw NAV values through the tranche token eth_defi.token.TokenDetails.

Examples:

Parameters
  • web3 – Connection we bind this instance to

  • spec – Chain, address tuple

  • token_cache

    Cache used with fetch_erc20_details() to avoid multiple calls to the same token.

    Reduces the number of RPC calls when scanning multiple vaults.

  • features – Pass vault feature flags along, externally detected.

  • default_block_identifier

    Override block identifier for on-chain metadata reads.

    When None, use get_safe_cached_latest_block_number() (the default, safe for broken RPCs). Set to "latest" for freshly deployed vaults whose contracts do not exist at the safe-cached block.

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

__init__(web3, spec, token_cache=None, features=None, default_block_identifier=None, require_denomination_token=False)
Parameters
  • web3 (web3.main.Web3) – Connection we bind this instance to

  • spec (eth_defi.vault.base.VaultSpec) – Chain, address tuple

  • token_cache (Optional[dict]) –

    Cache used with fetch_erc20_details() to avoid multiple calls to the same token.

    Reduces the number of RPC calls when scanning multiple vaults.

  • features (Optional[set[eth_defi.erc_4626.core.ERC4626Feature]]) – Pass vault feature flags along, externally detected.

  • default_block_identifier (Optional[Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, hexbytes.main.HexBytes, int]]) –

    Override block identifier for on-chain metadata reads.

    When None, use get_safe_cached_latest_block_number() (the default, safe for broken RPCs). Set to "latest" for freshly deployed vaults whose contracts do not exist at the safe-cached block.

  • require_denomination_token (bool) – If True, accessing denomination_token will raise RuntimeError when the on-chain lookup returns None.

property address: eth_typing.evm.HexAddress

Get the vault smart contract address.

can_check_deposit()

Check if maxDeposit(address(0)) can be used to check global deposit availability.

Most ERC-4626 vaults implement maxDeposit in a way that returns meaningful values when called with address(0):

  • Returns 0 when deposits are globally closed/capped

  • Returns a positive value indicating maximum deposit allowed

Override to return False in subclasses where maxDeposit(address(0)) doesn’t provide meaningful global availability information.

Returns

True if maxDeposit(address(0)) returns meaningful values for global deposit availability checking.

Return type

bool

can_check_redeem()

Check if maxRedeem(address(0)) can be used to check global redemption availability.

Most protocols return 0 for maxRedeem(address(0)) because that address has no balance/shares, not because redemptions are closed:

  • Gearbox: maxRedeem returns min(balanceOf(owner), convertToShares(availableLiquidity))

  • Most vaults: Return 0 because address(0) has no shares

Some protocols do use maxRedeem(address(0)) meaningfully:

  • Morpho, IPOR, Plutus: Return 0 when redemptions are globally blocked

Override to return True in subclasses that support address(0) redemption checks.

Returns

True if maxRedeem(address(0)) returns meaningful values for global redemption availability checking.

Return type

bool

property chain_id: int

Chain this vault is on

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.

property deposit_manager: eth_defi.vault.deposit_redeem.VaultDepositManager

Deposit manager assocaited with this vault

property description: Optional[str]

Full vault description from Royco offchain metadata.

property erc_7540: bool

Is this ERC-7540 vault with asynchronous deposits.

  • For example previewDeposit() function and other functions will revert

fetch_asset_claims(block_identifier='latest')

Fetch current Royco tranche AssetClaims.

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.

Returns

Decoded asset claims from totalAssets().

Return type

eth_defi.erc_4626.vault_protocol.royco.vault.RoycoAssetClaims

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_denomination_token()

Read denomination token from onchain.

Use denomination_token() for cached access.

Return type

Optional[eth_defi.token.TokenDetails]

fetch_denomination_token_address()

Get the asset() denomination token address of this vault.

Results are disk-cached per (chain_id, vault_address) via eth_defi.erc_4626.vault_token when the vault was constructed with a eth_defi.token.TokenDiskCache and no pinned default_block_identifier. The denomination token is immutable post-deployment, so the cached value is correct regardless of which block the caller would have asked for.

Only a definitive non-null answer is persisted. The None path taken on revert / broken contract is never cached, matching the behaviour of eth_defi.vault.base.VaultBase.denomination_token() which explicitly avoids memoising None so transient failures can be retried.

To disable the cache, pass token_cache=None (or any non- TokenDiskCache dict) when constructing the vault, or construct with a pinned default_block_identifier.

Returns

Denomination token address, or None if the vault contract is broken and did not return a valid address.

Return type

Optional[eth_typing.evm.HexAddress]

fetch_deposit_closed_reason()

Check if deposits are closed using maxDeposit(address(0)).

Uses the ERC-4626 standard maxDeposit function to determine if deposits are available. Returns a human-readable reason with the max deposit amount if deposits are restricted.

Returns

Human-readable string if deposits are closed/restricted, or None if deposits are open (maxDeposit > 0).

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_info()

Use info() property for cached access.

Returns

See LagoonVaultInfo

Return type

eth_defi.erc_4626.vault.ERC4626VaultInfo

fetch_nav(block_identifier=None)

Fetch current tranche NAV from Royco AssetClaims.nav.

Parameters

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

Returns

Vault NAV in Royco NAV units.

Return type

decimal.Decimal

fetch_portfolio(universe, block_identifier=None, allow_fallback=True)

Read the current token balances of a vault.

  • SHould be supported by all implementations

Parameters
Return type

eth_defi.vault.base.VaultPortfolio

fetch_redemption_closed_reason()

Check if redemptions are closed using maxRedeem(address(0)).

Only works for protocols that implement maxRedeem in a way that returns meaningful values for address(0). Most protocols return 0 because address(0) has no shares, not because redemptions are closed.

Returns

Human-readable string if redemptions are closed, or None if redemptions are open or check is not supported.

Return type

Optional[str]

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_share_price(block_identifier)

Fetch share price from convertToAssets(1 share).nav.

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.

Returns

Share price in Royco NAV units.

Return type

decimal.Decimal

fetch_share_token()

Read share token details onchain.

Use share_token() for cached access.

Return type

eth_defi.token.TokenDetails

fetch_share_token_address(block_identifier='latest')

Get share token of this vault.

  • Vault itself (ERC-4626)

  • share() accessor (ERC-7575)

Results are disk-cached per (chain_id, vault_address) via eth_defi.erc_4626.vault_token when the vault was constructed with a eth_defi.token.TokenDiskCache. Under normal circumstances the block_identifier argument is effectively ignored on cache hits — ERC-4626 share tokens are immutable post-deployment, so the cached value is correct regardless of which block the caller asked for.

Only a definitive answer from the chain is ever persisted: a successful call, or a revert matching KNOWN_SHARE_TOKEN_ERROR_MESSAGES (which positively classifies the contract as non-ERC-7575). Transient RPC failures (ProbablyNodeHasNoBlock, HTTP 502) fall back to self.vault_address but are not written to the cache, so a flaky node cannot poison a real ERC-7575 vault’s entry.

To disable the cache, pass token_cache=None (or any non- TokenDiskCache dict) when constructing the vault, or construct with a pinned default_block_identifier to force the uncached historical-read path on every call.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, hexbytes.main.HexBytes, int]) – Block to query. Cache is only consulted/written when the caller passes the default "latest" and the vault instance has no pinned default_block_identifier.

Return type

eth_typing.evm.HexAddress

fetch_total_assets(block_identifier)

Fetch the tranche NAV from AssetClaims.nav.

Royco’s totalAssets() does not return a single ERC-4626 asset amount. It returns AssetClaims where nav is the full net asset value in Royco NAV_UNIT precision.

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.

Returns

Vault NAV in Royco NAV units.

Return type

decimal.Decimal

fetch_total_supply(block_identifier)

What is the current outstanding shares.

Example:

Parameters

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

Block number to read.

Use web3.eth.block_number for the last block.

Returns

The vault value in underlyinh token

Return type

decimal.Decimal

fetch_tranche_type(block_identifier='latest')

Fetch Royco tranche type.

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.

Returns

0 for senior tranche and 1 for junior tranche.

Return type

int

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]

fetch_vault_info()

Get all information we can extract from the vault smart contracts.

Return type

eth_defi.erc_4626.vault.ERC4626VaultInfo

property flow_manager: eth_defi.vault.base.VaultFlowManager

Flow manager associated with this vault

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_deposit_manager()

Get deposit manager to deposit/redeem from the vault.

Return type

eth_defi.erc_4626.deposit_redeem.ERC4626DepositManager

get_estimated_lock_up()

Lock-up depends on the underlying vault.

Return type

Optional[datetime.timedelta]

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_fee_mode()

Get how this vault accounts its fees.

Return type

Optional[eth_defi.vault.fee.VaultFeeMode]

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_flow_manager()

Get flow manager to read indiviaul settle events.

Return type

eth_defi.vault.base.VaultFlowManager

get_historical_reader(stateful)

Get share price reader to fetch historical returns.

Parameters

stateful – If True, use a stateful reading strategy.

Returns

None if unsupported

Return type

eth_defi.vault.base.VaultHistoricalReader

Link to Royco homepage.

Individual vault pages are not available on the Royco interface.

Parameters

referral (Optional[str]) –

Return type

str

get_management_fee(block_identifier)

Fees are determined by the underlying wrapped vault.

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_notes()

Get notes for this vault.

Falls back to Royco’s offchain description when manual vault notes are not available.

Return type

Optional[str]

get_performance_fee(block_identifier)

Fees are determined by the underlying wrapped vault.

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_protocol_name()

Return the name of the vault protocol.

Return type

str

get_risk()

Get risk profile of this vault.

Return type

Optional[eth_defi.vault.risk.VaultTechnicalRisk]

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

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

has_custom_fees()

Royco vaults wrap underlying vaults.

Fees are handled by the underlying wrapped vault, not by the wrapper itself.

Return type

bool

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

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

is_valid()

Check if this vault is valid.

  • Call a known smart contract function to verify the function exists

Return type

bool

property name: str

Vault name.

property royco_metadata: Optional[eth_defi.erc_4626.vault_protocol.royco.offchain_metadata.RoycoOffchainVaultMetadata]

Offchain metadata from Royco’s first-party API.

This covers Royco vault/explore rows and classic Royco market/explore Vault Market rows.

property share_token: eth_defi.token.TokenDetails

ERC-20 that presents vault shares.

  • User gets shares on deposit and burns them on redemption

property short_description: Optional[str]

Short display name from Royco offchain metadata.

property symbol: str

Vault share token symbol

property underlying_token: eth_defi.token.TokenDetails

Alias for denomination_token()

property vault_contract: web3.contract.contract.Contract

Get vault deployment with Royco tranche ABI.

Senior and junior tranche implementations expose the same external function/event surface for scanner purposes. We use the senior ABI as the shared runtime interface while storing both verified implementation ABIs under eth_defi/abi/royco. See eth_defi/abi/royco/README.md for provenance notes.

class RoycoVault

Bases: eth_defi.erc_4626.vault.ERC4626Vault

Royco Protocol WrappedVault support.

Royco is an Incentivised Action Market (IAM) Protocol that allows protocols to create incentivised ERC-4626 vault wrappers with integrated rewards systems. The WrappedVault contract wraps underlying vaults and adds reward distribution functionality, supporting multiple simultaneous reward programmes.

Contract addresses: - WrappedVaultFactory: 0x75e502644284edf34421f9c355d75db79e343bca - WrappedVault implementation: 0x3c44c20377e252567d283dc7746d1bea67eb3e66 - VaultMarketHub: 0xa97eCc6Bfda40baf2fdd096dD33e88bd8e769280

Audits: - Spearbit (October 2024) - Cantina Private Competition - Cantina Open Competition

See: https://docs.royco.org/for-incentive-providers/audits

Parameters
  • web3 – Connection we bind this instance to

  • spec – Chain, address tuple

  • token_cache

    Cache used with fetch_erc20_details() to avoid multiple calls to the same token.

    Reduces the number of RPC calls when scanning multiple vaults.

  • features – Pass vault feature flags along, externally detected.

  • default_block_identifier

    Override block identifier for on-chain metadata reads.

    When None, use get_safe_cached_latest_block_number() (the default, safe for broken RPCs). Set to "latest" for freshly deployed vaults whose contracts do not exist at the safe-cached block.

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

__init__(web3, spec, token_cache=None, features=None, default_block_identifier=None, require_denomination_token=False)
Parameters
  • web3 (web3.main.Web3) – Connection we bind this instance to

  • spec (eth_defi.vault.base.VaultSpec) – Chain, address tuple

  • token_cache (Optional[dict]) –

    Cache used with fetch_erc20_details() to avoid multiple calls to the same token.

    Reduces the number of RPC calls when scanning multiple vaults.

  • features (Optional[set[eth_defi.erc_4626.core.ERC4626Feature]]) – Pass vault feature flags along, externally detected.

  • default_block_identifier (Optional[Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, hexbytes.main.HexBytes, int]]) –

    Override block identifier for on-chain metadata reads.

    When None, use get_safe_cached_latest_block_number() (the default, safe for broken RPCs). Set to "latest" for freshly deployed vaults whose contracts do not exist at the safe-cached block.

  • require_denomination_token (bool) – If True, accessing denomination_token will raise RuntimeError when the on-chain lookup returns None.

property address: eth_typing.evm.HexAddress

Get the vault smart contract address.

can_check_deposit()

Check if maxDeposit(address(0)) can be used to check global deposit availability.

Most ERC-4626 vaults implement maxDeposit in a way that returns meaningful values when called with address(0):

  • Returns 0 when deposits are globally closed/capped

  • Returns a positive value indicating maximum deposit allowed

Override to return False in subclasses where maxDeposit(address(0)) doesn’t provide meaningful global availability information.

Returns

True if maxDeposit(address(0)) returns meaningful values for global deposit availability checking.

Return type

bool

can_check_redeem()

Check if maxRedeem(address(0)) can be used to check global redemption availability.

Most protocols return 0 for maxRedeem(address(0)) because that address has no balance/shares, not because redemptions are closed:

  • Gearbox: maxRedeem returns min(balanceOf(owner), convertToShares(availableLiquidity))

  • Most vaults: Return 0 because address(0) has no shares

Some protocols do use maxRedeem(address(0)) meaningfully:

  • Morpho, IPOR, Plutus: Return 0 when redemptions are globally blocked

Override to return True in subclasses that support address(0) redemption checks.

Returns

True if maxRedeem(address(0)) returns meaningful values for global redemption availability checking.

Return type

bool

property chain_id: int

Chain this vault is on

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.

property deposit_manager: eth_defi.vault.deposit_redeem.VaultDepositManager

Deposit manager assocaited with this vault

property description: Optional[str]

Full vault description from Royco offchain metadata.

property erc_7540: bool

Is this ERC-7540 vault with asynchronous deposits.

  • For example previewDeposit() function and other functions will revert

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_denomination_token()

Read denomination token from onchain.

Use denomination_token() for cached access.

Return type

Optional[eth_defi.token.TokenDetails]

fetch_denomination_token_address()

Get the asset() denomination token address of this vault.

Results are disk-cached per (chain_id, vault_address) via eth_defi.erc_4626.vault_token when the vault was constructed with a eth_defi.token.TokenDiskCache and no pinned default_block_identifier. The denomination token is immutable post-deployment, so the cached value is correct regardless of which block the caller would have asked for.

Only a definitive non-null answer is persisted. The None path taken on revert / broken contract is never cached, matching the behaviour of eth_defi.vault.base.VaultBase.denomination_token() which explicitly avoids memoising None so transient failures can be retried.

To disable the cache, pass token_cache=None (or any non- TokenDiskCache dict) when constructing the vault, or construct with a pinned default_block_identifier.

Returns

Denomination token address, or None if the vault contract is broken and did not return a valid address.

Return type

Optional[eth_typing.evm.HexAddress]

fetch_deposit_closed_reason()

Check if deposits are closed using maxDeposit(address(0)).

Uses the ERC-4626 standard maxDeposit function to determine if deposits are available. Returns a human-readable reason with the max deposit amount if deposits are restricted.

Returns

Human-readable string if deposits are closed/restricted, or None if deposits are open (maxDeposit > 0).

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_info()

Use info() property for cached access.

Returns

See LagoonVaultInfo

Return type

eth_defi.erc_4626.vault.ERC4626VaultInfo

fetch_nav(block_identifier=None)

Fetch the most recent onchain NAV value.

  • In the case of Lagoon, this is the last value written in the contract with updateNewTotalAssets() and ` settleDeposit()`

  • TODO: updateNewTotalAssets() there is no way to read pending asset update on chain

Returns

Vault NAV, denominated in denomination_token()

Return type

decimal.Decimal

fetch_portfolio(universe, block_identifier=None, allow_fallback=True)

Read the current token balances of a vault.

  • SHould be supported by all implementations

Parameters
Return type

eth_defi.vault.base.VaultPortfolio

fetch_redemption_closed_reason()

Check if redemptions are closed using maxRedeem(address(0)).

Only works for protocols that implement maxRedeem in a way that returns meaningful values for address(0). Most protocols return 0 because address(0) has no shares, not because redemptions are closed.

Returns

Human-readable string if redemptions are closed, or None if redemptions are open or check is not supported.

Return type

Optional[str]

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_share_price(block_identifier)

Get the current share price.

Returns

The share price in underlying token.

If supply is zero return zero.

Parameters

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

Return type

decimal.Decimal

fetch_share_token()

Read share token details onchain.

Use share_token() for cached access.

Return type

eth_defi.token.TokenDetails

fetch_share_token_address(block_identifier='latest')

Get share token of this vault.

  • Vault itself (ERC-4626)

  • share() accessor (ERC-7575)

Results are disk-cached per (chain_id, vault_address) via eth_defi.erc_4626.vault_token when the vault was constructed with a eth_defi.token.TokenDiskCache. Under normal circumstances the block_identifier argument is effectively ignored on cache hits — ERC-4626 share tokens are immutable post-deployment, so the cached value is correct regardless of which block the caller asked for.

Only a definitive answer from the chain is ever persisted: a successful call, or a revert matching KNOWN_SHARE_TOKEN_ERROR_MESSAGES (which positively classifies the contract as non-ERC-7575). Transient RPC failures (ProbablyNodeHasNoBlock, HTTP 502) fall back to self.vault_address but are not written to the cache, so a flaky node cannot poison a real ERC-7575 vault’s entry.

To disable the cache, pass token_cache=None (or any non- TokenDiskCache dict) when constructing the vault, or construct with a pinned default_block_identifier to force the uncached historical-read path on every call.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, hexbytes.main.HexBytes, int]) – Block to query. Cache is only consulted/written when the caller passes the default "latest" and the vault instance has no pinned default_block_identifier.

Return type

eth_typing.evm.HexAddress

fetch_total_assets(block_identifier)

What is the total NAV of the vault.

Example:

assert vault.denomination_token.symbol == "USDC"
assert vault.share_token.symbol == "ipUSDCfusion"
assert vault.fetch_total_assets(block_identifier=test_block_number) == Decimal("1437072.77357")
assert vault.fetch_total_supply(block_identifier=test_block_number) == Decimal("1390401.22652875")
Parameters

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

Block number to read.

Use web3.eth.block_number for the last block.

Returns

The vault value in underlyinh token

Return type

Optional[decimal.Decimal]

fetch_total_supply(block_identifier)

What is the current outstanding shares.

Example:

Parameters

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

Block number to read.

Use web3.eth.block_number for the last block.

Returns

The vault value in underlyinh token

Return type

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]

fetch_vault_info()

Get all information we can extract from the vault smart contracts.

Return type

eth_defi.erc_4626.vault.ERC4626VaultInfo

property flow_manager: eth_defi.vault.base.VaultFlowManager

Flow manager associated with this vault

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_deposit_manager()

Get deposit manager to deposit/redeem from the vault.

Return type

eth_defi.erc_4626.deposit_redeem.ERC4626DepositManager

get_estimated_lock_up()

Lock-up depends on the underlying vault.

Return type

Optional[datetime.timedelta]

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_fee_mode()

Get how this vault accounts its fees.

Return type

Optional[eth_defi.vault.fee.VaultFeeMode]

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_flow_manager()

Get flow manager to read indiviaul settle events.

Return type

eth_defi.vault.base.VaultFlowManager

get_historical_reader(stateful)

Get share price reader to fetch historical returns.

Parameters

stateful – If True, use a stateful reading strategy.

Returns

None if unsupported

Return type

eth_defi.vault.base.VaultHistoricalReader

Link to Royco homepage.

Individual vault pages are not available on the Royco interface.

Parameters

referral (Optional[str]) –

Return type

str

get_management_fee(block_identifier)

Fees are determined by the underlying wrapped vault.

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_notes()

Get notes for this vault.

Falls back to Royco’s offchain description when manual vault notes are not available.

Return type

Optional[str]

get_performance_fee(block_identifier)

Fees are determined by the underlying wrapped vault.

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_protocol_name()

Return the name of the vault protocol.

Return type

str

get_risk()

Get risk profile of this vault.

Return type

Optional[eth_defi.vault.risk.VaultTechnicalRisk]

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

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

has_custom_fees()

Royco vaults wrap underlying vaults.

Fees are handled by the underlying wrapped vault, not by the wrapper itself.

Return type

bool

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

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

is_valid()

Check if this vault is valid.

  • Call a known smart contract function to verify the function exists

Return type

bool

property name: str

Vault name.

property royco_metadata: Optional[eth_defi.erc_4626.vault_protocol.royco.offchain_metadata.RoycoOffchainVaultMetadata]

Offchain metadata from Royco’s first-party API.

This covers Royco vault/explore rows and classic Royco market/explore Vault Market rows.

property share_token: eth_defi.token.TokenDetails

ERC-20 that presents vault shares.

  • User gets shares on deposit and burns them on redemption

property short_description: Optional[str]

Short display name from Royco offchain metadata.

property symbol: str

Vault share token symbol

property underlying_token: eth_defi.token.TokenDetails

Alias for denomination_token()

property vault_contract: web3.contract.contract.Contract

Get vault deployment.