feat: #2391 add ether.fi liquid restaking protocol integration - #2423
feat: #2391 add ether.fi liquid restaking protocol integration#2423zkasuran wants to merge 3 commits into
Conversation
Adds ether.fi as a first-class protocol: stake ETH for eETH via the Liquidity Pool, wrap/unwrap between eETH and weETH, and read pool accounting, exchange rates, and balances. Mainnet only; the withdrawal queue and L2 weETH are deferred. Three contracts, verified on mainnet before filing: - liquidityPool 0x308861A430be4cce5502d0A12724771Fc6DaF216 - weeth 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee - eeth 0x35fA164735182de50811E8e2E824cFb9B6118ac2 weETH.eETH() returns the eETH address, and weETH.getRate() equals LiquidityPool.amountForShare(1e18), so the set is coherent on-chain. protocols/index.ts and lib/types/integration.ts are regenerated by pnpm discover-plugins. Verified: 18-case unit test passes, tsgo and biome clean, seed-workflow baseline unchanged.
Resolve the generated lib/types/integration.ts by taking upstream then re-running discover-plugins.
… surface Name every ABI output so the testData field expectations resolve through structureAbiOutputs, and key the registry overrides to those names rather than "result". Fixes a silent fixture bug found while doing so: the testData bound amount-for-share, shares-for-amount, get-weeth-by-eeth and get-eeth-by-weeth by their raw ABI parameter names, but the overrides rename those inputs. An unmatched binding key is dropped and the encoder falls back to a type-derived default, so each 1e18 fixture was silently encoding 1 wei. The goldens now carry 0de0b6b3a7640000 as intended, and a unit case pins every binding key to a declared input name. Adds what a new protocol ships beyond the definition: - docs/plugins/ether-fi.md with the "Why no testnet entry" section, its _meta.ts key and an overview.md row - tests/integration/protocol-ether-fi-onchain.test.ts, 12 cases: every read decoded against deployed bytecode, the three writes simulated, plus a cross-check that amountForShare, getEETHByWeETH and getRate agree - tests/unit/__goldens__/protocol-calldata/ether-fi.json - public/protocols/ether-fi.png from the Optimism token list - chain-exclusion, EIP-55 and expectation-field unit cases
About the
|
|
@suisuss, this is the ether.fi PR for #2391. Everything in your acceptance comment is in it:
Two things I found while building it that you did not ask for, both real: The ABI outputs were all declared The second was silent. The overrides rename the raw ABI parameters for readability, but the testData still bound the old names. An unmatched binding key is dropped rather than rejected. The encoder then falls back to a type-derived default, so On verification, the cross-check is the one worth a look: 22 unit, 525 calldata goldens, 12 on-chain, tsgo and biome clean. Rebased on current staging. Ready for the CI approve-run when you have a moment. On your question about the referral-taking deposit variant: I stayed on the no-argument |
Issue
Closes #2391
What this changes
Adds ether.fi as a new ABI-driven protocol. Depositing ETH into the Liquidity Pool mints eETH, a rebasing receipt earning staking plus EigenLayer restaking rewards; eETH wraps into weETH, the non-rebasing form most DeFi integrations use.
13 actions across three mainnet contracts:
stake,wrapandunwrapas writes, plus ten reads covering pool accounting (getTotalPooledEther,amountForShare,sharesForAmount), the wrapper rate (getRate,getWeETHByeETH,getEETHByWeETH), balances and supply.Contracts, verified on-chain before the addresses were written down: Liquidity Pool
0x308861A430be4cce5502d0A12724771Fc6DaF216, eETH0x35fA164735182de50811E8e2E824cFb9B6118ac2, weETH0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee. The date and the derivation are in a comment on the definition perspecs/protocol-coverage-methodology.md:303-304.Beyond the definition, ABIs and unit test:
docs/plugins/ether-fi.md, its_meta.tskey and anoverview.mdrowtests/integration/protocol-ether-fi-onchain.test.ts, 12 casestests/unit/__goldens__/protocol-calldata/ether-fi.jsonpublic/protocols/ether-fi.png, the weETH mark from the Optimism token list rendered to 256x256wrapandunwrapstayskippedwith a reason, as planned.lib/test-data/chain-test-data.tsis untouched, so no eETH entry was added to the shared token registry. No coverage runner, so nothing to register in a shard list.Two encoding fixes worth reviewing closely
Unnamed ABI outputs. Every output was declared
"name": "", sostructureAbiOutputsreturns the bare scalar and afield:expectation cannot resolve against it. All 13 are now named, with the overrides keyed to those names instead ofresult.Bindings keyed to renamed inputs. This one was silent and is the reason the goldens changed shape. The overrides rename the raw ABI parameters for readability (
_sharetoshares,_amounttoethAmount,_eETHAmountand_weETHAmounttoamount), but the testData still bound the old names. An unmatched binding key is dropped rather than rejected, then the encoder falls back to a type-derived default, so all four conversion reads were encoding 1 wei where the fixture said 1 ETH. The goldens now carry0de0b6b3a7640000.Because nothing errors when that happens, there is now a unit case asserting every binding key names a declared input. Reverting one key back to
_sharefails it with the offending key and the valid set.Scope
One change. The definition, its three ABIs, the golden keyed off its testData, the docs page describing its actions and the logo it points at cannot ship independently.
How it was verified
vitest run tests/unit/protocol-ether-fi.test.ts: 22 passedvitest run tests/unit/protocol-calldata.test.ts: 525 passed, golden matches withoutUPDATE_GOLDENSvitest run tests/integration/protocol-ether-fi-onchain.test.ts: 12 passed against live mainnet. Every read decoded to its declared type, pool TVL and share count non-zero,getRateat or above 1e18, the three writes accepted by deployed bytecodeamountForShare(1e18),getEETHByWeETH(1e18)andgetRate()are asserted byte-identical, so a wrong contract address fails even though each read on its own would return a plausible non-zero numbertsgo --noEmit: clean apart from the pre-existing@workflow/buildersresolution miss intests/unit/workflow-directive-detection.test.tsbiome checkon every touched file: cleanScreenshots
Nothing renders beyond the plugin icon.
stagingpnpm checkandpnpm type-checkpass.envfiles, or credentials committedAI assistance (Claude, Anthropic) was used in developing this change. The design, review and verification were done by the author. Verified locally before submitting: the unit suite (22 cases), the calldata goldens (525 cases), the on-chain integration suite (12 cases) against deployed mainnet bytecode, tsgo and biome.