From d71a3664ec98fad7b793d6fe801206540ef3d6bc Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 22 Apr 2026 11:22:50 +0200 Subject: [PATCH] fix: decode BalancesSnapped event via strategy interface in snapBalances task When snapBalances runs with --consol, the tx is sent to ConsolidationController but the BalancesSnapped event is emitted by the target strategy. The receipt's decoded events are bound to the controller's ABI so the event lookup failed and the task threw even though the tx succeeded. Co-Authored-By: Claude Opus 4.7 (1M context) --- contracts/tasks/validatorCompound.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/contracts/tasks/validatorCompound.js b/contracts/tasks/validatorCompound.js index 7f102bb8be..0f754f0c16 100644 --- a/contracts/tasks/validatorCompound.js +++ b/contracts/tasks/validatorCompound.js @@ -50,17 +50,28 @@ async function snapBalances({ consol = false }) { await logTxDetails(tx, "snapBalances"); const receipt = await tx.wait(); - const event = receipt.events.find( - (event) => event.event === "BalancesSnapped" + + // When called via ConsolidationController the BalancesSnapped event is emitted + // by the target strategy, so decode logs against the strategy's interface. + const strategy = await resolveContract( + "CompoundingStakingSSVStrategyProxy", + "CompoundingStakingSSVStrategy" ); - if (!event) { + const eventTopic = strategy.interface.getEventTopic("BalancesSnapped"); + const rawLog = receipt.logs.find( + (l) => + l.address.toLowerCase() === strategy.address.toLowerCase() && + l.topics[0] === eventTopic + ); + if (!rawLog) { throw new Error("BalancesSnapped event not found in transaction receipt"); } + const parsed = strategy.interface.parseLog(rawLog); console.log( `Balances snapped successfully. Beacon block root ${ - event.args.blockRoot + parsed.args.blockRoot }, block ${receipt.blockNumber}, ETH balance ${formatUnits( - event.args.ethBalance + parsed.args.ethBalance )}` ); }