@@ -80,5 +80,171 @@ func (sp *SlashingProcessor) Process(blockNumber uint64, models map[string]types
8080 precommitDelegations = append (precommitDelegations , delegation )
8181 }
8282 stakerSharesModel .PrecommitDelegatedStakers [blockNumber ] = precommitDelegations
83+
84+ // Also handle slashing adjustments for queued withdrawals
85+ err := sp .processQueuedWithdrawalSlashing (blockNumber , models )
86+ if err != nil {
87+ sp .logger .Sugar ().Errorw ("Failed to process queued withdrawal slashing" ,
88+ zap .Error (err ),
89+ zap .Uint64 ("blockNumber" , blockNumber ),
90+ )
91+ return err
92+ }
93+
94+ return nil
95+ }
96+
97+ // SlashingEvent represents a slashing event from the database
98+ type SlashingEvent struct {
99+ Operator string
100+ Strategy string
101+ WadSlashed string
102+ TransactionHash string
103+ LogIndex uint64
104+ }
105+
106+ // processQueuedWithdrawalSlashing creates adjustment records for queued withdrawals
107+ // when an operator is slashed, so that the effective withdrawal amount is reduced.
108+ func (sp * SlashingProcessor ) processQueuedWithdrawalSlashing (blockNumber uint64 , models map [string ]types.IEigenStateModel ) error {
109+ // Query slashed_operator_shares table directly for this block's slashing events
110+ var slashingEvents []SlashingEvent
111+ err := sp .grm .Table ("slashed_operator_shares" ).
112+ Where ("block_number = ?" , blockNumber ).
113+ Find (& slashingEvents ).Error
114+
115+ if err != nil {
116+ sp .logger .Sugar ().Errorw ("Failed to query slashing events" ,
117+ zap .Error (err ),
118+ zap .Uint64 ("blockNumber" , blockNumber ),
119+ )
120+ return err
121+ }
122+
123+ if len (slashingEvents ) == 0 {
124+ sp .logger .Sugar ().Debug ("No slashing events found for block number" , zap .Uint64 ("blockNumber" , blockNumber ))
125+ return nil
126+ }
127+
128+ // For each slashing event, find active queued withdrawals and create adjustment records
129+ for i := range slashingEvents {
130+ slashEvent := & slashingEvents [i ]
131+ err := sp .createSlashingAdjustments (slashEvent , blockNumber )
132+ if err != nil {
133+ sp .logger .Sugar ().Errorw ("Failed to create slashing adjustments" ,
134+ zap .Error (err ),
135+ zap .Uint64 ("blockNumber" , blockNumber ),
136+ zap .String ("operator" , slashEvent .Operator ),
137+ zap .String ("strategy" , slashEvent .Strategy ),
138+ )
139+ return err
140+ }
141+ }
142+
143+ return nil
144+ }
145+
146+ func (sp * SlashingProcessor ) createSlashingAdjustments (slashEvent * SlashingEvent , blockNumber uint64 ) error {
147+ // Find all active queued withdrawals for this operator/strategy
148+ query := `
149+ SELECT
150+ qsw.staker,
151+ qsw.strategy,
152+ qsw.operator,
153+ qsw.block_number as withdrawal_block_number,
154+ ? as slash_block_number,
155+ -- Calculate cumulative slash multiplier: previous multipliers * (1 - current_slash)
156+ COALESCE(
157+ (SELECT slash_multiplier
158+ FROM queued_withdrawal_slashing_adjustments adj
159+ WHERE adj.staker = qsw.staker
160+ AND adj.strategy = qsw.strategy
161+ AND adj.operator = qsw.operator
162+ AND adj.withdrawal_block_number = qsw.block_number
163+ ORDER BY adj.slash_block_number DESC
164+ LIMIT 1),
165+ 1
166+ ) * (1 - LEAST(? / 1e18, 0)) as slash_multiplier,
167+ ? as block_number,
168+ ? as transaction_hash,
169+ ? as log_index
170+ FROM queued_slashing_withdrawals qsw
171+ INNER JOIN blocks b_queued ON qsw.block_number = b_queued.number
172+ WHERE qsw.operator = ?
173+ AND qsw.strategy = ?
174+ -- Withdrawal was queued before this slash
175+ AND qsw.block_number < ?
176+ -- Still within 14-day window (not yet completable)
177+ AND DATE(b_queued.block_time) + INTERVAL '14 days' > (
178+ SELECT block_time FROM blocks WHERE number = ?
179+ )
180+ -- Backwards compatibility: only process records with valid data
181+ AND qsw.staker IS NOT NULL
182+ AND qsw.strategy IS NOT NULL
183+ AND qsw.operator IS NOT NULL
184+ AND qsw.shares_to_withdraw IS NOT NULL
185+ AND b_queued.block_time IS NOT NULL
186+ `
187+
188+ type AdjustmentRecord struct {
189+ Staker string
190+ Strategy string
191+ Operator string
192+ WithdrawalBlockNumber uint64
193+ SlashBlockNumber uint64
194+ SlashMultiplier string
195+ BlockNumber uint64
196+ TransactionHash string
197+ LogIndex uint64
198+ }
199+
200+ var adjustments []AdjustmentRecord
201+ err := sp .grm .Raw (query ,
202+ blockNumber , // slash_block_number
203+ slashEvent .WadSlashed , // slash percentage for calculation
204+ blockNumber , // block_number for record
205+ slashEvent .TransactionHash , // transaction_hash for record
206+ slashEvent .LogIndex , // log_index for record
207+ slashEvent .Operator , // operator filter
208+ slashEvent .Strategy , // strategy filter
209+ blockNumber , // queued before slash
210+ blockNumber , // current block for 14-day check
211+ ).Scan (& adjustments ).Error
212+
213+ if err != nil {
214+ return fmt .Errorf ("failed to find active withdrawals for slashing: %w" , err )
215+ }
216+
217+ if len (adjustments ) == 0 {
218+ sp .logger .Sugar ().Debugw ("No active queued withdrawals found for slashing event" ,
219+ zap .String ("operator" , slashEvent .Operator ),
220+ zap .String ("strategy" , slashEvent .Strategy ),
221+ zap .Uint64 ("blockNumber" , blockNumber ),
222+ )
223+ return nil
224+ }
225+
226+ // Insert adjustment records
227+ for _ , adj := range adjustments {
228+ err := sp .grm .Table ("queued_withdrawal_slashing_adjustments" ).Create (& adj ).Error
229+ if err != nil {
230+ sp .logger .Sugar ().Errorw ("Failed to create slashing adjustment record" ,
231+ zap .Error (err ),
232+ zap .String ("staker" , adj .Staker ),
233+ zap .String ("strategy" , adj .Strategy ),
234+ zap .Uint64 ("withdrawalBlockNumber" , adj .WithdrawalBlockNumber ),
235+ )
236+ return err
237+ }
238+
239+ sp .logger .Sugar ().Infow ("Created queued withdrawal slashing adjustment" ,
240+ zap .String ("staker" , adj .Staker ),
241+ zap .String ("strategy" , adj .Strategy ),
242+ zap .String ("operator" , adj .Operator ),
243+ zap .Uint64 ("withdrawalBlock" , adj .WithdrawalBlockNumber ),
244+ zap .Uint64 ("slashBlock" , adj .SlashBlockNumber ),
245+ zap .String ("multiplier" , adj .SlashMultiplier ),
246+ )
247+ }
248+
83249 return nil
84250}
0 commit comments