Morpho Vault¶
| Field | Value |
|---|---|
| Module | almanak.connectors.morpho_vault |
| 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 |
morpho_vault
¶
MetaMorpho Vault Connector.
This module provides adapters and utilities for interacting with MetaMorpho vaults, the ERC-4626 vault layer that aggregates capital across Morpho Blue lending markets.
MetaMorpho Features: - ERC-4626 compliant vault deposits and redemptions - Passive yield optimization with curator-managed allocation - Multi-market capital allocation across Morpho Blue markets - Transparent share pricing via convertToAssets/convertToShares
Supported Chains: - Ethereum - Base
Example
from almanak.connectors.morpho_vault import (
MetaMorphoAdapter,
MetaMorphoConfig,
MetaMorphoReceiptParser,
MetaMorphoSDK,
create_test_adapter,
)
from decimal import Decimal
# Initialize adapter
config = MetaMorphoConfig(chain="ethereum", wallet_address="0x...")
adapter = MetaMorphoAdapter(config, gateway_client=gateway_client)
# Deposit assets
result = adapter.deposit(
vault_address="0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB",
amount=Decimal("1000"),
)
# Redeem all shares
result = adapter.redeem(
vault_address="0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB",
shares="all",
)
# Parse transaction receipts
parser = MetaMorphoReceiptParser()
parse_result = parser.parse_receipt(receipt)
MetaMorphoAdapter
¶
MetaMorphoAdapter(
config: MetaMorphoConfig,
gateway_client=None,
token_resolver: TokenResolver | None = None,
)
Adapter for MetaMorpho vault protocol.
Provides high-level methods for depositing into and redeeming from MetaMorpho ERC-4626 vaults, with token resolution and validation.
Example
Initialize the adapter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
MetaMorphoConfig
|
Adapter configuration |
required |
gateway_client
|
Gateway client for RPC calls. Required for on-chain operations. |
None
|
|
token_resolver
|
TokenResolver | None
|
Optional TokenResolver instance. If None, uses singleton. |
None
|
get_vault_info
¶
Get complete vault information.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
MetaMorpho vault address |
required |
Returns:
| Type | Description |
|---|---|
VaultInfo
|
VaultInfo with vault state |
get_position
¶
Get user's position in the vault.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
MetaMorpho vault address |
required |
user
|
str | None
|
User address (defaults to wallet_address) |
None
|
Returns:
| Type | Description |
|---|---|
VaultPosition
|
VaultPosition with shares and assets |
deposit
¶
Build a deposit transaction for a MetaMorpho vault.
This builds approve + deposit transactions. The approve TX authorizes the vault to pull the exact amount of underlying tokens.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
MetaMorpho vault address |
required |
amount
|
Decimal
|
Amount of underlying assets to deposit (in token units, e.g. 1000.0 USDC) |
required |
Returns:
| Type | Description |
|---|---|
TransactionResult
|
TransactionResult with transaction data for both approve and deposit |
redeem
¶
redeem(
vault_address: str,
shares: Decimal | str,
*,
allow_force_deallocate: bool = False,
max_force_deallocate_penalty_bps: int = 10,
) -> TransactionResult
Build a redeem transaction for a Morpho vault (v1 or V2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
Morpho vault address |
required |
shares
|
Decimal | str
|
Number of shares to redeem, or "all" to redeem all |
required |
allow_force_deallocate
|
bool
|
V2 only — permit a penalised forced exit
( |
False
|
max_force_deallocate_penalty_bps
|
int
|
V2 only — refuse a forced exit whose penalty exceeds this share of the redeemed assets. |
10
|
Returns:
| Type | Description |
|---|---|
TransactionResult
|
TransactionResult with transaction data |
build_approve_transaction
¶
Build an ERC20 approve transaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
Token symbol or address |
required |
amount
|
Decimal
|
Amount to approve |
required |
spender
|
str
|
Address to approve |
required |
Returns:
| Type | Description |
|---|---|
TransactionResult
|
TransactionResult with transaction data |
MetaMorphoConfig
dataclass
¶
Configuration for MetaMorpho adapter.
Attributes:
| Name | Type | Description |
|---|---|---|
chain |
str
|
Blockchain network (ethereum, base) |
wallet_address |
str
|
User wallet address |
TransactionResult
dataclass
¶
TransactionResult(
success: bool,
tx_data: dict[str, Any] | None = None,
gas_estimate: int = 0,
description: str = "",
error: str | None = None,
requires_atomic: bool = False,
)
Result of a transaction build operation.
Attributes:
| Name | Type | Description |
|---|---|---|
success |
bool
|
Whether operation succeeded |
tx_data |
dict[str, Any] | None
|
Transaction payloads only (to/value/data). Execution order is insertion order; force-deallocate legs come before redeem. |
gas_estimate |
int
|
Estimated gas |
description |
str
|
Human-readable description |
error |
str | None
|
Error message if failed |
requires_atomic |
bool
|
When True, the caller must put this on
|
MetaMorphoEvent
dataclass
¶
MetaMorphoEvent(
event_type: MetaMorphoEventType,
event_name: str,
log_index: int,
transaction_hash: str,
block_number: int,
contract_address: str,
data: dict[str, Any],
raw_topics: list[str] = list(),
raw_data: str = "",
)
Parsed MetaMorpho event.
MetaMorphoEventType
¶
Bases: Enum
MetaMorpho event types.
MetaMorphoReceiptParser
¶
Parser for MetaMorpho vault transaction receipts.
Extracts ERC-4626 Deposit/Withdraw events and ERC-20 Transfer/Approval events.
Example
parser = MetaMorphoReceiptParser() result = parser.parse_receipt(receipt) if result.success: for event in result.events: print(f"{event.event_name}: {event.data}")
Initialize the parser.
parse_receipt
¶
Parse a transaction receipt.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
receipt
|
dict[str, Any]
|
Transaction receipt dictionary with 'logs' field |
required |
timestamp
|
datetime | None
|
Optional timestamp for events |
None
|
Returns:
| Type | Description |
|---|---|
ParseResult
|
ParseResult with parsed events |
extract_deposit_data
¶
Extract deposit data from transaction receipt.
Called by ResultEnricher for VAULT_DEPOSIT intents.
Returns:
| Type | Description |
|---|---|
dict | None
|
Dict with {assets, shares, share_price_raw} if found, None otherwise. |
dict | None
|
All values are in raw on-chain units (wei). share_price_raw is the |
dict | None
|
ratio of raw assets to raw shares -- to get a human-readable price, |
dict | None
|
normalize by asset and share decimals. |
extract_redeem_data
¶
Extract redeem data from transaction receipt.
Called by ResultEnricher for VAULT_REDEEM intents. The redemption is the
Withdraw that pays an external receiver; penalty Withdraws (receiver ==
vault, emitted by forceDeallocate) are reported separately as
penalty_shares / penalty_assets and NEVER as the payout. A
receipt holding only penalty legs yields None so the enricher moves
on to the receipt that carries the redemption.
Returns:
| Type | Description |
|---|---|
dict | None
|
Dict with {shares_burned, assets_received, penalty_shares, penalty_assets} |
dict | None
|
if a payout Withdraw is found, None otherwise. |
extract_force_deallocate_penalty
¶
Sum the forceDeallocate penalty legs (Withdraws paid to the vault itself) in a receipt.
Returns:
| Type | Description |
|---|---|
dict | None
|
Dict with {penalty_shares, penalty_assets} when at least one penalty |
dict | None
|
leg is present, None otherwise. |
ParseResult
dataclass
¶
ParseResult(
success: bool,
events: list[MetaMorphoEvent] = list(),
error: str | None = None,
transaction_hash: str = "",
block_number: int = 0,
)
Result of parsing a transaction receipt.
TransferEventData
dataclass
¶
Parsed data from ERC-20 Transfer event.
VaultDepositEventData
dataclass
¶
Parsed data from ERC-4626 Deposit event.
VaultWithdrawEventData
dataclass
¶
Parsed data from ERC-4626 Withdraw event.
DepositExceedsCapError
¶
Bases: MetaMorphoSDKError
Raised when deposit amount exceeds vault's maxDeposit.
InsufficientSharesError
¶
Bases: MetaMorphoSDKError
Raised when redeem amount exceeds user's redeemable shares.
MetaMorphoSDK
¶
Low-level SDK for reading MetaMorpho 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 |
detect_vault_version
¶
Fingerprint the vault generation on-chain (cached per address).
withdrawQueueLength() answers only on MetaMorpho v1;
adaptersLength() answers only on Morpho Vault V2. A contract that
answers neither is not a Morpho vault this connector knows how to exit
safely — UnsupportedVaultError rather than a guess.
get_vault_asset
¶
Read the vault's underlying asset address (asset()).
get_total_assets
¶
Read the vault's total assets (totalAssets()).
get_total_supply
¶
Read the vault's total share supply (totalSupply()).
get_share_price
¶
Get share price as convertToAssets(one_share) in raw underlying units.
get_decimals
¶
Read the vault's share decimals (decimals()). Always 18 for MetaMorpho.
get_balance_of
¶
Read user's share balance in the vault.
get_max_deposit
¶
Read maximum deposit amount allowed for a receiver.
get_max_redeem
¶
Read maximum shares that can be redeemed by an owner.
preview_deposit
¶
Preview how many shares a deposit of assets would mint.
preview_redeem
¶
Preview how many assets a redemption of shares would return.
convert_to_assets
¶
Convert share amount to asset amount.
convert_to_shares
¶
Convert asset amount to share amount.
get_redeemable_shares
¶
Shares a redeem-all should request, by generation.
v1: maxRedeem(owner) — a hair below balanceOf because of the
ERC-4626 round-trip rounding; redeem(balanceOf) reverts there.
V2: balanceOf(owner) — V2 returns 0 from every max* view by
design, so maxRedeem would turn every exit into "No shares to
redeem". Liquidity is checked by simulate_redeem.
simulate_redeem
¶
Dry-run redeem(shares, receiver, owner) as an eth_call from owner.
Returns the assets the redeem would return. Raises VaultIlliquidError
when the call reverts — on V2 that is the "idle + liquidity adapter
cannot cover this" signal (or a gate refusal); the tx must not be sent.
check_deposit_gate
¶
V2 only: raise VaultGatedError if the deposit is gated.
A V2 vault can configure sendAssetsGate independently of
receiveSharesGate: the depositing wallet (sender) must be
allowed to supply the underlying, and receiver must be allowed
to receive shares. receiver defaults to sender.
check_redeem_gates
¶
V2 only: raise VaultGatedError if owner may not send shares or receiver receive assets.
get_v2_liquidity_data
¶
The vault's liquidityData() — abi.encode(MarketParams) of the liquidity market.
get_v2_adapter_market_ids
¶
Enumerate marketIds(i) on a MorphoMarketV1Adapter until it reverts.
get_v2_adapter_morpho
¶
The Morpho Blue singleton the adapter allocates to.
get_morpho_blue_market_params_data
¶
idToMarketParams(id) as raw 160-byte hex — the adapter's data for that market.
get_morpho_blue_market_liquidity
¶
market(id) → (totalSupplyAssets, totalSupplyShares, available liquidity).
get_morpho_blue_supply_shares
¶
position(id, account).supplyShares.
get_asset_balance_of
¶
ERC-20 balanceOf of account on token (the vault's idle assets when account is the vault).
preview_withdraw
¶
previewWithdraw(assets) — shares burned to withdraw assets (rounds up).
plan_force_deallocate
¶
plan_force_deallocate(
vault_address: str,
shares: int,
owner: str,
max_penalty_bps: int,
) -> ForceDeallocatePlan
Size a forced exit for redeeming shares against live state.
Shortfall = assets the redeem needs − vault idle assets − what the
vault's own liquidity market can serve (the normal path already drains
that one). The shortfall (+ a 0.1% accrual buffer) is covered from the
adapters' OTHER markets, largest withdrawable first, where withdrawable
is min(adapter's supplied assets there, that market's free liquidity).
Refused whole when the markets cannot cover it or the total penalty
exceeds max_penalty_bps of the redeemed assets.
build_force_deallocate_tx
¶
build_force_deallocate_tx(
vault_address: str,
adapter: str,
market_params_data: str,
assets: int,
on_behalf: str,
) -> dict
Unsigned forceDeallocate call (sent by on_behalf, who pays the penalty).
simulate_force_deallocate
¶
simulate_force_deallocate(
vault_address: str,
adapter: str,
market_params_data: str,
assets: int,
on_behalf: str,
) -> None
Dry-run one forceDeallocate leg from on_behalf; raises VaultIlliquidError on revert.
get_fee
¶
Read the vault's performance fee (WAD scale, 1e18 = 100%).
get_timelock
¶
Read the vault's timelock duration in seconds.
is_allocator
¶
Check if an address is an allocator for the vault.
get_supply_queue
¶
Read the vault's supply queue (list of market IDs).
get_withdraw_queue
¶
Read the vault's withdraw queue (list of market IDs).
get_vault_info
¶
Read complete vault information in multiple RPC calls (generation-aware).
The ERC-4626 block is shared; the generation-specific block reads the
selectors that exist on that generation only (v1 fee/timelock
revert on V2, V2 fee/adapter reads revert on v1).
get_position
¶
Read a user's position in the vault.
build_deposit_tx
¶
Build an unsigned ERC-4626 deposit(uint256,address) transaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The MetaMorpho vault address. |
required |
assets
|
int
|
Amount of underlying assets to deposit (raw units). |
required |
receiver
|
str
|
Address to receive vault shares. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_redeem_tx
¶
Build an unsigned ERC-4626 redeem(uint256,address,address) transaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault_address
|
str
|
The MetaMorpho vault address. |
required |
shares
|
int
|
Number of shares to redeem (raw units). |
required |
receiver
|
str
|
Address to receive underlying assets. |
required |
owner
|
str
|
Address that owns the shares being redeemed. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict with keys: to, from, data, value, gas_estimate. |
build_approve_tx
¶
Build an ERC-20 approve transaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token_address
|
str
|
The ERC-20 token address. |
required |
spender
|
str
|
The address to approve. |
required |
amount
|
int
|
Amount to approve (raw units). |
required |
owner
|
str
|
The address that owns the tokens (tx sender). |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Unsigned transaction dict. |
MetaMorphoSDKError
¶
Bases: Exception
Base exception for MetaMorpho SDK errors.
RPCError
¶
Bases: MetaMorphoSDKError
Raised when an RPC call fails.
UnsupportedChainError
¶
Bases: MetaMorphoSDKError
Raised when chain is not supported.
VaultInfo
dataclass
¶
VaultInfo(
address: str,
asset: str,
total_assets: int,
total_supply: int,
share_price: int,
decimals: int,
curator: str,
fee: int,
timelock: int,
vault_version: str = VAULT_VERSION_V1,
management_fee: int = 0,
liquidity_adapter: str | None = None,
adapters: list[str] = list(),
force_deallocate_penalty: int | None = None,
)
Information about a MetaMorpho vault.
VaultMarketConfig
dataclass
¶
Market configuration within a MetaMorpho vault (Phase 2).
VaultNotFoundError
¶
Bases: MetaMorphoSDKError
Raised when vault contract does not exist or returns invalid data.
VaultPosition
dataclass
¶
User position in a MetaMorpho vault.
create_test_adapter
¶
create_test_adapter(
chain: str = "ethereum",
wallet_address: str = "0x1234567890123456789012345678901234567890",
) -> MetaMorphoAdapter
Create a test adapter without gateway client (for unit tests).
For unit testing only. On-chain operations will raise RuntimeError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
chain
|
str
|
Chain name (default: ethereum) |
'ethereum'
|
wallet_address
|
str
|
Wallet address (default: test address) |
'0x1234567890123456789012345678901234567890'
|
Returns:
| Type | Description |
|---|---|
MetaMorphoAdapter
|
MetaMorphoAdapter configured for testing |