erc_4626.vault_protocol.lagoon.vault

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

Vault adapter for Lagoon Finance protocol.

Notes on active Lagoon development:

Lagoon v0.5.0 changes to the original release

  • Affect the vault interactions greatlty

  • Vault initialisation parameters changed: fee registry and wrapped native token moved from parameters payload to constructor arguments

  • Beacon proxy replaced with BeaconProxyFactory.createVault() patterns

  • pendingSilo() accessor removed, now needs a direct storage slot read

  • safe() accessor added

How to detect version:

  • Call pendingSilo(): if reverts is a new version

How to get pendingSilo(): see eth_defi.lagoon.vault.LagoonVault.silo_address().

Lagoon error code translation.

Module Attributes

DEFAULT_LAGOON_POST_VALUATION_GAS

How much gas we use for valuation post

DEFAULT_LAGOON_SETTLE_GAS

How much gas we use for valuation post

LAGOON_V06_ACCESS_ABI

Minimal interface for Lagoon v0.6's access-policy view.

Classes

AutomatedSafe

Mixin for Safe multisig wallets with TradingStrategyModuleV0 guard.

LagoonFlowManager

Manage deposit/redemption queue for Lagoon.

LagoonSatelliteVault

A satellite chain deployment: Safe + TradingStrategyModuleV0, no vault contract.

LagoonVault

Python interface for interacting with Lagoon Finance vaults.

LagoonVaultInfo

Capture information about Lagoon vault deployment.

LagoonVersion

Figure out Lagoon version.

DEFAULT_LAGOON_POST_VALUATION_GAS = 500000

How much gas we use for valuation post

DEFAULT_LAGOON_SETTLE_GAS = 500000

How much gas we use for valuation post

LAGOON_V06_ACCESS_ABI = [{'inputs': [{'internalType': 'address', 'name': 'account', 'type': 'address'}], 'name': 'isAllowed', 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool'}], 'stateMutability': 'view', 'type': 'function'}]

Minimal interface for Lagoon v0.6’s access-policy view.

Canonical source: https://github.com/hopperlabsxyz/lagoon-v0/blob/a8e73f5a5276aa4047b901083cbce127d7f7b470/src/v0.6.0/Accessable.sol

class LagoonVaultInfo

Bases: eth_defi.vault.base.VaultInfo

Capture information about Lagoon vault deployment.

asset: eth_typing.evm.HexAddress

The ERC-20 token that nominates the vault assets

safe: eth_typing.evm.HexAddress

Lagoon vault deployment info

whitelistManager: eth_typing.evm.HexAddress

Lagoon vault deployment info

feeReceiver: eth_typing.evm.HexAddress

Lagoon vault deployment info

feeRegistry: eth_typing.evm.HexAddress

Lagoon vault deployment info

valuationManager: eth_typing.evm.HexAddress

Lagoon vault deployment info

address: eth_typing.evm.ChecksumAddress

Safe multisig core info

fallback_handler: eth_typing.evm.ChecksumAddress

Safe multisig core info

guard: eth_typing.evm.ChecksumAddress

Safe multisig core info

master_copy: eth_typing.evm.ChecksumAddress

Safe multisig core info

modules: list[eth_typing.evm.ChecksumAddress]

Safe multisig core info

nonce: int

Safe multisig core info

owners: list[eth_typing.evm.ChecksumAddress]

Safe multisig core info

threshold: int

Safe multisig core info

version: str

Safe multisig core info

__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 LagoonVersion

Bases: enum.Enum

Figure out Lagoon version.

class AutomatedSafe

Bases: object

Mixin for Safe multisig wallets with TradingStrategyModuleV0 guard.

Provides transaction wrapping through the guard module, used by both full Lagoon vaults (LagoonVault) and satellite Safe-only deployments (LagoonSatelliteVault).

  • Encapsulates Safe + TradingStrategyModuleV0 interaction

  • Independent of vault contracts (no ERC-4626 dependency)

Parameters
  • web3 – Web3 connection to the chain where the Safe is deployed.

  • safe_address – Address of the Gnosis Safe multisig. Can be None for LagoonVault where it is lazily resolved from the vault contract.

  • trading_strategy_module_address – Address of the TradingStrategyModuleV0 guard module enabled on the Safe.

__init__(web3, safe_address=None, trading_strategy_module_address=None)
Parameters
  • web3 (web3.main.Web3) – Web3 connection to the chain where the Safe is deployed.

  • safe_address (Optional[eth_typing.evm.HexAddress]) – Address of the Gnosis Safe multisig. Can be None for LagoonVault where it is lazily resolved from the vault contract.

  • trading_strategy_module_address (Optional[eth_typing.evm.HexAddress]) – Address of the TradingStrategyModuleV0 guard module enabled on the Safe.

property safe_address: eth_typing.evm.HexAddress

Get Safe multisig contract address.

property trading_strategy_module_address: Optional[eth_typing.evm.HexAddress]

Get TradingStrategyModuleV0 contract address.

fetch_safe(address)

Create a Safe object from an address.

Use safe property for cached access.

Parameters

address (Union[eth_typing.evm.HexAddress, str]) –

Return type

safe_eth.safe.safe.Safe

property safe: safe_eth.safe.safe.Safe

Get the underlying Safe object used as an API from safe-eth-py library.

  • Wraps Safe contract using Gnosis’s in-house library

property safe_contract: web3.contract.contract.Contract

Safe multisig as a contract.

  • Interact with Safe multisig ABI

property trading_strategy_module: web3.contract.contract.Contract

Get the TradingStrategyModuleV0 contract instance.

fetch_trading_strategy_module_version()

Perform deployed smart contract probing.

Returns

v0.1.0 or v0.1.1.

None if not TS module associated.

Return type

Optional[str]

property trading_strategy_module_version: str

Get TradingStrategyModuleV0 contract ABI version.

  • Subject to change, development in progress

transact_via_exec_module(func_call, value=0, operation=0)

Create a multisig transaction using a module.

  • Calls execTransactionFromModule on Gnosis Safe contract

  • Executes a transaction as a multisig

  • Mostly used for testing w/whitelist ignore

Warning

A special gas fix is needed, because eth_estimateGas seems to fail for these Gnosis Safe transactions.

Parameters
  • func_call (web3.contract.contract.ContractFunction) – Bound smart contract function call

  • value (int) – ETH attached to the transaction

  • operation –

    Gnosis enum.

    Call = 0, DelegateCall = 1.

Return type

web3.contract.contract.ContractFunction

transact_via_trading_strategy_module(func_call, value=0, abi_version=None)

Create a Safe multisig transaction using TradingStrategyModuleV0.

Parameters
  • func_call (web3.contract.contract.ContractFunction) – Bound smart contract function call

  • value (int) – ETH value attached to the call.

  • abi_version (str) – Use specific TradingStrategyModuleV0 ABI version.

Returns

Bound Solidity function call you need to turn to a transaction

Return type

web3.contract.contract.ContractFunction

class LagoonSatelliteVault

Bases: eth_defi.erc_4626.vault_protocol.lagoon.vault.AutomatedSafe

A satellite chain deployment: Safe + TradingStrategyModuleV0, no vault contract.

Used on chains that only receive bridged assets and execute trades, without deposit/redemption infrastructure (no ERC-4626 vault).

Parameters
  • web3 – Web3 connection to the chain where the Safe is deployed.

  • safe_address – Address of the Gnosis Safe multisig. Can be None for LagoonVault where it is lazily resolved from the vault contract.

  • trading_strategy_module_address – Address of the TradingStrategyModuleV0 guard module enabled on the Safe.

__init__(web3, safe_address, trading_strategy_module_address)
Parameters
  • web3 (web3.main.Web3) – Web3 connection to the chain where the Safe is deployed.

  • safe_address (eth_typing.evm.HexAddress) – Address of the Gnosis Safe multisig. Can be None for LagoonVault where it is lazily resolved from the vault contract.

  • trading_strategy_module_address (eth_typing.evm.HexAddress) – Address of the TradingStrategyModuleV0 guard module enabled on the Safe.

property web3: web3.main.Web3

Get Web3 connection for this satellite chain.

fetch_safe(address)

Create a Safe object from an address.

Use safe property for cached access.

Parameters

address (Union[eth_typing.evm.HexAddress, str]) –

Return type

safe_eth.safe.safe.Safe

fetch_trading_strategy_module_version()

Perform deployed smart contract probing.

Returns

v0.1.0 or v0.1.1.

None if not TS module associated.

Return type

Optional[str]

property safe: safe_eth.safe.safe.Safe

Get the underlying Safe object used as an API from safe-eth-py library.

  • Wraps Safe contract using Gnosis’s in-house library

property safe_address: eth_typing.evm.HexAddress

Get Safe multisig contract address.

property safe_contract: web3.contract.contract.Contract

Safe multisig as a contract.

  • Interact with Safe multisig ABI

property trading_strategy_module: web3.contract.contract.Contract

Get the TradingStrategyModuleV0 contract instance.

property trading_strategy_module_address: Optional[eth_typing.evm.HexAddress]

Get TradingStrategyModuleV0 contract address.

property trading_strategy_module_version: str

Get TradingStrategyModuleV0 contract ABI version.

  • Subject to change, development in progress

transact_via_exec_module(func_call, value=0, operation=0)

Create a multisig transaction using a module.

  • Calls execTransactionFromModule on Gnosis Safe contract

  • Executes a transaction as a multisig

  • Mostly used for testing w/whitelist ignore

Warning

A special gas fix is needed, because eth_estimateGas seems to fail for these Gnosis Safe transactions.

Parameters
  • func_call (web3.contract.contract.ContractFunction) – Bound smart contract function call

  • value (int) – ETH attached to the transaction

  • operation –

    Gnosis enum.

    Call = 0, DelegateCall = 1.

Return type

web3.contract.contract.ContractFunction

transact_via_trading_strategy_module(func_call, value=0, abi_version=None)

Create a Safe multisig transaction using TradingStrategyModuleV0.

Parameters
  • func_call (web3.contract.contract.ContractFunction) – Bound smart contract function call

  • value (int) – ETH value attached to the call.

  • abi_version (str) – Use specific TradingStrategyModuleV0 ABI version.

Returns

Bound Solidity function call you need to turn to a transaction

Return type

web3.contract.contract.ContractFunction

class LagoonVault

Bases: eth_defi.erc_7540.vault.ERC7540Vault, eth_defi.erc_4626.vault_protocol.lagoon.vault.AutomatedSafe

Python interface for interacting with Lagoon Finance vaults.

For information see VaultBase base class documentation.

Example vault: https://basescan.org/address/0x6a5ea384e394083149ce39db29d5787a658aa98a#readContract

Notes

  • Vault contract knows about Safe, Safe does not know about the Vault

  • Ok so for settlement you dont have to worry about this metric, the only thing you have to value is the assets inside the safe (what you currently have under management) and update the NAV of the vault by calling updateNewTotalAssets (ex: if you have 1M inside the vault and 500K pending deposit you only need to call updateTotalAssets with the 1M that are currently inside the safe). Then, to settle you just call settleDeposit and the vault calculate everything for you.

  • To monitor the pending deposits it’s a bit more complicated. You have to check the balanceOf the pendingSilo contract (0xAD1241Ba37ab07fFc5d38e006747F8b92BB217D5) in term of underlying (here USDC) for pending deposit and in term of shares (so the vault itself) for pending withdraw requests

Lagoon tokens can be in

  • Safe: Tradeable assets

  • Silo: pending deposits (USDC)

  • Vault: pending redemptions (USDC)

  • User wallets: after deposit() have been called share tokens are moved to the user wallet

Parameters
  • spec – Address must be Lagoon vault address (not Safe address)

  • trading_strategy_module_address –

    TradingStrategyModuleV0 enabled on Safe for automated trading.

    If not given, not known.

  • vault_abi –

    ABI filename we use.

    Lagoon has different versions.

    None = autodetect.

  • default_block_identifier –

    Override block identifier for on-chain metadata reads.

    See ERC4626Vault for details.

__init__(web3, spec, trading_strategy_module_address=None, token_cache=None, vault_abi=None, features=None, default_block_identifier=None, **kwargs)
Parameters
  • spec (eth_defi.vault.base.VaultSpec) – Address must be Lagoon vault address (not Safe address)

  • trading_strategy_module_address (Optional[eth_typing.evm.HexAddress]) –

    TradingStrategyModuleV0 enabled on Safe for automated trading.

    If not given, not known.

  • vault_abi (Optional[str]) –

    ABI filename we use.

    Lagoon has different versions.

    None = autodetect.

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

    Override block identifier for on-chain metadata reads.

    See ERC4626Vault for details.

  • web3 (web3.main.Web3) –

  • token_cache (Optional[dict]) –

  • features (set[eth_defi.erc_4626.core.ERC4626Feature]) –

fetch_version()

Figure out Lagoon version.

  • Poke the smart contract with probe functions to get version

  • Specifically call pendingSilo() that has been removed because the contract is too big

  • Our ABI definitions and callign conventions change between Lagoon versions

Return type

eth_defi.erc_4626.vault_protocol.lagoon.vault.LagoonVersion

check_version_compatibility()

Throw if there is mismatch between ABI and contract exposed EVM calls

property version: eth_defi.erc_4626.vault_protocol.lagoon.vault.LagoonVersion

Get Lagoon version.

  • Cached property to avoid multiple calls

property lagoon_metadata: Optional[eth_defi.erc_4626.vault_protocol.lagoon.offchain_metadata.LagoonVaultMetadata]

Offchain metadata from Lagoon’s web app API.

  • Fetched from app.lagoon.finance/api/vault endpoint

  • Cached on first access

  • Returns None if vault is not in Lagoon’s app database

property description: Optional[str]

Full vault strategy description from Lagoon’s offchain metadata.

property short_description: Optional[str]

Short one-liner vault summary from Lagoon’s offchain metadata.

property manager_name: Optional[str]

Lagoon curator names from Lagoon’s offchain vault API.

get_flags()

Get vault flags, auto-flagging vaults missing from Lagoon’s frontend.

  • If the vault has no metadata in Lagoon’s API, it is flagged as unofficial

  • Manual flags from VAULT_FLAGS_AND_NOTES take precedence

Return type

set[eth_defi.vault.flag.VaultFlag]

get_notes()

Get notes for this vault.

  • Returns manual notes from the vault flags if set

  • If vault is missing from Lagoon’s frontend, returns the missing note

  • Otherwise falls back to the full description from Lagoon’s offchain metadata

Return type

Optional[str]

property vault_contract: web3.contract.contract.Contract

Get vault deployment.

property whitelist_contract: web3.contract.contract.Contract

Get the stable whitelist interface at the vault address.

Lagoon’s version-specific vault ABIs do not consistently include the inherited whitelist views. The shared interface contains both selectors and can be safely bound to every Lagoon vault deployment. Unsupported selectors are translated to NotImplementedError by the public accessors below.

property access_contract: web3.contract.contract.Contract

Get Lagoon v0.6’s isAllowed(address) access interface.

Lagoon v0.6 replaced Whitelistable with the canonical Accessable contract. This is versioned source on the upstream main branch; the pinned revision did not have a v0.6.0 GitHub release or tag. The one-function interface is bound separately because the repository intentionally continues to use the compatible v0.5 vault ABI for general v0.6 reads.

Returns

Contract proxy exposing isAllowed(address).

is_whitelisted_deposit()

Determine whether a Lagoon vault uses whitelist-mode deposits.

Lagoon released isWhitelistActivated() in v0.3.0 and retained it in the canonical v0.4.0 Whitelistable source. The getter was removed from the v0.5.0 Whitelistable source, despite isWhitelisted(address) remaining available. For v0.5 deployments only, use the zero-address sentinel: its False result means whitelist enforcement is active, while True means deposits are permissionless. This follows the v0.5 implementation’s isWhitelisted branch for a disabled whitelist.

Lagoon v0.6 replaces Whitelistable with an access layer supporting whitelist mode, blacklist mode and an external sanctions oracle. Its canonical AccessableLib.isAllowed implementation returns False for the zero address in whitelist mode and True under the default-open blacklist mode. Therefore v0.6 uses isAllowed(0x0) as its version-specific sentinel. Individual account admission must still be checked separately because blacklist and sanctions rules may deny an otherwise default-open account.

Returns

True when the vault uses whitelist mode.

Raises

NotImplementedError – If the deployed Lagoon version exposes neither the policy getter nor its version-specific account-access fallback.

Return type

bool

is_account_whitelisted(address)

Determine whether an account passes Lagoon’s versioned access view.

In the versioned v0.5 implementation, the canonical isWhitelisted source returns True for every account when the whitelist is disabled and returns mapping membership when it is active. Thus this probe is a reliable whitelist-admission result even where the v0.5 deployment lacks isWhitelistActivated(). It does not establish allowance, capacity, pause state, or an open ERC-7540 request window.

Lagoon v0.6 instead calls isAllowed(address). The canonical versioned AccessableLib implementation combines whitelist or blacklist mode with an optional external sanctions oracle. Thus this method’s historical name means “admitted by Lagoon’s access policy” for v0.6. The pinned upstream revision did not have a v0.6.0 GitHub release or tag.

Parameters

address (eth_typing.evm.HexAddress) – Account whose access status is queried.

Returns

True when Lagoon’s versioned access policy accepts the account.

Raises

NotImplementedError – If the deployed Lagoon version does not expose its expected access getter.

Return type

bool

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_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

get_flow_manager()

Get flow manager to read indiviaul settle events.

Return type

eth_defi.erc_4626.vault_protocol.lagoon.vault.LagoonFlowManager

fetch_vault_info()

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

Return type

dict

fetch_info()

Use info() property for cached access.

Returns

See LagoonVaultInfo

Return type

eth_defi.erc_4626.vault_protocol.lagoon.vault.LagoonVaultInfo

property safe_address: eth_typing.evm.HexAddress

Get Safe multisig contract address

property safe: safe_eth.safe.safe.Safe

Get the underlying Safe object used as an API from safe-eth-py library.

  • Warps Safe Contract using Gnosis’s in-house library

property safe_contract: web3.contract.contract.Contract

Safe multisig as a contract.

  • Interact with Safe multisig ABI

property valuation_manager: eth_typing.evm.HexAddress

Valuation manager role on the vault.

property silo_address: eth_typing.evm.HexAddress

Pending Silo contract address.

Returns

Checksummed Silo contract addrewss “pendingSilo”.

property silo_contract: web3.contract.contract.Contract

Pending Silo contract.

  • This contract does not have any functionality, but stores deposits (pending USDC) and redemptions (pending share token)

post_new_valuation(total_valuation)

Update the valuations of this vault.

  • Lagoon vault does not currently track individual positions, but takes a “total value” number

  • Updating this number also allows deposits and redemptions to proceed

Notes:

How can I post a valuation commitee update 1. as the valuationManager, call the function updateNewTotalAssets(_newTotalAssets) _newTotalAssets being expressed in underlying in its smallest unit for usdc, it would with its 6 decimals. Do not take into account requestDeposit and requestRedeem in your valuation

  1. as the safe, call the function settleDeposit()

Parameters

total_valuation (decimal.Decimal) – The vault value nominated in denomination_token().

Returns

Bound contract function that can be turned to a transaction

Return type

web3.contract.contract.ContractFunction

settle_via_trading_strategy_module(valuation=None, abi_version=None)

Settle the new valuation and deposits.

  • settleDeposit will also settle the redeems request if possible. If there are enough assets in the safe it will settleRedeem It there are not enough assets, it will only settleDeposit.

  • if there is nothing to settle: no deposit and redeem requests you can still call settleDeposit/settleRedeem to validate the new nav

  • If there is not enough USDC to redeem, the transaction will revert

Parameters
  • abi_version (None) – Use specific ABI version.

  • raw_amount – Needed in Lagoon v0.5+

  • valuation (decimal.Decimal) –

Return type

web3.contract.contract.ContractFunction

post_valuation_and_settle(valuation, asset_manager, gas=1000000)

Do both new valuation and settle.

  • Quickhand method for asset_manager code

  • Only after this we can read back

  • Broadcasts two transactions and waits for the confirmation

  • If there is not enough USDC to redeem, the second transaction will fail with revert

Returns

The transaction hash of the settlement transaction

Parameters
Return type

hexbytes.main.HexBytes

get_management_fee(block_identifier)

Get Lagoon vault rates

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 Lagoon vault rates

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

is_trading_strategy_module_enabled()

Check if TradingStrategyModuleV0 is enabled on the Safe multisig.

Return type

bool

get_deposit_manager()

Create Lagoon’s ERC-7540 deposit manager.

Lagoon uses the generic ERC-7540 lifecycle with protocol-specific access-policy checks and an Anvil settlement driver.

Returns

Lagoon-specific extension of the generic ERC-7540 manager.

Return type

LagoonDepositManager

get_deposit_manager_capability()

Declare Lagoon’s asynchronously settleable manager lifecycle.

Lagoon accepts the standard ERC-7540 request types and its selected manager can force-settle both ticket directions on Anvil.

Note

Trade-executor may call force_settle() for a full-lifecycle simulation only when this capability flag is true and it holds the matching ERC-7540 request ticket. Request-only behaviour remains unchanged.

Returns

Two-way asynchronous capability with Anvil settlement support.

Return type

eth_defi.vault.deposit_redeem.VaultDepositManagerCapability

can_check_deposit()

Lagoon’s maxDeposit does not work correctly for deposit availability checks.

Return type

bool

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

property address: eth_typing.evm.HexAddress

Get the vault smart contract address.

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 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_minimum_deposit(block_identifier='latest')

Fetch a source-proven minimum deposit in decimal token units.

A None result means this adapter does not expose a known minimum; it does not prove the protocol accepts arbitrarily small deposits. A zero result means the adapter positively established that the vault has no minimum deposit.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) – Block at which to read the protocol configuration.

Returns

Decimal denomination-token minimum, or None when unknown.

Return type

Optional[decimal.Decimal]

fetch_minimum_redemption(block_identifier='latest')

Fetch a source-proven redemption minimum in decimal share units.

A None result means this adapter does not expose a known minimum; it does not prove the protocol accepts arbitrarily small redemptions. A zero result means the adapter positively established that the vault has no minimum redemption.

Parameters

block_identifier (Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]) – Block at which to read the protocol configuration.

Returns

Decimal vault-share minimum, or None when unknown.

Return type

Optional[decimal.Decimal]

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_safe(address)

Create a Safe object from an address.

Use safe property for cached access.

Parameters

address (Union[eth_typing.evm.HexAddress, str]) –

Return type

safe_eth.safe.safe.Safe

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]

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

Perform deployed smart contract probing.

Returns

v0.1.0 or v0.1.1.

None if not TS module associated.

Return type

Optional[str]

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]

finalise_deposit(depositor, raw_amount=None)

Build the transaction that claims settled deposit shares.

This is phase two of an asynchronous deposit. The three-argument ERC-7540 deposit(assets, receiver, controller) call uses depositor as both receiver and controller.

Parameters
  • depositor (eth_typing.evm.HexAddress) – Request controller and share receiver.

  • raw_amount (Optional[int]) – Settled underlying assets to claim. When omitted, use maxDeposit(depositor).

Returns

Bound ERC-7540 deposit-claim function.

Return type

web3.contract.contract.ContractFunction

finalise_redeem(depositor, raw_amount=None)

Build the transaction that claims settled redemption assets.

This is phase two of an asynchronous redemption. The three-argument ERC-7540 redeem(shares, receiver, controller) call uses depositor as both receiver and controller.

Parameters
  • depositor (eth_typing.evm.HexAddress) – Request controller and underlying-token receiver.

  • raw_amount (Optional[int]) – Settled shares to claim in raw units. When omitted, use maxRedeem(depositor).

Returns

Bound ERC-7540 redemption-claim function.

Return type

web3.contract.contract.ContractFunction

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

Return an unknown operator-controlled ERC-7540 lock-up.

ERC-7540 standardises request state, but not the operator’s settlement schedule. A generic adapter therefore cannot provide a duration.

Returns

None because no generic lock-up estimate exists.

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_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

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

Return the standard ERC-4626 share-price source.

ERC-4626 prices are calculated from vault accounting values read at a specific block, including protocol-specific overrides that expose the same state through another contract view.

Returns

Smart-contract state source.

Return type

eth_defi.vault.price_source.PriceSource

get_synchronous_deposit_manager_capability()

Build static metadata for a verified synchronous manager.

A caller must already have established the reader class’ guarded fork evidence. This deliberately performs no RPC reads: the capability is static library metadata, not a live vault availability check.

Returns

Synchronous two-way capability.

Return type

eth_defi.vault.deposit_redeem.VaultDepositManagerCapability

get_whitelist_notes()

Return an export caveat for the vault-wide whitelist status.

Adapters may attach a concise, stable explanation when a classification is an explicitly requested operating assumption or excludes an integration-specific permission mechanism. The note describes the policy classification only; it must not be used to report temporary deposit availability.

Returns

Export note, or None when the classification needs no caveat.

Return type

Optional[str]

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_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

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.

request_deposit(depositor, raw_amount, check_allowance=True, check_balance=True)

Build a deposit transaction.

This is phase one of the asynchronous ERC-7540 flow. The depositor must hold enough underlying tokens and approve the vault unless the corresponding checks are disabled.

Note

Legacy. Use get_deposit_manager() instead.

Parameters
  • depositor (eth_typing.evm.HexAddress) – Token owner and request controller.

  • raw_amount (int) – Underlying-token amount in raw units.

  • check_allowance – Check that the vault can transfer raw_amount from the depositor.

  • check_balance – Check that the depositor owns at least raw_amount.

Returns

Bound requestDeposit contract function.

Return type

web3.contract.contract.ContractFunction

request_redeem(depositor, raw_amount, check_enough_token=True)

Build a redemption-request transaction.

This is phase one of the asynchronous ERC-7540 redemption flow. The depositor acts as both owner and controller.

Parameters
  • depositor (eth_typing.evm.HexAddress) – Share owner and request controller.

  • raw_amount (int) – Vault shares to redeem in raw units.

  • check_enough_token (bool) – Whether to verify the depositor’s current share balance. Disable only when reconstructing an already-broadcast request.

Returns

Bound requestRedeem contract function.

Return type

web3.contract.contract.ContractFunction

property share_token: eth_defi.token.TokenDetails

ERC-20 that presents vault shares.

  • User gets shares on deposit and burns them on redemption

supports_generic_deposit_manager()

Check whether the live vault exposes the standard ERC-4626 surface.

This is deliberately an interface check, not a public support claim. Callers must still execute a guarded fork probe before relying on the generic manager for a protocol-specific adapter.

Returns

True when asset succeeds with a non-zero asset address. Deposit and redemption availability is established only by a guarded fork transaction, not by ERC-4626 max* advisory values.

Return type

bool

property symbol: str

Vault share token symbol

property trading_strategy_module: web3.contract.contract.Contract

Get the TradingStrategyModuleV0 contract instance.

property trading_strategy_module_address: Optional[eth_typing.evm.HexAddress]

Get TradingStrategyModuleV0 contract address.

property trading_strategy_module_version: str

Get TradingStrategyModuleV0 contract ABI version.

  • Subject to change, development in progress

transact_via_exec_module(func_call, value=0, operation=0)

Create a multisig transaction using a module.

  • Calls execTransactionFromModule on Gnosis Safe contract

  • Executes a transaction as a multisig

  • Mostly used for testing w/whitelist ignore

Warning

A special gas fix is needed, because eth_estimateGas seems to fail for these Gnosis Safe transactions.

Parameters
  • func_call (web3.contract.contract.ContractFunction) – Bound smart contract function call

  • value (int) – ETH attached to the transaction

  • operation –

    Gnosis enum.

    Call = 0, DelegateCall = 1.

Return type

web3.contract.contract.ContractFunction

transact_via_trading_strategy_module(func_call, value=0, abi_version=None)

Create a Safe multisig transaction using TradingStrategyModuleV0.

Parameters
  • func_call (web3.contract.contract.ContractFunction) – Bound smart contract function call

  • value (int) – ETH value attached to the call.

  • abi_version (str) – Use specific TradingStrategyModuleV0 ABI version.

Returns

Bound Solidity function call you need to turn to a transaction

Return type

web3.contract.contract.ContractFunction

property underlying_token: eth_defi.token.TokenDetails

Alias for denomination_token()

first_seen_at_block: int | None

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.

class LagoonFlowManager

Bases: eth_defi.vault.base.VaultFlowManager

Manage deposit/redemption queue for Lagoon.

  • Lagoon uses ERC-7540 Asynchronous ERC-4626 Tokenized Vaults for deposits and redemptions flow

On the Lagoon flow:

Ok so for settlement you dont have to worry about this metric, the only thing you have to value is the assets inside the safe (what you currently have under management) and update the NAV of the vault by calling updateNewTotalAssets (ex: if you have 1M inside the vault and 500K pending deposit you only need to call updateTotalAssets with the 1M that are currently inside the safe). Then, to settle you just call settleDeposit and the vault calculate everything for you.

To monitor the pending deposits it’s a bit more complicated. You have to check the balanceOf the pendingSilo contract (0xAD1241Ba37ab07fFc5d38e006747F8b92BB217D5) in term of underlying (here USDC) for pending deposit and in term of shares (so the vault itself) for pending withdraw requests

__init__(vault)
Parameters

vault (eth_defi.erc_4626.vault_protocol.lagoon.vault.LagoonVault) –

Return type

None

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

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

fetch_pending_deposit_events(range)

Read incoming pending deposits.

Parameters

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

Return type

None

fetch_pending_redemption_event(range)

Read outgoing pending withdraws.

Parameters

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

Return type

None

fetch_processed_deposit_event(range)

Read incoming pending deposits.

Parameters

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

Return type

None

fetch_processed_redemption_event(vault, range)

Read outgoing pending withdraws.

Parameters
Return type

None

calculate_underlying_needed_for_redemptions(block_identifier)

How much underlying token (USDC) we are going to need on the next redemption cycle.

Computed as pendingRedemptionShares * sharePrice.

Warning

This returns a human-readable decimal.Decimal denomination amount, not a raw integer token amount. Callers must convert with denomination_token.convert_to_raw() before comparing against raw balances (e.g. the Anvil settlement top-up in LagoonDepositManager._provision_safe_for_settlement() depends on this). Do not “fix” this to return raw units without updating those callers.

Returns

Human-readable decimal amount of the denomination token needed.

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

decimal.Decimal

get_estimated_lock_up()

Estimate lock up period from Lagoon’s offchain metadata.

  • Uses average_settlement from Lagoon’s web app API (in seconds)

  • Returns None if metadata is not available

Return type

Optional[datetime.timedelta]