waveygist

Safe MultiSendCallOnly - 28/09/2026 18:03 - MEDIUM

Corrected 29/09/2026. The first version was wrong in three ways. It said simulation was skipped, but the batch can be simulated and all 7 calls succeed. It said the prior claimable amounts were not provided, but they are public on-chain, and each payout equals claimable × recovery rate exactly. It described the management change only as a pending handover, without saying who gains control. Pipeline fix: yearn/monitoring#396. Every value below was read at block 26,077,557 (Safe submission, 28/09/2026 17:50 UTC). Risk is unchanged at MEDIUM, but the reason is different: it comes from the management change, not the withdrawals.

Summary

Nominates Executor as Funding Distributor management. Executor is Yearn's on-chain-governance executor: its only operator is the Voting contract, and it is managed by a 2-of-4 Safe. Once Executor accepts, control moves from yChad's 6-of-9 to on-chain governance, with a 2-of-4 admin that can whitelist new operators. The batch also pays three yETH-recovery claimants who missed the 01/06/2026 claim deadline. Each receives exactly claimable × recovery rate (11.362 WETH total) from yChad's vault shares, and their claim entries are zeroed so they cannot be paid twice. MEDIUM

Execution Context

The Safe DELEGATECALLs into MultiSendCallOnly, which sends each inner transaction as a plain CALL from the Safe (msg.sender = yChad). A Tenderly bundle simulation of the seven calls in order from the Safe at block 26,077,557 succeeds for all seven calls.

Analysis

Call 1 — Funding Distributor management → Executor (two-step)

set_management on the Funding Distributor (0xbCc932e4750C3E465A7E54A06A34F9EdF8f6116b) only sets pending_management, which is empty now. Control moves when Executor calls accept_management. Management can approve team funding and sweep any token the distributor holds.

Now After acceptance
Management yChad 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52: Safe 6-of-9 Executor 0xac7D4A37Ba61C2CAc7f64d3e2b5773D85613Fe7b: contract that executes call scripts for whitelisted operators
Who can act 6 of 9 yChad signers Executor's operators. The only active one is Yearn's governance Voting contract 0x543e8871562a8C53E8B6a26835aeEcB3a5A13070 (proposal → vote → on-chain execution).
Admin behind it — Executor's management() is 0xABCDEF0028B6Cc3539C2397aCab017519f8744c8: Safe 2-of-4. The same Safe manages Voting.

This moves the Funding Distributor under on-chain governance. The catch is the admin: the 2-of-4 Safe can whitelist any operator on Executor, itself included, and then act directly. In the worst case, the signing threshold behind the distributor drops from 6-of-9 to 2-of-4. That is the main reason for MEDIUM. Once Executor accepts, reversing this requires an Executor operator, not yChad.

Calls 2–7 — late payouts to three yETH-recovery claimants

The yETH recovery claim contract (0x9564850c7090B13794e6d1164B0826C0aEFf3143) let listed accounts claim() their allocation × recovery_rate until deadline.

  • Deadline: 1780272000 = 01/06/2026, so it has passed and these accounts can no longer claim.
  • Recovery rate: 0.3196079.
  • Shares held: the claim contract holds 0 shares of the yield vault.

The batch therefore does the payout manually, per account:

  1. It calls set_claimable([account], [0]) to zero the entry, so the account cannot also claim if the deadline is ever extended. This also lowers unclaimed by the zeroed amount. unclaimed is 318.17 now and becomes 282.62 after the batch.
  2. It calls withdraw(assets, account, yChad) on the Yearn yETH Recovery Vault (0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6), which sends WETH to the account and burns yChad's shares (price per share 1.0).
Account Claimable now × 0.3196079 Paid (WETH) Match
0xFC5453ACF7807455d6bC6406a06d6A6Bb26DFf55 (EOA with EIP-7702 code) 29.010537425567867493 9.271996944457152436 9.271996944457152436 exact
0x1BF44e3b0DfC84046a416c2Cd2040860EC593e53 (EOA) 5.449396751095157502 1.741670251884345989 1.741670251884345989 exact
0x55Bc991b2edF3DDb4c520B222bE4F378418ff0fA (EOA) 1.089879350219031500 0.348334050376869197 0.348334050376869197 exact
Total 11.362001246718367622

yChad holds 803.17 shares (of 2,445.35 total supply), so the 11.36 withdrawn is 1.4% of its position. The vault has no idle WETH, so each withdrawal pulls from its strategies. The pinned simulation succeeds with the default max_loss = 0, meaning no loss is realized.

This part is routine: each account receives exactly what claim(_exit=True) would have paid it before the deadline, funded by yChad's own shares.

Risk assessment

MEDIUM, driven by call 1. The payouts are exact, simulated, and self-funded, so they are low risk on their own. Once Executor accepts, the Funding Distributor is controlled by on-chain governance, with a 2-of-4 Safe able to add operators. That is a smaller signer set than yChad's 6-of-9 for a contract that can release team funding and sweep tokens. Reviewers should confirm the 2-of-4 Safe is the intended governance admin.

Call Flow

From: 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52 (yChad (Yearn multisig/daddy))

  1. set_management(address) on 0xbCc932e4750C3E465A7E54A06A34F9EdF8f6116b (Funding Distributor)

  2. set_claimable(address[],uint256[]) on 0x9564850c7090B13794e6d1164B0826C0aEFf3143 (yETH recovery claim)

  3. withdraw(uint256,address,address) on 0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6 (Yearn yETH Recovery Vault)

  4. set_claimable(address[],uint256[]) on 0x9564850c7090B13794e6d1164B0826C0aEFf3143 (yETH recovery claim)

  5. withdraw(uint256,address,address) on 0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6 (Yearn yETH Recovery Vault)

  6. set_claimable(address[],uint256[]) on 0x9564850c7090B13794e6d1164B0826C0aEFf3143 (yETH recovery claim)

  7. withdraw(uint256,address,address) on 0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6 (Yearn yETH Recovery Vault)

Reference

Address Label Role
0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52 yChad (Yearn multisig), Safe 6-of-9 Executing Safe; current Funding Distributor management; share owner
0x40A2aCCbd92BCA938b02010E17A5b8929b49130D Safe MultiSendCallOnly Delegatecall target
0xbCc932e4750C3E465A7E54A06A34F9EdF8f6116b Funding Distributor Call 1 target
0xac7D4A37Ba61C2CAc7f64d3e2b5773D85613Fe7b Executor Proposed management
0x543e8871562a8C53E8B6a26835aeEcB3a5A13070 Voting (Yearn governance) Executor's only active operator
0xABCDEF0028B6Cc3539C2397aCab017519f8744c8 Safe 2-of-4 Management of Executor and Voting
0x9564850c7090B13794e6d1164B0826C0aEFf3143 yETH recovery claim Calls 2, 4, 6 target
0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6 Yearn yETH Recovery Vault (claim contract's yield_vault) Calls 3, 5, 7 target
0xFC5453ACF7807455d6bC6406a06d6A6Bb26DFf55 Claimant (EIP-7702 account) Paid 9.27 WETH
0x1BF44e3b0DfC84046a416c2Cd2040860EC593e53 Claimant Paid 1.74 WETH
0x55Bc991b2edF3DDb4c520B222bE4F378418ff0fA Claimant Paid 0.35 WETH