Skip to content

Lido

Connector for Lido liquid staking protocol.

almanak.framework.connectors.lido

Lido Connector.

This module provides an adapter for interacting with Lido liquid staking protocol.

Lido is a decentralized liquid staking protocol supporting: - Stake ETH to receive stETH - Wrap stETH to wstETH (non-rebasing) - Unwrap wstETH to stETH

Supported chains: - Ethereum (full staking + wrap/unwrap) - Arbitrum, Optimism, Polygon (wstETH only)

Example

from almanak.framework.connectors.lido import LidoAdapter, LidoConfig

config = LidoConfig( chain="ethereum", wallet_address="0x...", ) adapter = LidoAdapter(config)

Stake ETH to receive stETH

result = adapter.stake(amount=Decimal("1.0"))

Wrap stETH to wstETH

result = adapter.wrap(amount=Decimal("1.0"))

LidoAdapter

LidoAdapter(
    config: LidoConfig,
    token_resolver: TokenResolver | None = None,
)

Adapter for Lido liquid staking protocol.

This adapter provides methods for interacting with Lido: - Stake ETH to receive stETH - Wrap stETH to wstETH (non-rebasing) - Unwrap wstETH back to stETH

Note: stETH is a rebasing token - balances change daily as rewards accrue. wstETH is non-rebasing and preferred for DeFi integrations.

Example

config = LidoConfig( chain="ethereum", wallet_address="0x...", ) adapter = LidoAdapter(config)

Stake ETH to get stETH

result = adapter.stake(Decimal("1.0"))

Wrap stETH to wstETH

result = adapter.wrap(Decimal("1.0"))

Unwrap wstETH back to stETH

result = adapter.unwrap(Decimal("1.0"))

Initialize the adapter.

Parameters:

Name Type Description Default
config LidoConfig

Adapter configuration

required
token_resolver TokenResolver | None

Optional TokenResolver instance. If None, uses singleton.

None

stake

stake(
    amount: Decimal,
    referral: str = "0x0000000000000000000000000000000000000000",
) -> TransactionResult

Build a stake transaction to receive stETH.

Stakes ETH to the Lido stETH contract and receives stETH in return. Only available on Ethereum mainnet.

Parameters:

Name Type Description Default
amount Decimal

Amount of ETH to stake

required
referral str

Referral address (default: zero address)

'0x0000000000000000000000000000000000000000'

Returns:

Type Description
TransactionResult

TransactionResult with transaction data

wrap

wrap(amount: Decimal) -> TransactionResult

Build a wrap transaction to convert stETH to wstETH.

Parameters:

Name Type Description Default
amount Decimal

Amount of stETH to wrap

required

Returns:

Type Description
TransactionResult

TransactionResult with transaction data

unwrap

unwrap(amount: Decimal) -> TransactionResult

Build an unwrap transaction to convert wstETH to stETH.

Parameters:

Name Type Description Default
amount Decimal

Amount of wstETH to unwrap

required

Returns:

Type Description
TransactionResult

TransactionResult with transaction data

request_withdrawal

request_withdrawal(
    amounts: list[Decimal], owner: str | None = None
) -> TransactionResult

Build a withdrawal request transaction.

Requests stETH withdrawal from the Lido withdrawal queue. Each amount in the list creates a separate withdrawal request. Only available on Ethereum mainnet.

Note: Requires prior approval of stETH to the withdrawal queue contract.

Parameters:

Name Type Description Default
amounts list[Decimal]

List of stETH amounts to withdraw

required
owner str | None

Address to own the withdrawal requests (default: wallet_address)

None

Returns:

Type Description
TransactionResult

TransactionResult with transaction data

claim_withdrawals

claim_withdrawals(
    request_ids: list[int], hints: list[int] | None = None
) -> TransactionResult

Build a claim withdrawals transaction.

Claims finalized withdrawal requests, sending ETH to msg.sender. Only available on Ethereum mainnet.

Note: Request IDs are returned when calling requestWithdrawals(). Hints can be obtained from findCheckpointHints() on the withdrawal queue, or pass None/empty list for the contract to compute them (higher gas).

Parameters:

Name Type Description Default
request_ids list[int]

List of withdrawal request IDs to claim

required
hints list[int] | None

Checkpoint hints for each request ID (optional, improves gas)

None

Returns:

Type Description
TransactionResult

TransactionResult with transaction data

compile_stake_intent

compile_stake_intent(
    intent: StakeIntent, market_snapshot: Any | None = None
) -> ActionBundle

Compile a StakeIntent to an ActionBundle.

This method converts a high-level StakeIntent into executable transaction data. It handles the receive_wrapped flag: - If receive_wrapped=True: stake ETH -> stETH, then wrap stETH -> wstETH - If receive_wrapped=False: stake ETH -> stETH only

Parameters:

Name Type Description Default
intent StakeIntent

The StakeIntent to compile

required
market_snapshot Any | None

Optional market data (not used for Lido)

None

Returns:

Type Description
ActionBundle

ActionBundle containing transaction(s) for execution

Raises:

Type Description
ValueError

If amount="all" is not resolved before compilation

compile_unstake_intent

compile_unstake_intent(
    intent: UnstakeIntent,
    market_snapshot: Any | None = None,
) -> ActionBundle

Compile an UnstakeIntent to an ActionBundle.

This method converts a high-level UnstakeIntent into executable transaction data. It handles the token_in type: - If token_in is wstETH: unwrap wstETH -> stETH first, then request withdrawal - If token_in is stETH: request withdrawal directly

Note: This only initiates the withdrawal request. Actual ETH claiming happens separately after the withdrawal is finalized (claim_withdrawals).

Parameters:

Name Type Description Default
intent UnstakeIntent

The UnstakeIntent to compile

required
market_snapshot Any | None

Optional market data (not used for Lido)

None

Returns:

Type Description
ActionBundle

ActionBundle containing transaction(s) for execution

Raises:

Type Description
ValueError

If amount="all" is not resolved before compilation

LidoConfig dataclass

LidoConfig(chain: str, wallet_address: str)

Configuration for Lido adapter.

Attributes:

Name Type Description
chain str

Blockchain network (ethereum, arbitrum, optimism, polygon)

wallet_address str

User wallet address

__post_init__

__post_init__() -> None

Validate configuration.

TransactionResult dataclass

TransactionResult(
    success: bool,
    tx_data: dict[str, Any] | None = None,
    gas_estimate: int = 0,
    description: str = "",
    error: str | None = None,
)

Result of a transaction build operation.

Attributes:

Name Type Description
success bool

Whether operation succeeded

tx_data dict[str, Any] | None

Transaction data (to, value, data)

gas_estimate int

Estimated gas

description str

Human-readable description

error str | None

Error message if failed

LidoEventType

Bases: Enum

Lido event types.

LidoReceiptParser

LidoReceiptParser(chain: str = 'ethereum', **kwargs: Any)

Parser for Lido transaction receipts.

Refactored to use base infrastructure utilities for hex decoding and event registry management. Handles multiple contracts (stETH, wstETH, withdrawal queue) with different event types.

Initialize the parser.

Parameters:

Name Type Description Default
chain str

Blockchain network (ethereum, arbitrum, optimism, polygon)

'ethereum'
**kwargs Any

Additional arguments (ignored for compatibility)

{}

parse_receipt

parse_receipt(receipt: dict[str, Any]) -> ParseResult

Parse a transaction receipt.

Parameters:

Name Type Description Default
receipt dict[str, Any]

Transaction receipt dict

required

Returns:

Type Description
ParseResult

ParseResult with extracted events

parse_stake

parse_stake(log: dict[str, Any]) -> StakeEventData | None

Parse a Submitted (stake) event from a single log entry.

parse_wrap

parse_wrap(log: dict[str, Any]) -> WrapEventData | None

Parse a wrap event (Transfer from zero address) from a single log entry.

parse_unwrap

parse_unwrap(log: dict[str, Any]) -> UnwrapEventData | None

Parse an unwrap event (Transfer to zero address) from a single log entry.

parse_withdrawal_requested

parse_withdrawal_requested(
    log: dict[str, Any],
) -> WithdrawalRequestedEventData | None

Parse a WithdrawalRequested event from a single log entry.

parse_withdrawals_claimed

parse_withdrawals_claimed(
    log: dict[str, Any],
) -> WithdrawalClaimedEventData | None

Parse a WithdrawalClaimed event from a single log entry.

is_lido_event

is_lido_event(topic: str | bytes) -> bool

Check if a topic is a known Lido event.

Parameters:

Name Type Description Default
topic str | bytes

Event topic (supports bytes, hex string with/without 0x, any case)

required

Returns:

Type Description
bool

True if topic is a known Lido event

get_event_type

get_event_type(
    topic: str | bytes, log: dict[str, Any] | None = None
) -> LidoEventType

Get the event type for a topic.

Parameters:

Name Type Description Default
topic str | bytes

Event topic (supports bytes, hex string with/without 0x, any case)

required
log dict[str, Any] | None

Optional log dict for disambiguating Transfer events

None

Returns:

Type Description
LidoEventType

Event type or UNKNOWN

extract_stake_amount

extract_stake_amount(receipt: dict[str, Any]) -> int | None

Extract stake amount from transaction receipt.

Parameters:

Name Type Description Default
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

required

Returns:

Type Description
int | None

Stake amount in wei if found, None otherwise

extract_shares_received

extract_shares_received(
    receipt: dict[str, Any],
) -> int | None

Extract stETH/wstETH shares received from transaction receipt.

When staking ETH, user receives stETH. When wrapping stETH, user receives wstETH.

Parameters:

Name Type Description Default
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

required

Returns:

Type Description
int | None

Shares received in wei if found, None otherwise

extract_unstake_amount

extract_unstake_amount(
    receipt: dict[str, Any],
) -> int | None

Extract unstake amount from transaction receipt.

This is the amount of stETH requested for withdrawal.

Parameters:

Name Type Description Default
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

required

Returns:

Type Description
int | None

Unstake amount in wei if found, None otherwise

extract_underlying_received

extract_underlying_received(
    receipt: dict[str, Any],
) -> int | None

Extract underlying ETH received from withdrawal claim.

Parameters:

Name Type Description Default
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

required

Returns:

Type Description
int | None

ETH received in wei if found, None otherwise

ParseResult dataclass

ParseResult(
    success: bool,
    stakes: list[StakeEventData] = list(),
    wraps: list[WrapEventData] = list(),
    unwraps: list[UnwrapEventData] = list(),
    withdrawal_requests: list[
        WithdrawalRequestedEventData
    ] = list(),
    withdrawal_claims: list[
        WithdrawalClaimedEventData
    ] = list(),
    error: str | None = None,
    transaction_hash: str = "",
    block_number: int = 0,
)

Result of parsing a receipt.

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

StakeEventData dataclass

StakeEventData(
    sender: str, amount: Decimal, referral: str = ""
)

Parsed data from Submitted event (stake operation).

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

UnwrapEventData dataclass

UnwrapEventData(
    from_address: str,
    to_address: str,
    amount: Decimal,
    token: str = "",
)

Parsed data from unwrap operation (Transfer event on wstETH).

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

WithdrawalClaimedEventData dataclass

WithdrawalClaimedEventData(
    request_id: int,
    owner: str,
    receiver: str,
    amount_of_eth: Decimal,
)

Parsed data from WithdrawalClaimed event.

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

WithdrawalRequestedEventData dataclass

WithdrawalRequestedEventData(
    request_id: int,
    requestor: str,
    owner: str,
    amount_of_steth: Decimal,
    amount_of_shares: Decimal,
)

Parsed data from WithdrawalRequested event.

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

WrapEventData dataclass

WrapEventData(
    from_address: str,
    to_address: str,
    amount: Decimal,
    token: str = "",
)

Parsed data from wrap operation (Transfer event on wstETH).

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.