11package rewards
22
33import (
4+ "github.com/Layr-Labs/sidecar/internal/config"
45 "github.com/Layr-Labs/sidecar/pkg/rewardsUtils"
56 "go.uber.org/zap"
67)
@@ -11,7 +12,8 @@ const operatorAllocationSnapshotsQuery = `
1112 SELECT *,
1213 ROW_NUMBER() OVER (PARTITION BY operator, avs, strategy, operator_set_id, cast(block_time AS DATE) ORDER BY block_time DESC, log_index DESC) AS rn
1314 FROM operator_allocations oa
14- INNER JOIN blocks b ON oa.effective_block = b.number
15+ -- Backward compatibility: use effective_block if available, fall back to block_number for old records
16+ INNER JOIN blocks b ON COALESCE(oa.effective_block, oa.block_number) = b.number
1517 WHERE b.block_time < TIMESTAMP '{{.cutoffDate}}'
1618 ),
1719 -- Get the latest record for each day
@@ -38,9 +40,12 @@ const operatorAllocationSnapshotsQuery = `
3840 magnitude,
3941 block_time,
4042 LAG(magnitude) OVER (PARTITION BY operator, avs, strategy, operator_set_id ORDER BY block_time, block_number, log_index) as previous_magnitude,
41- -- Allocation (increase): Round UP to next day
42- -- Deallocation (decrease or no change): Round DOWN to current day
43+ -- Backward compatibility: Apply new rounding logic only after Sabine fork
44+ -- Pre-Sabine: Always round down to current day (old behavior)
45+ -- Post-Sabine: Allocation (increase) rounds UP, deallocation rounds DOWN
4346 CASE
47+ {{ if .useSabineRounding }}
48+ -- Post-Sabine fork rounding logic
4449 WHEN LAG(magnitude) OVER (PARTITION BY operator, avs, strategy, operator_set_id ORDER BY block_time, block_number, log_index) IS NULL THEN
4550 -- First allocation: round up to next day
4651 date_trunc('day', block_time) + INTERVAL '1' day
@@ -50,6 +55,15 @@ const operatorAllocationSnapshotsQuery = `
5055 ELSE
5156 -- Decrease or no change: round down to current day
5257 date_trunc('day', block_time)
58+ {{ else }}
59+ -- Pre-Sabine fork rounding logic (backward compatibility)
60+ WHEN LAG(magnitude) OVER (PARTITION BY operator, avs, strategy, operator_set_id ORDER BY block_time, block_number, log_index) IS NULL THEN
61+ -- First allocation: round down to current day (old behavior)
62+ date_trunc('day', block_time)
63+ ELSE
64+ -- All other cases: round down to current day
65+ date_trunc('day', block_time)
66+ {{ end }}
5367 END AS snapshot_time
5468 FROM daily_records
5569 ),
@@ -88,14 +102,33 @@ const operatorAllocationSnapshotsQuery = `
88102`
89103
90104func (r * RewardsCalculator ) GenerateAndInsertOperatorAllocationSnapshots (snapshotDate string ) error {
105+ // Determine if we should use Sabine fork rounding logic based on snapshot date
106+ forks , err := r .globalConfig .GetRewardsSqlForkDates ()
107+ if err != nil {
108+ r .logger .Sugar ().Errorw ("Failed to get rewards fork dates" , "error" , err )
109+ return err
110+ }
111+
112+ useSabineRounding := false
113+ if sabineFork , exists := forks [config .RewardsFork_Sabine ]; exists {
114+ // Use new rounding logic if snapshot date is on or after Sabine fork
115+ useSabineRounding = snapshotDate >= sabineFork .Date
116+ }
117+
91118 query , err := rewardsUtils .RenderQueryTemplate (operatorAllocationSnapshotsQuery , map [string ]interface {}{
92- "cutoffDate" : snapshotDate ,
119+ "cutoffDate" : snapshotDate ,
120+ "useSabineRounding" : useSabineRounding ,
93121 })
94122 if err != nil {
95123 r .logger .Sugar ().Errorw ("Failed to render query template" , "error" , err )
96124 return err
97125 }
98126
127+ r .logger .Sugar ().Debugw ("Generating operator allocation snapshots" ,
128+ zap .String ("snapshotDate" , snapshotDate ),
129+ zap .Bool ("useSabineRounding" , useSabineRounding ),
130+ )
131+
99132 res := r .grm .Exec (query )
100133 if res .Error != nil {
101134 r .logger .Sugar ().Errorw ("Failed to generate operator_allocation_snapshots" ,
0 commit comments