feat(protocols): #2402 add Euler v2 vaults (ERC-4626 reads and deposit/withdraw) - #2420
feat(protocols): #2402 add Euler v2 vaults (ERC-4626 reads and deposit/withdraw)#2420walkonwayvs wants to merge 2 commits into
Conversation
About the
|
suisuss
left a comment
There was a problem hiding this comment.
What this changes
protocols/euler-v2.ts defines Euler V2 as one userSpecifiedAddress vault contract with a 29-function inline EVK ABI, registry fallback addresses for chain 1 and 8453, erc4626AbiOverrides({ decimals: 6 }) plus eleven hand-written overrides for the Euler-specific reads, and a chain-1 ProtocolTestData block. Plus the docs page and its _meta.ts key, a real 460x460 logo, the golden, a 218-line shape-lock test, and both regenerated barrels.
Everything on the artefact checklist is present, which is the first time that has happened on one of these. I verified both declared vaults on chain: mainnet 0x797DD80692c3b2dAdabCe8e30C07fDE5307D48a9 is EVK Vault eUSDC-2, decimals() 6, asset USDC, 2,083,665.61 assets, interestRate() decoding to about 8.95% APR at 1e27 per-second scaling, which confirms the units in your description; Base 0x07954BEB7e137101A7cbb3e47864C684aEC50524 is EVK Vault eUSDC-100, decimals 6, Base USDC. No coverage runner, correctly, so there is no shard registration to do.
The write asymmetry is documented accurately in the Technical Notes, including that a self-withdrawal can revert while the account has an open borrow. That is the thing I most expected to be got wrong.
Does it match the description
Matches.
Blocking
protocols/euler-v2.tsinline ABI, the four write entries - the first parameter is namedamount, whileerc4626AbiOverrideskeys its input overrides byassetsandshares(lib/web3/standards/erc4626.ts:375-407) andderiveActionlooks overrides up by the ABI parameter's own name (lib/abi/protocol-derive.ts:230).protocols/yearn-v3.tsworks only because its inline ABI names those paramsassetsandshares. -> Two things follow, and the second is the one that bites. The derived input is{ name: "amount", label: "Amount" }, so the deposit form renders "Amount (uint256)" rather than "Asset Amount (wei)", anddocs/plugins/euler-v2.mddocuments a config key namedassetsthat does not exist - an MCP or REST caller following the docs and sending{"assets": "10000000"}has it silently defaulted. AndbuildActionWorkflowmaps bindings by input name (lib/test-data/build-workflow.ts:372) with no validation of unknown keys, soassets: amount("USDC", "10")at:97binds nothing andamountfalls through to the uint default of"1". The golden records that:vault-depositis0x6e553f65followed by...0001and the receiver - one wei, where yearn's equivalent golden carries the real amount. I checkedpreviewDeposit(1)on the declared mainnet vault and it returns 0 shares, so EVK would revertE_ZeroShares; therequiredTokens: 1000 USDCand the fabricated approvals at:71-78are funding a transaction that never spends them. -> Rename the four ABI params toassets/shares. Calldata is positional so the wire format does not change, then regenerate the golden.
Mechanical - actionable as-is
-
docs/plugins/euler-v2.md:10- "Each vault is a separate contract--you must provide the vault address" uses a double dash. Single dash. -
protocols/euler-v2.ts:497-504describesunitOfAccountas "the address of the asset the vault denominates risk calculations in", but both declared vaults return0x0000000000000000000000000000000000000348, which is decimal 840 - the ISO-4217 code for USD, an EVK convention for USD-denominated markets, not a token. A workflow piping that into a token-balance step gets a non-contract address and a confusing downstream failure. A help tip rather than a code change. -
:123-126-writeExpectationscoversvault-depositandvault-mintonly. The two actions whose EVC semantics are non-obvious, withdraw and redeem, have no post-condition at all. -
:158-166- the source comment says only that deposit passesCHECKACCOUNT_NONE, omitting mint and the withdraw/redeem side that the docs page covers properly. Worth bringing into line, since the comment is what the next person editing the file reads. -
decimals: 6is right for both declared vaults, but this is auserSpecifiedAddressprotocol - a user can point it at eWETH (18) or eWBTC (8). Your comment concedes this and offersget-vault-decimalsas the escape hatch, which is the honest framing. Worth knowing: I could not find any consumer ofProtocolActionOutput.decimals-buildOutputFieldsFromActionandoutputToAbiParameterboth drop it - so today it appears to be documentation-grade metadata repo-wide. Mark that UNSURE; I greppedlib/,plugins/andcomponents/and found nothing, but a dynamic lookup could exist.
With the team
Nothing.
Verdict
Changes requested on the ABI parameter names - the four write bindings are silently dropped, so the golden froze a one-wei deposit and the docs name an input key that does not exist.
Worth saying that the shape-lock test is the most thorough one any of the protocol PRs has shipped, and it still could not catch this: it asserts counts, casing, address shape and registry round-trip, but never an input name or encoded calldata. One assertion that vault-deposit's first input is named assets would have.
…es so overrides bind
|
Fixed, and thank you for catching it. The four write parameters are now named You are right about where it came from: Euler's own EVault source names that parameter Golden regenerated. On your closing point, that the shape-lock test could not catch this: agreed, and I have added the assertion. Also in this push:
On |
Issue
Closes #2402. Accepted with amendments; this implements the amended scope.
What this changes
Adds
euler-v2as a protocol: 18 standard ERC-4626 actions plus 11 Euler-specific reads (cash,totalBorrows,interestRate,interestAccumulator,accumulatedFees,debtOf,oracle,unitOfAccount,EVC,creator,decimals), across Ethereum and Base.As triage noted, the capability already exists: an Euler EVault is reachable today through the
morphovault entry, which isuserSpecifiedAddresswith an empty address map. What is missing is identity and discoverability - no Euler name, icon, docs page or typed actions, and a position recorded under integration typemorphoand labelled "MetaMorpho Vault". This closes that gap the same way the other 26 entries close it, and adds the Euler-specific reads that a generic ERC-4626 entry cannot express.erc4626AbiOverrides({ decimals: 6 })is passed explicitly. The helper defaults to 18, which is wrong for the USDC markets this is most used for. Vault decimals follow the underlying asset, soget-vault-decimalsis exposed for non-USDC markets.Scope
protocols/euler-v2.tsdocs/plugins/euler-v2.mdand thedocs/plugins/_meta.tsnav keypublic/protocols/euler-v2.pngtests/unit/protocol-euler-v2.test.tstests/unit/__goldens__/protocol-calldata/euler-v2.jsonprotocols/index.tsandlib/types/integration.ts, regeneratedNo coverage runner, per triage: neither chain has a funded persistent test wallet, and an unregistered suite would fail
scripts/protocol-coverage-completeness.ts.How it was verified
pnpm type-checkclean,pnpm fixclean, 19 shape-lock tests and 538 calldata tests passing. Rebased onstagingatcaa60d103.Test vault is
0x797DD80692c3b2dAdabCe8e30C07fDE5307D48a9(eUSDC-2, mainnet), verified byeth_callon 2026-09-11: asset USDC, decimals 6, totalAssets ~2.036M, maxDeposit ~72.96M of headroom. Headroom is the reason this vault and not the largest by TVL: eUSDC-64 holds ~14.4M and is at its supply cap, somaxDepositreturns 0 and the deposit leg reverts.The write path is verified by reading the vault kit source, not by execution.
callThroughEVC(Dispatch.sol) routes a non-EVC caller through the connector and re-enters, so a direct wallet call works. Per triage,depositandmintpassCHECKACCOUNT_NONEbutwithdrawandredeemcheck the share owner; the docs page states that asymmetry rather than implying all four behave alike.Screenshots
Not applicable.