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.
- Protocol: YEARN_MS
- Safe: yChad (Yearn multisig) —
0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52, 6-of-9, nonce 2296 - Contract: Safe MultiSendCallOnly —
0x40A2aCCbd92BCA938b02010E17A5b8929b49130D - Chain: Mainnet (chain id 1)
- Risk: MEDIUM (originally MEDIUM, for a different reason)
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:
- It calls
set_claimable([account], [0])to zero the entry, so the account cannot also claim if the deadline is ever extended. This also lowersunclaimedby the zeroed amount.unclaimedis 318.17 now and becomes 282.62 after the batch. - 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))
-
set_management(address)on0xbCc932e4750C3E465A7E54A06A34F9EdF8f6116b(Funding Distributor)address _management:0xac7D4A37Ba61C2CAc7f64d3e2b5773D85613Fe7b(Executor)- Batch simulation: SUCCESS, gas 46,951
-
set_claimable(address[],uint256[])on0x9564850c7090B13794e6d1164B0826C0aEFf3143(yETH recovery claim)address[] _accounts:0xFC5453ACF7807455d6bC6406a06d6A6Bb26DFf55uint256[] _amounts:0- Batch simulation: SUCCESS, gas 32,179
-
withdraw(uint256,address,address)on0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6(Yearn yETH Recovery Vault)uint256 assets:9,271,996,944,457,152,436(≈ 9.27 WETH)address receiver:0xFC5453ACF7807455d6bC6406a06d6A6Bb26DFf55address owner:0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52(yChad)- Batch simulation: SUCCESS, gas 1,298,960
-
set_claimable(address[],uint256[])on0x9564850c7090B13794e6d1164B0826C0aEFf3143(yETH recovery claim)address[] _accounts:0x1BF44e3b0DfC84046a416c2Cd2040860EC593e53uint256[] _amounts:0- Batch simulation: SUCCESS, gas 32,179
-
withdraw(uint256,address,address)on0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6(Yearn yETH Recovery Vault)uint256 assets:1,741,670,251,884,345,989(≈ 1.74 WETH)address receiver:0x1BF44e3b0DfC84046a416c2Cd2040860EC593e53address owner:0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52(yChad)- Batch simulation: SUCCESS, gas 1,054,282
-
set_claimable(address[],uint256[])on0x9564850c7090B13794e6d1164B0826C0aEFf3143(yETH recovery claim)address[] _accounts:0x55Bc991b2edF3DDb4c520B222bE4F378418ff0fAuint256[] _amounts:0- Batch simulation: SUCCESS, gas 32,179
-
withdraw(uint256,address,address)on0xd7a540ba3626c0aa66e7DB4088971d0CD64695B6(Yearn yETH Recovery Vault)uint256 assets:348,334,050,376,869,197(≈ 0.35 WETH)address receiver:0x55Bc991b2edF3DDb4c520B222bE4F378418ff0fAaddress owner:0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52(yChad)- Batch simulation: SUCCESS, gas 1,037,182
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 |