erc_4626.vault_protocol.ember.deposit_redeem

Documentation for eth_defi.erc_4626.vault_protocol.ember.deposit_redeem Python module.

Ember synchronous-deposit and operator-finalised redemption support.

Ember deposits follow ERC-4626 deposit(uint256,address) semantics, while withdrawals use redeemShares(uint256,address) and are later paid directly to the requested receiver by the vault operator. See the Ember vault contracts.

Module Attributes

EMBER_LIQUIDITY_TOP_UP_MAX_ATTEMPTS

Bound Anvil-only top-ups when a deployed processor needs more than the quoted FIFO withdrawal prefix.

Classes

EmberDepositManager

Ember adapter with synchronous deposits and operator-finalised redemptions.

EmberRedemptionRequest

Two-call Ember redemption request: share approval and queue creation.

EmberRedemptionTicket

Persisted Ember withdrawal request.

EMBER_INSUFFICIENT_BALANCE_SELECTOR = HexBytes('0xf4d678b8')

InsufficientBalance() from Ember’s operator withdrawal processor.

EMBER_LIQUIDITY_TOP_UP_MAX_ATTEMPTS = 8

Bound Anvil-only top-ups when a deployed processor needs more than the quoted FIFO withdrawal prefix.

class EmberRedemptionTicket

Bases: eth_defi.vault.deposit_redeem.RedemptionTicket

Persisted Ember withdrawal request.

Ember’s globally monotonic request sequence identifies the later RequestProcessed event. The request block bound makes the terminal log lookup efficient and makes restart-safe persistence possible.

request_sequence_number: int

Globally monotonic Ember withdrawal request sequence.

block_number: int

Block that emitted RequestRedeemed.

block_timestamp: datetime.datetime

Naive UTC timestamp of block_number.

get_request_id()

Return Ember’s globally monotonic withdrawal request identifier.

Returns

Request sequence number used by the operator processing event.

Return type

int

__init__(vault_address, owner, to, raw_shares, tx_hash, request_sequence_number, block_number, block_timestamp)
Parameters
Return type

None

class EmberRedemptionRequest

Bases: eth_defi.vault.deposit_redeem.RedemptionRequest

Two-call Ember redemption request: share approval and queue creation.

parse_redeem_transaction(tx_hashes)

Parse and validate the RequestRedeemed receipt event.

The event is emitted by the Ember vault even when the outer transaction is a GuardV0 SimpleVault or Lagoon module call. Its timestamp is required to equal the receipt block timestamp at millisecond precision.

Parameters

tx_hashes (list[hexbytes.main.HexBytes]) – Hashes broadcast for this request; the final hash is redemption.

Returns

Validated, restart-safe Ember redemption ticket.

Raises

CannotParseRedemptionTransaction – If the receipt does not contain one matching Ember request event.

Return type

eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionTicket

__init__(vault, owner, to, shares, raw_shares, funcs)
Parameters
Return type

None

broadcast(from_=None, gas=1000000)

Broadcast all the transactions in this request.

Parameters
Returns

List of transaction hashes

Return type

list[hexbytes.main.HexBytes]

class EmberDepositManager

Bases: eth_defi.erc_4626.deposit_redeem.ERC4626DepositManager

Ember adapter with synchronous deposits and operator-finalised redemptions.

Ember pairs an ordinary ERC-4626 deposit path with a custom, operator-driven withdrawal queue. Deposits mint shares immediately, whereas withdrawals only escrow shares onchain and are paid out later by the vault operator, so the depositor never owns a claim step of their own. See the Ember vault contracts.

Deposit process. Synchronous. create_deposit_request() builds a single standard ERC-4626 deposit(assets, receiver) call (via deposit_4626()), preceded by the usual ERC-20 approve of the denomination token onto the vault. The receiver is explicit and defaults to owner; the zero address is rejected. Shares are minted in the same transaction, which emits Ember’s VaultDeposit event (not the ERC-4626 Deposit event) parsed by analyse_deposit().

Redemption process. Asynchronous. Ember does not use ERC-4626 redeem. create_redemption_request() builds two calls: a self approve(vault, shares) followed by the custom redeemShares(shares, receiver), which escrows the shares and enqueues the request. The request id is Ember’s globally monotonic sequenceNumber, read from the RequestRedeemed event by EmberRedemptionRequest.parse_redeem_transaction() and persisted in an EmberRedemptionTicket together with the request block. There is no depositor claim call — the operator pays the receiver directly, so can_finish_redeem() and finish_redemption() always report that no depositor-owned finish call exists.

Queues and settlement. Withdrawal requests accumulate in a single vault-global queue (not per owner). The vault operator — read at runtime from the roles() tuple (admin, operator, rateManager) — drains it by calling processWithdrawalRequests(n), which emits a terminal RequestProcessed event per request (carrying skipped/cancelled flags). minWithdrawableShares enforces a per-request minimum and pauseStatus gates both deposits and withdrawal requests.

Lockups and cooldowns. No deterministic onchain deadline exists: pay-out timing is entirely operator-driven. get_redemption_delay_over() therefore returns None, and estimate_redemption_delay() is only a service-level estimate from EmberVault.get_estimated_lock_up(), which reads Ember’s offchain withdrawal_period_days metadata and falls back to four days.

Whitelisting / access control. Permissionless — Ember has no deposit whitelist. can_create_deposit_request() only checks that deposits are unpaused and maxDeposit(owner) > 0, and can_create_redemption_request() only checks that withdrawals are unpaused and the owner holds at least minWithdrawableShares.

Anvil settlement (force_settle). Ember has no claimable ticket state: its configured operator processes a request and pays the receiver directly, leaving the ticket in AsyncVaultRequestStatus.none. The Anvil driver therefore accepts only the configured roles()[1] operator, validates the matching RequestProcessed event and returns direct-payout evidence only when the receiver’s denomination-token balance increased.

Create an Ember manager for a protocol-specific Ember vault.

Parameters

vault – Ember vault adapter whose ABI exposes the custom withdrawal queue.

__init__(vault)

Create an Ember manager for a protocol-specific Ember vault.

Parameters

vault (EmberVault) – Ember vault adapter whose ABI exposes the custom withdrawal queue.

create_deposit_request(owner, to=None, amount=None, raw_amount=None, check_max_deposit=True, check_enough_token=True)

Build one synchronous Ember deposit call with an explicit receiver.

Ember uses standard ERC-4626 deposits but emits VaultDeposit rather than Deposit. The generic constructor otherwise remains suitable.

Parameters
  • owner (eth_typing.evm.HexAddress) – Address funding the denomination token transfer.

  • to (Optional[eth_typing.evm.HexAddress]) – Share receiver; defaults to owner.

  • amount (Optional[decimal.Decimal]) – Decimal denomination amount, mutually exclusive with raw amount.

  • raw_amount (Optional[int]) – Raw denomination amount, mutually exclusive with decimal amount.

  • check_max_deposit (bool) – Check the vault’s current ERC-4626 maximum when requested.

  • check_enough_token (bool) – Check the owner’s current denomination balance when requested.

Returns

One-call synchronous deposit request.

Return type

eth_defi.erc_4626.deposit_redeem.ERC4626DepositRequest

create_redemption_request(owner, to=None, shares=None, raw_shares=None, check_max_deposit=True, check_enough_token=True)

Build Ember share approval followed by redeemShares.

Ember does not use ERC-4626 redeem. It escrows shares after a self-allowance and lets its operator transfer the final assets later.

Parameters
  • owner (eth_typing.evm.HexAddress) – Owner of Ember vault shares.

  • to (Optional[eth_typing.evm.HexAddress]) – Final asset receiver; defaults to owner.

  • shares (Optional[decimal.Decimal]) – Decimal shares, mutually exclusive with raw shares.

  • raw_shares (Optional[int]) – Raw shares, mutually exclusive with decimal shares.

  • check_max_deposit (bool) – Retained inherited API argument; Ember applies its own queue rules.

  • check_enough_token (bool) – Validate the owner’s current share balance before binding calls.

Returns

Two-call Ember request in approval then redemption order.

Return type

eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionRequest

has_synchronous_deposit()

Return whether Ember deposits finish in their submitted transaction.

Returns

Always True for Ember deposits.

Return type

bool

has_synchronous_redemption()

Return whether Ember redemptions finish in their submitted transaction.

Returns

Always False because an operator later processes the request.

Return type

bool

is_deposit_in_progress(owner)

Return whether Ember has an asynchronous deposit queue.

Parameters

owner (eth_typing.evm.HexAddress) – Ignored; Ember deposits are synchronous.

Returns

Always False.

Return type

bool

is_redemption_in_progress(owner)

Check the owner-specific Ember pending withdrawal amount.

getAccountState(owner) returns the owner’s totalPendingWithdrawalShares as its first ABI-named value, followed by that same owner’s pending sequence list. This is not a vault-global pending-share getter.

Parameters

owner (eth_typing.evm.HexAddress) – Ember share owner to inspect.

Returns

True when this owner has pending withdrawal shares.

Return type

bool

can_create_deposit_request(owner)

Check whether Ember currently advertises deposit availability.

The inherited API has no amount parameter, so this is not a cap or fillability guarantee. The actual deposit call still enforces the requested amount and current remaining cap.

Parameters

owner (eth_typing.evm.HexAddress) – Prospective deposit receiver used for maxDeposit.

Returns

True when deposits are unpaused and a positive maximum exists.

Return type

bool

can_create_redemption_request(owner)

Check current Ember withdrawal queue availability for an owner.

Parameters

owner (eth_typing.evm.HexAddress) – Owner whose share balance is checked.

Returns

True when withdrawals are unpaused and the owner can redeem at least Ember’s minimum withdrawal share amount.

Return type

bool

estimate_redemption_delay()

Return Ember’s off-chain operator service estimate.

The value comes from EmberVault.get_estimated_lock_up(), which reads Ember’s cached off-chain metadata and uses its documented four-day fallback. It is not an on-chain processing deadline.

Returns

Documented estimated operator processing interval.

Return type

datetime.timedelta

get_redemption_delay_over(address)

Return no deadline because Ember processing is operator-driven.

Parameters

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

Returns

Always None because no deterministic on-chain deadline exists.

Return type

Optional[datetime.datetime]

can_finish_redeem(redemption_ticket)

Report that an Ember depositor never owns a final claim call.

Parameters

redemption_ticket (eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionTicket) – Ember ticket whose settlement is operator-finalised.

Returns

Always False.

Return type

bool

finish_redemption(redemption_ticket)

Return no call because only Ember’s operator may process withdrawals.

Parameters

redemption_ticket (eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionTicket) – Ember ticket retained for type validation.

Returns

Always None; never an operator-only processing call.

Return type

Optional[web3.contract.contract.ContractFunction]

force_settle(ticket, *, mock=None, ignore_liquidity=True)

Process an Ember redemption through its configured Anvil operator.

Ember uses a direct payout rather than a user claim. The driver accepts it as terminal only after the exact request’s RequestProcessed event and a positive denomination-token balance delta prove the payout. A synchronous deposit remains a no-op settlement.

Parameters
Returns

Synchronous no-op or direct-payout terminal settlement result.

Raises

UnsupportedVaultSimulation – When the provider is not Anvil, the configured operator cannot be identified, the ticket is no longer in the global queue, or the operator transaction does not prove this ticket received a direct payout.

Return type

eth_defi.vault.deposit_redeem.VaultForcedSettlementResult

fetch_pending_withdrawal_index(ticket)

Locate an Ember ticket in the vault-global pending queue.

processWithdrawalRequests(n) consumes the first n queue items, rather than selecting an owner or request id. Resolving the exact index before broadcasting ensures the operator transaction reaches the requested ticket even when older requests are pending.

Parameters

ticket (eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionTicket) – Persisted Ember redemption request to locate.

Returns

Zero-based queue index of ticket.

Raises

UnsupportedVaultSimulation – If the exact request sequence is no longer pending in the global queue.

Return type

int

get_redemption_request_status(ticket)

Map the exact Ember request sequence to pending or consumed state.

Parameters

ticket (eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionTicket) – Persisted Ember redemption request.

Returns

pending while its sequence remains in the owner list, otherwise none. none is not evidence of successful payment.

Return type

eth_defi.vault.deposit_redeem.AsyncVaultRequestStatus

fetch_completed_redemption_tx_hash(ticket)

Locate and validate the operator RequestProcessed transaction.

The globally monotonic request sequence selects a candidate event within the ticket’s request-block-to-tip range. Owner, receiver and shares are then validated rather than used as filters, preventing a malformed ABI decode from being silently converted into a false None.

Parameters

ticket (eth_defi.vault.deposit_redeem.RedemptionTicket) – Ember redemption ticket whose terminal event is sought.

Returns

Unique matching operator transaction, or None before observed.

Raises

ValueError – If a matching sequence has inconsistent identity or duplicates.

Return type

Optional[hexbytes.main.HexBytes]

analyse_deposit(claim_tx_hash, deposit_ticket)

Analyse the actual Ember VaultDeposit receipt event.

Parameters
Returns

Executed deposit amounts or a transaction failure result.

Return type

Union[eth_defi.vault.deposit_redeem.DepositRedeemEventAnalysis, eth_defi.vault.deposit_redeem.DepositRedeemEventFailure]

analyse_redemption(claim_tx_hash, redemption_ticket)

Analyse one terminal Ember operator processing event.

Parameters
Returns

Executed payout, or skipped/cancelled terminal failure evidence.

Return type

Union[eth_defi.vault.deposit_redeem.DepositRedeemEventAnalysis, eth_defi.vault.deposit_redeem.DepositRedeemEventFailure]

serialize_redemption_ticket(ticket)

Serialise Ember’s sequence and canonical request-block identity.

Parameters

ticket (eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionTicket) – Ember ticket to persist across a process restart.

Returns

JSON-compatible base and Ember-specific ticket fields.

Return type

dict

reconstruct_redemption_ticket(data)

Rebuild an Ember ticket from its serialised request identity.

Parameters

data (dict) – JSON-compatible data returned by serialize_redemption_ticket().

Returns

Ticket ready for current-state and terminal-event checks.

Return type

eth_defi.erc_4626.vault_protocol.ember.deposit_redeem.EmberRedemptionTicket

fetch_vault_flow_events(hypersync_client, start_block, end_block)

Fetch historical Ember RequestRedeemed queue requests.

Parameters
  • hypersync_client – Configured Ethereum Hypersync client.

  • start_block (int) – Inclusive request-event block range start.

  • end_block (int) – Inclusive request-event block range end.

Returns

Event-derived pending redemption discovery hints in chain order.

Return type

collections.abc.Iterator[eth_defi.vault.flow_events.PendingVaultFlow]

can_finish_deposit(deposit_ticket)

Synchronous deposits can be finished immediately.

Parameters

deposit_ticket (eth_defi.erc_4626.deposit_redeem.ERC4626DepositTicket) –

check_deposit_whitelist(owner)

Reject a deposit when the vault’s whitelist excludes the owner.

Shared deposit-preflight helper implementing the whitelisting contract every manager must honour: when a vault applies a deposit whitelist policy that is applicable and queryable, and owner is not a member of it, raise WhitelistingRequired before any transaction is broadcast so the caller can surface a “whitelisting required” state instead of paying gas for a guaranteed revert.

The check is intentionally conservative — it only raises when the whitelist information can be obtained and is applicable:

  • if is_whitelisted_deposit() raises NotImplementedError, the vault-wide policy cannot be determined for this adapter/version, so no exception is raised;

  • if the vault is permissionless, no exception is raised;

  • if is_account_whitelisted() raises NotImplementedError, per-account membership cannot be queried, so no exception is raised;

  • only when the policy is applicable and the owner is provably not admitted is WhitelistingRequired raised.

Adapters that need a stricter fail-closed policy for an unknown admission state should override their own preflight and raise VaultFlowUnavailable in addition to calling this helper (see the Lagoon manager for an example).

Parameters

owner (eth_typing.evm.HexAddress) – Deposit owner and controller whose whitelist membership is checked.

Raises

WhitelistingRequired – When the vault applies an applicable, queryable whitelist policy and owner is not permitted to deposit.

Return type

None

create_deposit_request_for_guard_validation(owner, raw_amount)

Build ERC-4626 deposit calldata after a proven global closure.

This Anvil-only diagnostic path is available only when the selected vault’s authoritative global closure reader reports that deposits are unavailable to every account. It preserves the normal protocol admission preflight and all permanent amount constraints, while omitting the temporary closed-deposit capacity and token-balance checks needed to encode the production-equivalent deposit call.

Parameters
  • owner (eth_typing.evm.HexAddress) – Safe/SimpleVault address that would own the minted shares.

  • raw_amount (int) – Raw denomination-token amount from the rejected real-deposit attempt.

Returns

Single ERC-4626 deposit request for isolated GuardV0 validation.

Raises
Return type

eth_defi.erc_4626.deposit_redeem.ERC4626DepositRequest

estimate_deposit(owner, amount, block_identifier='latest')

How many shares we get for a deposit.

Parameters
Return type

decimal.Decimal

estimate_redeem(owner, shares, block_identifier='latest')

How many denomination tokens we get for a redeem.

Parameters
Return type

decimal.Decimal

fetch_depositable_raw_assets(owner)

Read the vault’s current raw deposit limit for an owner.

Overridable deposit-limit hook. The base implementation reads the standard ERC-4626 maxDeposit(). Multi-asset or non-standard vaults that do not implement maxDeposit (for example Upshift’s multi-asset vault) override this to answer from their own limit reader, so the deposit preflight does not depend on the ERC-4626 method being present.

Parameters

owner (eth_typing.evm.HexAddress) – Account the deposit limit is queried for.

Returns

Raw deposit limit, or None when the vault exposes no limit. A zero maxDeposit is omitted from this owner-specific capacity hook (EIP-4626 is not universally honoured), consistent with eth_defi.erc_4626.flow.deposit_4626(). The normal deposit preflight separately recognises a meaningful global zero through ERC4626Vault.fetch_deposit_closed_reason().

Raises

VaultFlowUnavailable – When the vault does not expose a readable ERC-4626 maxDeposit and no protocol-specific override is provided, instead of leaking a raw web3 ABI/read error.

Return type

Optional[int]

finish_deposit(deposit_ticket)

Can we finish the deposit process in async vault.

  • We can claim our shares from the vault now

Parameters

deposit_ticket (eth_defi.vault.deposit_redeem.DepositTicket) –

Return type

web3.contract.contract.ContractFunction

force_redemption_liquidity(owner, raw_shares, failure)

Provision an unavailable synchronous redemption on an Anvil fork.

Concrete managers may implement this only for a source-proven liquidity failure. The default is deliberately unsupported: this hook must never bypass admission, minimums, maturity or time locks.

Parameters
Returns

Structured intervention evidence from a concrete manager.

Raises

UnsupportedVaultSimulation – Always for managers without a protocol-specific implementation.

Return type

eth_defi.vault.deposit_redeem.VaultRedemptionSimulationIntervention

get_deposit_approval_target()

Return the ERC-20 spender required for a deposit request.

Standard ERC-4626 and the currently supported async adapters pull denomination tokens from the vault address itself. An adapter using a different router or silo must override this method; guarded callers use it to whitelist and validate the exact approval calldata.

Returns

ERC-20 approval spender address.

Return type

eth_typing.evm.HexAddress

get_deposit_delay_over(address)

Estimate when a pending async deposit request will settle.

  • Mirror of get_redemption_delay_over() for the deposit side.

  • Used to show an estimated settlement time for unsettled deposits (e.g. in the trade-executor trade-ui table).

  • Default returns None: the protocol has no deterministic onchain settlement schedule (e.g. operator-driven ERC-7540 vaults like Lagoon). Subclasses with a predictable settlement cadence (e.g. Ostium V1.5) override this to return an estimated UTC timestamp.

Parameters

address (Union[eth_typing.evm.HexAddress, str]) – Owner of the pending deposit request.

Returns

Naive UTC timestamp when the deposit is expected to settle, or None when no onchain estimate is available.

Return type

Optional[datetime.datetime]

get_deposit_request_status(ticket)

Query the current status of an async deposit request.

Default implementation probes via can_finish_deposit(). Subclasses should override for more accurate status reporting (e.g. distinguishing reclaimable from pending).

Parameters

ticket (eth_defi.vault.deposit_redeem.DepositTicket) –

Return type

eth_defi.vault.deposit_redeem.AsyncVaultRequestStatus

get_max_deposit(owner)

How much we can deposit

Parameters

owner (eth_typing.evm.HexAddress) –

Return type

Optional[decimal.Decimal]

reclaim_deposit(ticket)

Return a function to recover funds after a failed async deposit settlement.

Returns None if the protocol does not support reclaim.

Parameters

ticket (eth_defi.vault.deposit_redeem.DepositTicket) –

Return type

Optional[web3.contract.contract.ContractFunction]

reclaim_withdrawal(ticket)

Return a function to recover shares after a failed async withdrawal settlement.

Returns None if the protocol does not support reclaim.

Parameters

ticket (eth_defi.vault.deposit_redeem.RedemptionTicket) –

Return type

Optional[web3.contract.contract.ContractFunction]

reconstruct_deposit_ticket(data)

Reconstruct a deposit ticket from a serialised dict.

Default returns a base DepositTicket. Subclasses override for protocol-specific ticket types.

Parameters

data (dict) –

Return type

eth_defi.vault.deposit_redeem.DepositTicket

serialize_deposit_ticket(ticket)

Serialise a deposit ticket to a dict for persistence.

The trade-executor stores this in trade.other_data so that the settlement retry module can reconstruct the ticket after a process restart.

Default implementation stores base DepositTicket fields. Subclasses override to add protocol-specific fields (e.g. settlement_id for Ostium, requestId for ERC-7540).

Parameters

ticket (eth_defi.vault.deposit_redeem.DepositTicket) –

Return type

dict