@@ -28,6 +28,12 @@ type Cache struct {
2828 PodOwnerShares map [string ]PodOwnerShare
2929}
3030
31+ // multiply by a fraction
32+ func FracMul (a * big.Int , x * big.Int , y * big.Int ) * big.Int {
33+ _a := new (big.Int ).Mul (a , x )
34+ return _a .Div (_a , y )
35+ }
36+
3137func keys [A comparable , B any ](coll map [A ]B ) []A {
3238 if len (coll ) == 0 {
3339 return []A {}
@@ -42,8 +48,8 @@ func keys[A comparable, B any](coll map[A]B) []A {
4248}
4349
4450type PodOwnerShare struct {
45- SharesWei uint64
46- ExecutionLayerBalanceWei uint64
51+ SharesWei * big. Int
52+ ExecutionLayerBalanceWei * big. Int
4753 IsEigenpod bool
4854}
4955
@@ -60,8 +66,8 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) (
6066
6167 // default to false
6268 cache .PodOwnerShares [eigenpodAddress ] = PodOwnerShare {
63- SharesWei : 0 ,
64- ExecutionLayerBalanceWei : 0 ,
69+ SharesWei : big . NewInt ( 0 ) ,
70+ ExecutionLayerBalanceWei : big . NewInt ( 0 ) ,
6571 IsEigenpod : false ,
6672 }
6773
@@ -109,8 +115,8 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) (
109115 // Simulate fetching from contracts
110116 // Implement contract fetching logic here
111117 cache .PodOwnerShares [eigenpodAddress ] = PodOwnerShare {
112- SharesWei : podOwnerShares . Uint64 () ,
113- ExecutionLayerBalanceWei : balance . Uint64 () ,
118+ SharesWei : podOwnerShares ,
119+ ExecutionLayerBalanceWei : balance ,
114120 IsEigenpod : true ,
115121 }
116122
@@ -205,7 +211,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri
205211
206212 if verbose {
207213 log .Printf ("%d EigenValidators have been slashed\n " , len (allSlashedValidatorsBelongingToEigenpods ))
208- log .Printf ("%d EigenValidators have been slashed AND were active\n " , len (allActiveSlashedValidatorsBelongingToEigenpods ))
214+ log .Printf ("%d EigenValidators have been slashed + active\n " , len (allActiveSlashedValidatorsBelongingToEigenpods ))
209215 }
210216
211217 slashedEigenpods := utils .Reduce (allActiveSlashedValidatorsBelongingToEigenpods , func (pods map [string ][]ValidatorWithIndex , validator ValidatorWithIndex ) map [string ][]ValidatorWithIndex {
@@ -224,42 +230,75 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri
224230 return nil , err
225231 }
226232
227- totalAssetsWeiByEigenpod := utils .Reduce (keys (slashedEigenpods ), func (allBalances map [string ]uint64 , eigenpod string ) map [string ]uint64 {
233+ totalAssetsWeiByEigenpod := utils .Reduce (keys (slashedEigenpods ), func (allBalances map [string ]* big. Int , eigenpod string ) map [string ]* big. Int {
228234 // total assets of an eigenpod are determined as;
229235 // SUM(
230236 // - native ETH in the pod
231237 // - any active validators and their associated balances
232238 // )
233- allActiveValidatorsForEigenpod := utils .Filter (allValidatorsWithIndices , func (v ValidatorWithIndex ) bool {
234- if allValidatorInfo [v .Index ].Status != 1 {
239+ validatorsForEigenpod := utils .Filter (allValidatorsWithIndices , func (v ValidatorWithIndex ) bool {
240+ withdrawal := executionWithdrawalAddress (v .Validator .WithdrawalCredentials )
241+ return withdrawal != nil && strings .EqualFold (* withdrawal , eigenpod )
242+ })
243+
244+ podValidatorInfo , err := FetchMultipleOnchainValidatorInfo (ctx , eth , eigenpod , validatorsForEigenpod )
245+ if err != nil {
246+ return allBalances
247+ }
248+
249+ allActiveValidatorsForEigenpod := utils .Filter (podValidatorInfo , func (v ValidatorWithOnchainInfo ) bool {
250+ if v .Info .Status != 1 { // ignore any inactive validators
235251 return false
236252 }
237253
238254 withdrawal := executionWithdrawalAddress (v .Validator .WithdrawalCredentials )
239255 return withdrawal != nil && strings .EqualFold (* withdrawal , eigenpod )
240256 })
241257
242- allActiveValidatorBalancesSummedGwei := utils .Reduce (allActiveValidatorsForEigenpod , func (accum phase0.Gwei , validator ValidatorWithIndex ) phase0.Gwei {
258+ allActiveValidatorBalancesSummedGwei := utils .Reduce (allActiveValidatorsForEigenpod , func (accum phase0.Gwei , validator ValidatorWithOnchainInfo ) phase0.Gwei {
243259 return accum + allValidatorBalances [validator .Index ]
244260 }, phase0 .Gwei (0 ))
245- // converting gwei to wei
246- allBalances [eigenpod ] = cache .PodOwnerShares [eigenpod ].ExecutionLayerBalanceWei + (uint64 (allActiveValidatorBalancesSummedGwei ) * params .GWei )
261+ activeValidatorBalancesSum := new (big.Int ).Mul (
262+ new (big.Int ).SetUint64 (uint64 (allActiveValidatorBalancesSummedGwei )),
263+ new (big.Int ).SetUint64 (params .GWei ),
264+ )
265+
266+ if verbose {
267+ log .Printf ("[%s] podOwnerShares(%sETH), anticipated balance = beacon(%s across %d validators) + executionBalance(%sETH)\n " ,
268+ eigenpod ,
269+ IweiToEther (cache .PodOwnerShares [eigenpod ].SharesWei ).String (),
270+ IweiToEther (activeValidatorBalancesSum ).String (),
271+ len (allActiveValidatorsForEigenpod ),
272+ IweiToEther (cache .PodOwnerShares [eigenpod ].ExecutionLayerBalanceWei ).String (),
273+ ) // converting gwei to wei
274+ }
275+
276+ allBalances [eigenpod ] = new (big.Int ).Add (cache .PodOwnerShares [eigenpod ].ExecutionLayerBalanceWei , activeValidatorBalancesSum )
247277 return allBalances
248- }, map [string ]uint64 {})
278+ }, map [string ]* big. Int {})
249279
250280 if verbose {
251281 log .Printf ("%d EigenPods were slashed\n " , len (slashedEigenpods ))
252282 }
253283
254284 unhealthyEigenpods := utils .Filter (keys (slashedEigenpods ), func (eigenpod string ) bool {
255- balance , ok := totalAssetsWeiByEigenpod [eigenpod ]
285+ currentTotalAssets , ok := totalAssetsWeiByEigenpod [eigenpod ]
256286 if ! ok {
257287 return false
258288 }
259- executionBalance := cache .PodOwnerShares [eigenpod ].SharesWei
260- if balance <= uint64 (float64 (executionBalance )* (1 - (tolerance / 100 ))) {
289+ currentShares := cache .PodOwnerShares [eigenpod ].SharesWei
290+
291+ delta := new (big.Int ).Sub (currentShares , currentTotalAssets )
292+ allowableDelta := FracMul (currentShares , big .NewInt (int64 (tolerance )), big .NewInt (100 ))
293+ if delta .Cmp (allowableDelta ) >= 0 {
261294 if verbose {
262- log .Printf ("[%s] %.2f%% deviation (beacon: %d -> execution: %d)\n " , eigenpod , 100 * (float64 (executionBalance )- float64 (balance ))/ float64 (executionBalance ), balance , executionBalance )
295+ log .Printf ("[%s] %sETH drop in assets (max drop allowed: %sETH, current shares: %sETH, anticipated shares: %sETH)\n " ,
296+ eigenpod ,
297+ IweiToEther (delta ).String (),
298+ IweiToEther (allowableDelta ).String (),
299+ IweiToEther (currentShares ).String (),
300+ IweiToEther (currentTotalAssets ).String (),
301+ )
263302 }
264303 return true
265304 }
0 commit comments