Lagoon¶
| Field | Value |
|---|---|
| Module | almanak.connectors.lagoon |
| Protocol kind | Vault |
| Aliases | N/A |
Supported Chains And Intents¶
| Chain | Family | Supported Intents |
|---|---|---|
| Base | EVM | VAULT_DEPOSIT, VAULT_REDEEM |
| Ethereum | EVM | VAULT_DEPOSIT, VAULT_REDEEM |
API Reference¶
almanak.connectors.lagoon
¶
Lagoon Vault Connector.
This module provides a low-level SDK and adapter for interacting with Lagoon vault contracts (ERC-7540) through the gateway's RPC service.
Supported operations: - Read vault state (total assets, pending deposits/redemptions, share price) - Read storage slots (proposed total assets, silo address) - Verify vault contract version - Build ActionBundles for vault write operations (propose, settle) - Deploy new Lagoon vaults via factory contracts
The SDK / adapter / deployer / receipt parser are consumed by the ax
vault commands (almanak/framework/agent_tools/executor.py) and the
vault lifecycle code (almanak/framework/vault/lifecycle.py).
Strategy-layer VaultDepositIntent / VaultRedeemIntent routing is
currently blocked at Pydantic vocabulary validation (only metamorpho is
registered via register_vault_adapter). The connector ships the
operator-side surface today; user-side requestDeposit / requestRedeem
ActionBundle building is tracked in VIB-4307. The intent-coverage gate is
satisfied by the blocker-invariant tests in
tests/intents/{ethereum,base}/test_lagoon_vault.py — those flip to a
real 4-layer on-chain test the moment the vault adapter lands in
register_vault_adapter.
Example
from almanak.connectors.lagoon import LagoonVaultSDK, LagoonVaultAdapter
sdk = LagoonVaultSDK(gateway_client, chain="ethereum") adapter = LagoonVaultAdapter(sdk)
from almanak.connectors.lagoon import LagoonVaultDeployer, VaultDeployParams
deployer = LagoonVaultDeployer()
LagoonVaultAdapter
¶
Adapter that converts vault params into ActionBundles.
The adapter builds ActionBundles from vault operation params using the LagoonVaultSDK to construct unsigned transactions. It does NOT execute transactions -- the VaultLifecycleManager passes bundles to the ExecutionOrchestrator for execution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sdk
|
LagoonVaultSDK
|
A LagoonVaultSDK instance for building transactions. |
required |
build_propose_valuation_bundle
¶
Build an ActionBundle for proposing a new vault valuation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
UpdateTotalAssetsParams
|
Parameters containing vault address, valuator address, and the proposed total assets value. |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle with a single propose transaction. |
build_settle_deposit_bundle
¶
Build an ActionBundle for settling pending deposits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
SettleDepositParams
|
Parameters containing vault address, safe address, and the total assets value for settlement. |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle with a single settle deposit transaction. |
build_settle_redeem_bundle
¶
Build an ActionBundle for settling pending redemptions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
SettleRedeemParams
|
Parameters containing vault address, safe address, and the total assets value for settlement. |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle with a single settle redeem transaction. |
build_initiate_closing_bundle
¶
Build an ActionBundle for initiateClosing() (Open->Closing).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
InitiateClosingParams
|
Parameters containing vault address and owner address. |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle with a single initiateClosing transaction. |
build_close_bundle
¶
Build an ActionBundle for close(uint256) (Closing->Closed).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
CloseVaultParams
|
Parameters containing vault address, safe address, and the
exact |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle with a single close transaction. |
build_redeem_bundle
¶
Build an ActionBundle for ERC-4626 redeem (post-close sweep).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
RedeemVaultParams
|
Parameters containing vault address, controller address, and the share amount to redeem. |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle with a single redeem transaction. |
LagoonVaultDeployer
¶
Deploys new Lagoon vaults via factory contracts.
Uses the Lagoon OptinProxyFactory with proper ABI-encoded calldata. The factory function signature is: createVaultProxy(address logic, address owner, uint256 delay, InitStruct init, bytes32 salt)
Where InitStruct is
(address underlying, string name, string symbol, address admin, address safe, address feeReceiver, address valuationManager, address whitelistManager, uint16 managementRate, uint16 performanceRate, bool enableWhitelist, uint256 rateUpdateCooldown)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gateway_client
|
Gateway client for RPC calls (needed to read vault logic from registry). |
None
|
get_factory_address
staticmethod
¶
Look up the factory address for a chain.
Returns:
| Type | Description |
|---|---|
str
|
Factory contract address. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If chain has no known factory. |
build_deploy_vault_tx
¶
Build an unsigned transaction to deploy a new vault proxy.
Uses eth_abi for proper ABI encoding of the createVaultProxy call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
VaultDeployParams
|
Vault deployment parameters. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If chain is unsupported or parameters are invalid. |
build_deploy_vault_bundle
¶
Build an ActionBundle for vault deployment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
VaultDeployParams
|
Vault deployment parameters. |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle wrapping the deploy transaction. |
parse_deploy_receipt
staticmethod
¶
Parse a deployment transaction receipt to extract the vault address.
Looks for ProxyDeployed event in logs. The vault address is in the event data (first 32 bytes), not in topics.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
receipt
|
Any
|
Transaction receipt. Either a raw dict (with |
required |
Returns:
| Type | Description |
|---|---|
VaultDeployResult
|
VaultDeployResult with extracted vault address. |
build_approve_underlying_tx
staticmethod
¶
build_approve_underlying_tx(
underlying_token_address: str,
vault_address: str,
safe_address: str,
*,
approval_amount: int | None = None,
) -> dict[str, Any]
Build an ERC20 approve transaction for the Safe to allow vault redemptions.
Post-deployment: the Safe calls underlying.approve(vault, amount) so the vault
can pull tokens during redemption settlement.
Security rationale for MAX_UINT256 default: This is the standard ERC-4626 vault
approval pattern. The vault contract is the trust boundary -- if it is
compromised, the approval amount is moot because the vault already has
custody of deposited funds. A scoped approval would require re-approving
before every settlement cycle, adding gas cost and operational complexity
with no meaningful security improvement. Callers who want a tighter
bound can pass approval_amount to cap the approval.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
underlying_token_address
|
str
|
The ERC20 token the vault manages. |
required |
vault_address
|
str
|
The newly deployed vault address (spender). |
required |
safe_address
|
str
|
The Safe wallet address (token holder / tx sender). |
required |
approval_amount
|
int | None
|
Optional cap on the approval amount. Defaults to MAX_UINT256 (standard ERC-4626 pattern). |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Unsigned transaction dict. |
build_post_deploy_bundle
staticmethod
¶
build_post_deploy_bundle(
underlying_token_address: str,
vault_address: str,
safe_address: str,
) -> ActionBundle
Build an ActionBundle for post-deployment approval.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
underlying_token_address
|
str
|
The ERC20 token the vault manages. |
required |
vault_address
|
str
|
The newly deployed vault address. |
required |
safe_address
|
str
|
The Safe wallet address. |
required |
Returns:
| Type | Description |
|---|---|
ActionBundle
|
ActionBundle wrapping the approve transaction. |
get_default_logic
¶
Read the default vault logic address from the factory's registry.
Calls registry() on the factory, then defaultLogic() on the registry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
chain
|
str
|
Chain identifier. |
required |
factory_address
|
str | None
|
Override factory address (uses chain default if None). |
None
|
Returns:
| Type | Description |
|---|---|
str
|
Default vault implementation address. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If gateway client is not configured or RPC call fails. |
VaultDeployParams
dataclass
¶
VaultDeployParams(
chain: str,
underlying_token_address: str,
name: str,
symbol: str,
safe_address: str,
admin_address: str,
fee_receiver_address: str,
deployer_address: str,
logic_address: str | None = None,
valuation_manager_address: str | None = None,
whitelist_manager_address: str | None = None,
management_rate_bps: int = 200,
performance_rate_bps: int = 2000,
enable_whitelist: bool = False,
rate_update_cooldown: int = 86400,
deploy_delay: int = 86400,
salt: bytes | None = None,
)
Parameters for deploying a new Lagoon vault.
VaultDeployResult
dataclass
¶
VaultDeployResult(
success: bool,
vault_address: str | None = None,
transaction_hash: str | None = None,
error: str | None = None,
)
Result of parsing a vault deployment receipt.
LagoonReceiptParser
¶
Parser for Lagoon vault transaction receipts.
Handles three vault settlement event types: - SettleDeposit: deposit settlement with epoch, assets, and shares data - SettleRedeem: redemption settlement with epoch, assets, and shares data - NewTotalAssets: valuation update with new total assets value
parse_receipt
¶
Parse a transaction receipt for Lagoon vault events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
receipt
|
dict[str, Any]
|
Transaction receipt dict with 'logs', 'transactionHash', etc. |
required |
Returns:
| Type | Description |
|---|---|
LagoonParseResult
|
LagoonParseResult with extracted events |
parse_event
¶
parse_event(
log: dict[str, Any],
) -> (
SettleDepositEventData
| SettleRedeemEventData
| NewTotalAssetsEventData
| None
)
Parse a single log entry for Lagoon vault events.
LagoonVaultSDK
¶
Low-level SDK for reading Lagoon vault state via gateway RPC calls.
All RPC calls are routed through the gateway client's RPC service. This SDK handles ABI encoding/decoding and provides typed return values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gateway_client
|
Connected gateway client with RPC service |
required | |
chain
|
str
|
Chain identifier (e.g., "ethereum", "base") |
required |
get_total_assets
¶
Read the vault's total assets (totalAssets()).
Returns:
| Type | Description |
|---|---|
int
|
Total assets in underlying token units (raw integer). |
get_pending_deposits
¶
Read pending deposit requests for the vault.
Uses ERC-7540 pendingDepositRequest(uint256,address) with requestId=0 and the vault address as the controller.
Returns:
| Type | Description |
|---|---|
int
|
Pending deposits in underlying token units (raw integer). |
get_pending_redemptions
¶
Read pending redemption requests for the vault.
Uses ERC-7540 pendingRedeemRequest(uint256,address) with requestId=0 and the vault address as the controller.
Returns:
| Type | Description |
|---|---|
int
|
Pending redemptions in share units (raw integer). |
get_share_price
¶
Get the current share price by converting 1 share to assets.
Uses convertToAssets(1e18) to get the value of one full share in underlying token units.
Returns:
| Type | Description |
|---|---|
Decimal
|
Share price as a Decimal (assets per share, normalized to 18 decimals). |
convert_to_assets
¶
Convert a share amount to underlying asset units via on-chain call.
Uses the ERC-4626 convertToAssets(uint256) function directly with the given share amount, avoiding precision loss from intermediate division.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
Vault contract address. |
required |
shares
|
int
|
Share amount in raw units (18 decimals). |
required |
Returns:
| Type | Description |
|---|---|
int
|
Equivalent underlying asset amount in raw units (underlying decimals). |
get_underlying_balance
¶
Read the underlying token balance of a wallet in the vault context.
Uses balanceOf(address) on the vault to read share balance, then could be converted to underlying. Returns raw share balance.
Returns:
| Type | Description |
|---|---|
int
|
Share balance (raw integer). |
get_proposed_total_assets
¶
Read the proposed total assets via direct storage slot read.
This value is set during the propose phase of settlement and represents the valuator's proposed total asset value.
Returns:
| Type | Description |
|---|---|
int
|
Proposed total assets in underlying token units (raw integer). |
has_live_proposal
¶
Return whether the vault currently holds a live (unconsumed) valuation proposal.
Lagoon v0.5.0 makes updateNewTotalAssets single-use: a settle call consumes
the proposal and resets the newTotalAssets slot to type(uint256).max
(PROPOSAL_CONSUMED). This read distinguishes "proposal still pending" from
"proposal already spent", which the settlement state machine needs to avoid
re-issuing a settle against a consumed proposal (which would revert
NewTotalAssetsMissing()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
expected
|
int | None
|
If provided, additionally require the live proposal to equal this value (guards against confirming a stale or unrelated proposal). |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if a live proposal exists (and matches |
get_silo_address
¶
Read the silo contract address via direct storage slot read.
The silo is a helper contract that holds deposited assets during the settlement process.
Returns:
| Type | Description |
|---|---|
str
|
Silo contract address as a checksummed hex string. |
get_new_total_assets
¶
Read the live proposed newTotalAssets() slot (VIB-5667).
Alias of :meth:get_proposed_total_assets — Lagoon's newTotalAssets
lives at PROPOSED_TOTAL_ASSETS_SLOT (base+1). The vault-release path
reads this back from chain AFTER updateNewTotalAssets and passes the
exact value to close(uint256) so the call cannot revert
WrongNewTotalAssets. Returns PROPOSAL_CONSUMED (type(uint256).max)
when no live proposal exists.
Returns:
| Type | Description |
|---|---|
int
|
The proposed total assets in underlying units (raw integer). |
get_vault_state
¶
Read the vault's lifecycle state: Open / Closing / Closed.
Lagoon v0.5.0 does NOT expose a public state() getter, so the State
enum (Open=0, Closing=1, Closed=2) is read directly from its ERC-7201
storage slot (VAULT_STATE_SLOT). Used by the vault-release state machine
for idempotent resume (skip already-completed phases after a crash).
Returns:
| Type | Description |
|---|---|
str
|
One of |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the stored ordinal is not a known state (fail loud rather than silently treating an unknown state as Open). |
get_underlying_token_address
¶
Read the vault's underlying token address (ERC-4626 asset()).
Returns:
| Type | Description |
|---|---|
str
|
Underlying token contract address as a hex string. |
get_roles_storage
¶
Read the vault's RolesStorage via getRolesStorage().
Returns a dict with the vault's role addresses, matching Lagoon v0.5.0: whitelistManager, feeReceiver, safe, feeRegistry, valuationManager
Returns:
| Type | Description |
|---|---|
dict
|
Dict with keys: whitelistManager, feeReceiver, safe, feeRegistry, valuationManager. |
get_owner
¶
Read the vault owner (owner() — the init.admin, Ownable).
The owner is the only address authorised to call initiateClosing().
The vault-release single-signer preflight asserts owner == safe == valuator
== the gateway's signing key before attempting a close (VIB-5667).
Returns:
| Type | Description |
|---|---|
str
|
Owner address as a hex string. |
get_valuation_manager
¶
Read the vault's valuation manager address.
Convenience method that calls getRolesStorage() and extracts the valuationManager. This is the address authorized to call updateNewTotalAssets().
Returns:
| Type | Description |
|---|---|
str
|
Valuation manager address as a hex string. |
get_curator
¶
Read the vault's curator (Safe) address.
Convenience method that calls getRolesStorage() and extracts the Safe address. This is the address that owns the vault and can call settleDeposit/settleRedeem.
Returns:
| Type | Description |
|---|---|
str
|
Curator (Safe) address as a hex string. |
verify_version
¶
Verify the on-chain vault version matches the expected version.
Reads the version() string from the vault contract and compares it to the expected VaultVersion. Raises ValueError on mismatch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
expected_version
|
VaultVersion
|
The expected VaultVersion enum value. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the on-chain version does not match. |
build_update_total_assets_tx
¶
build_update_total_assets_tx(
vault_address: str,
valuator_address: str,
new_total_assets: int,
) -> dict
Build an unsigned transaction for updateNewTotalAssets(uint256).
This is called by the valuator to propose a new total asset valuation during the settlement process.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
valuator_address
|
str
|
The valuator's address (tx sender). |
required |
new_total_assets
|
int
|
The proposed total assets in underlying token units. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_settle_deposit_tx
¶
Build an unsigned transaction for settleDeposit(uint256).
This is called by the safe (vault owner) to settle pending deposits after the valuator has proposed a new total asset value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
safe_address
|
str
|
The safe wallet address (tx sender). |
required |
total_assets
|
int
|
The total assets value for settlement. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_settle_redeem_tx
¶
Build an unsigned transaction for settleRedeem(uint256).
This is called by the safe (vault owner) to settle pending redemptions after deposits have been settled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
safe_address
|
str
|
The safe wallet address (tx sender). |
required |
total_assets
|
int
|
The total assets value for settlement. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_initiate_closing_tx
¶
Build an unsigned transaction for initiateClosing() (VIB-5667).
Called by the vault owner (init.admin) to transition Open->Closing.
Re-proposes the pending NAV if one is defined. No calldata arguments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
owner_address
|
str
|
The vault owner's address (tx sender). |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_close_tx
¶
Build an unsigned transaction for close(uint256) (VIB-5667).
Called by the Safe (Closing->Closed). Atomically takes fees, settles
deposits + redeems, sets state=Closed and pulls new_total_assets
underlying from the Safe into the vault. new_total_assets MUST equal
the on-chain newTotalAssets() slot exactly (read it back via
:meth:get_new_total_assets between propose and close), otherwise the
call reverts WrongNewTotalAssets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
safe_address
|
str
|
The Safe wallet address (tx sender). |
required |
new_total_assets
|
int
|
Final NAV; must equal the live |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_redeem_tx
¶
Build an unsigned tx for ERC-4626 redeem(uint256,address,address).
Post-close synchronous redemption: burns shares and transfers the
underlying to controller_address. Calls
redeem(shares, receiver=controller, owner=controller) — used to sweep
the manager's own residual shares after the vault is Closed (VIB-5667).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
controller_address
|
str
|
The share owner/receiver (tx sender). |
required |
shares
|
int
|
Number of shares to redeem (raw 18-decimal units). |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_approve_deposit_tx
¶
build_approve_deposit_tx(
underlying_token: str,
vault_address: str,
depositor: str,
amount: int,
) -> dict
Build an ERC20 approve tx so the vault can pull underlying tokens.
The depositor must approve the vault to spend amount of the underlying
token before calling requestDeposit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
underlying_token
|
str
|
Address of the underlying ERC20 token. |
required |
vault_address
|
str
|
The vault contract address (spender). |
required |
depositor
|
str
|
The depositor address (tx sender / token owner). |
required |
amount
|
int
|
Amount in raw underlying units to approve. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict. |
build_request_deposit_tx
¶
Build an ERC-7540 requestDeposit(uint256,address,address) tx.
Calls vault.requestDeposit(assets, controller=depositor, owner=depositor).
The depositor must have approved the vault for amount of underlying first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The vault contract address. |
required |
depositor
|
str
|
The depositor address (controller and owner). |
required |
amount
|
int
|
Amount of underlying tokens to deposit (raw units). |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict. |