KeeperHub / KeeperHub/keeperhub

feat(protocols): add Lido Withdrawal Queue lifecycle support

Open
#2,433 1 comment 0 reactions 0 assignees View on GitHub
accepted confirmed enhancement
Dominant language
TypeScript
Stars
24
Forks
93
Avg merge
1d 4h
Merged PRs (30d)
253

Description

## Before filing

- [x] I searched open and closed issues for this proposal.
- [x] I checked the docs and current behavior on `staging`.
- [x] This is one change, not several.

## Reason: what you cannot do today

I am building a real Lido withdrawal lifecycle in which an agent validates and monitors a request while KeeperHub is the only component allowed to move value. KeeperHub's existing `lido` protocol exposes stETH approval plus wstETH wrap, unwrap, balance, supply, and exchange-rate actions, but it does not expose Lido's Withdrawal Queue.

A protocol workflow therefore cannot natively:

- request an stETH or wstETH withdrawal;
- discover the request IDs owned by a wallet;
- inspect the queue's structured request status;
- calculate checkpoint hints and claimable ETH; or
- claim a finalized request back to its owner.

Lido's queue is deliberately a multi-stage lifecycle: request now, wait for oracle finalization, then claim. Those are the protocol primitives a reliable workflow needs; wrapping and balance reads alone cannot complete the withdrawal.

## Reason: what the workaround costs

The workaround is a set of generic `web3/read-contract` and `web3/write-contract` nodes with a hand-pasted proxy address, reduced ABI, array arguments, tuple-array output knowledge, and event definitions. Every builder has to rediscover the same boundary and manually distinguish owner-directed `claimWithdrawals` from arbitrary-recipient `claimWithdrawalsTo`.

That loses the first-class action discovery, labels, schemas, output fields, and shared protocol coverage that the existing Lido connector provides. It also makes the highest-risk part of the lifecycle, claiming ETH, the place where each agent author has to reproduce contract details manually.

I verified the missing surface from a real integration, not a hypothetical one. Against Ethereum mainnet on 2026-09-13, the official Wayfinder `LidoAdapter` and an independent ethers call both returned request `135184` as finalized and unclaimed for `0x60042Ce11258A07E1BC6Bd63983C6Ee63E80c2DC`, with checkpoint hint `1216`. A local derivation spike against KeeperHub `staging` commit `f8c8f18c754ccbca481774a1c3c0fdf71e282e96` successfully derived the proposed actions and events, encoded request and claim calls, and structured the live `getWithdrawalStatus` `tuple[]` response.

## Scope: what this touches, and what it does not

In scope:

- Extend the existing `protocols/lido.ts` definition with one `withdrawalQueue` contract entry for Ethereum mainnet at `0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1`.
- Add a reduced official ABI for this one lifecycle: `requestWithdrawals`, `requestWithdrawalsWstETH`, `getWithdrawalRequests`, `getWithdrawalStatus`, `getLastCheckpointIndex`, `findCheckpointHints`, `getClaimableEther`, and `claimWithdrawals`.
- Expose the queue's `WithdrawalRequested`, `WithdrawalsFinalized`, and `WithdrawalClaimed` events from the same contract entry.
- Extend the existing Lido unit and Ethereum protocol-coverage fixtures for the added surface.

The actions and events belong to one contract lifecycle and one protocol-definition entry: the request event supplies the authoritative IDs used by the status and claim stages, the finalization event wakes the status check, and the claim event verifies the terminal write. They are tested and consumed together rather than introducing a second connector or abstraction.

Deliberately out of scope:

- No chain other than Ethereum mainnet. Lido's canonical Withdrawal Queue is the target being integrated.
- No `requestWithdrawalsWithPermit`, `requestWithdrawalsWstETHWithPermit`, single-item convenience calls, queue administration, oracle finalization, pause controls, ERC-721 transfer/approval actions, or metadata methods.
- No `claimWithdrawalsTo`; the first write scope can only return ETH to `msg.sender`, who must own every request.
- No change to KeeperHub core execution, wallet permissions, schemas, APIs, UI, dependencies, or the existing Lido actions.
- No Wayfinder-specific code and no product-level monitor. Those remain consumers of the reusable protocol surface.
- No attempt to fix the separate advertised-output problem in #2424. Every single-output queue ABI entry is explicitly named so its runtime result has the same stable key the action advertises.

Searches for `Lido`, `withdrawal`, and `unstETH` across open and closed KeeperHub issues and pull requests found the existing Lido connector work but no Withdrawal Queue proposal or implementation.

## Plan: what you propose

1. Add a minimal `WITHDRAWAL_QUEUE_ABI` inside `protocols/lido.ts`, following the file's current `defineAbiProtocol` pattern and Lido's official deployed contract/source.
2. Register the `withdrawalQueue` contract at the canonical Ethereum address and add editorial overrides for plain labels, help text, named outputs, and 18-decimal ETH/stETH values where applicable.
3. Keep Solidity array values as arrays through the existing ABI argument pipeline and keep `getWithdrawalStatus.statuses` as a named `tuple[]` with `amountOfStETH`, `amountOfShares`, `owner`, `timestamp`, `isFinalized`, and `isClaimed` components.
4. Add the three queue event definitions with their official indexed fields.
5. Extend `tests/unit/protocol-lido.test.ts` to cover the new contract, action/read/write counts, exact slugs/functions, array inputs, named tuple-array output, owner-only claim, event shapes, and absence of arbitrary-recipient claim actions.
6. Extend Lido's Ethereum test data and coverage where the harness can establish the real precondition. The existing mainnet-fork WSTETH whale can fund and approve a small `requestWithdrawalsWstETH` call; its receipt can verify `WithdrawalRequested` and the resulting request status. Read actions get non-vacuous expectations against the created or known queue state.
7. Mark only lifecycle writes whose oracle-controlled precondition cannot be created by the generic fixture as explicit skips with the reason. Cover their ABI encoding and safety shape in unit tests rather than pretending a claimable request exists. If maintainers prefer a Lido-specific fork setup that creates a finalized request, I will follow that direction instead.
8. Run `pnpm type-check`, `pnpm fix`, the focused Lido/unit tests, and the Lido Ethereum protocol-coverage suite.

This adds actions and events; it changes no existing action slug, response shape, default, or address mapping. It adds no dependency and requires no migration.

## Plan: alternatives considered

- Do nothing and keep using generic Web3 nodes: workable for one application, but every agent author must manually reproduce a safety-sensitive protocol lifecycle and receives none of the native connector's discovery or coverage.
- Create a second protocol such as `lido-withdrawals`: rejected because KeeperHub already has a Lido protocol and the queue is part of that same user-facing protocol.
- Add only request and claim writes: rejected because the delayed lifecycle cannot safely decide when to claim without the status, checkpoint, and claimable-ETH reads.
- Add every Withdrawal Queue method: rejected because permit, administration, oracle, ERC-721 transfer, and arbitrary-recipient features can ship independently and materially widen the review surface.
- Add `claimWithdrawalsTo`: rejected for the initial scope because arbitrary recipient selection is not required to complete an owner withdrawal and expands the wallet permission risk.
- Add a new SDK dependency: rejected because the ABI-driven protocol registry already represents the complete surface and KeeperHub protocol plugins should not depend on third-party SDKs.

## Scope: compatibility

- [ ] Changes an existing response shape, status code, CLI flag, or default.
- [ ] Adds, removes, or upgrades a dependency.
- [ ] Changes database schema or requires a migration.
- [ ] Touches authentication, permissions, validation, or spend limits.
- [ ] Changes pricing, plan limits, or anything a user is charged.

## AI assistance

AI assistance was used to inspect the repository, exercise the existing ABI derivation/structuring code, and draft this proposal. The source references, live RPC result, action/event shapes, issue/PR search, and commands above were verified against the named commits before filing.

Contributor guide

Open the contributing guide

Research direction

Start with protocols/lido.ts and its existing defineAbiProtocol pattern, then read tests/unit/protocol-lido.test.ts and the Lido Ethereum protocol-coverage fixtures. Add the scoped Withdrawal Queue contract, actions, reads, events, and safety-shaped tests described in the issue; done means the focused tests, Ethereum coverage, pnpm type-check, and pnpm fix pass without changing existing Lido behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
blockchain
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.