1
1
package rewards
2
2
3
3
import (
4
+ "context"
4
5
"encoding/json"
5
6
"errors"
6
7
"fmt"
@@ -19,6 +20,7 @@ import (
19
20
contractrewardscoordinator "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IRewardsCoordinator"
20
21
21
22
"github.com/Layr-Labs/eigenlayer-rewards-proofs/pkg/claimgen"
23
+ "github.com/Layr-Labs/eigenlayer-rewards-proofs/pkg/proofDataFetcher"
22
24
"github.com/Layr-Labs/eigenlayer-rewards-proofs/pkg/proofDataFetcher/httpProofDataFetcher"
23
25
24
26
"github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts"
@@ -35,8 +37,6 @@ import (
35
37
"github.com/urfave/cli/v2"
36
38
)
37
39
38
- const LatestClaimTimestamp = "latest"
39
-
40
40
type ClaimConfig struct {
41
41
Network string
42
42
RPCUrl string
@@ -122,20 +122,11 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error {
122
122
http .DefaultClient ,
123
123
)
124
124
125
- latestSubmittedTimestamp , err := elReader .CurrRewardsCalculationEndTimestamp (& bind.CallOpts {})
126
- if err != nil {
127
- return eigenSdkUtils .WrapError ("failed to get latest submitted timestamp" , err )
128
- }
129
- claimDate := time .Unix (int64 (latestSubmittedTimestamp ), 0 ).UTC ().Format (time .DateOnly )
130
- logger .Debugf ("Latest submitted timestamp: %s" , claimDate )
131
-
132
- rootCount , err := elReader .GetDistributionRootsLength (& bind.CallOpts {})
125
+ claimDate , rootIndex , err := getClaimDistributionRoot (ctx , config .ClaimTimestamp , df , elReader , logger )
133
126
if err != nil {
134
- return eigenSdkUtils .WrapError ("failed to get number of published roots " , err )
127
+ return eigenSdkUtils .WrapError ("failed to get claim distribution root " , err )
135
128
}
136
129
137
- rootIndex := uint32 (rootCount .Uint64 () - 1 )
138
-
139
130
proofData , err := df .FetchClaimAmountsForDate (ctx , claimDate )
140
131
if err != nil {
141
132
return eigenSdkUtils .WrapError ("failed to fetch claim amounts for date" , err )
@@ -264,6 +255,64 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error {
264
255
return nil
265
256
}
266
257
258
+ func getClaimDistributionRoot (
259
+ ctx context.Context ,
260
+ claimTimestamp string ,
261
+ df * httpProofDataFetcher.HttpProofDataFetcher ,
262
+ elReader * elcontracts.ChainReader ,
263
+ logger logging.Logger ,
264
+ ) (string , uint32 , error ) {
265
+ if claimTimestamp == "latest" {
266
+ latestSubmittedTimestamp , err := elReader .CurrRewardsCalculationEndTimestamp (& bind.CallOpts {})
267
+ if err != nil {
268
+ return "" , 0 , eigenSdkUtils .WrapError ("failed to get latest submitted timestamp" , err )
269
+ }
270
+ claimDate := time .Unix (int64 (latestSubmittedTimestamp ), 0 ).UTC ().Format (time .DateOnly )
271
+ logger .Debugf ("Latest submitted timestamp: %s" , claimDate )
272
+
273
+ rootCount , err := elReader .GetDistributionRootsLength (& bind.CallOpts {})
274
+ if err != nil {
275
+ return "" , 0 , eigenSdkUtils .WrapError ("failed to get number of published roots" , err )
276
+ }
277
+
278
+ rootIndex := uint32 (rootCount .Uint64 () - 1 )
279
+ return claimDate , rootIndex , nil
280
+ } else if claimTimestamp == "latest_active" {
281
+ // Get the latest 10 roots
282
+ postedRoots , err := df .FetchPostedRewards (ctx )
283
+ if err != nil {
284
+ return "" , 0 , eigenSdkUtils .WrapError ("failed to fetch posted rewards" , err )
285
+ }
286
+
287
+ ts , rootIndex , err := getLatestActivePostedRoot (postedRoots )
288
+ if err != nil {
289
+ return "" , 0 , eigenSdkUtils .WrapError ("failed to get latest active posted root" , err )
290
+ }
291
+ logger .Debugf ("Latest active posted root timestamp: %s, index: %d" , ts , rootIndex )
292
+
293
+ return ts , rootIndex , nil
294
+ }
295
+ return "" , 0 , errors .New ("invalid claim timestamp" )
296
+ }
297
+
298
+ // getLatestActivePostedRoot returns the latest active posted root by sorting the roots by the latest calculated end
299
+ // timestamp in descending order and checking the latest timestamp which activated before the current time
300
+ func getLatestActivePostedRoot (postedRoots []* proofDataFetcher.SubmittedRewardRoot ) (string , uint32 , error ) {
301
+ // sort by latest calculated end timestamp
302
+ sort .Slice (postedRoots , func (i , j int ) bool {
303
+ return postedRoots [i ].CalcEndTimestamp .After (postedRoots [j ].CalcEndTimestamp )
304
+ })
305
+
306
+ currTime := time .Now ()
307
+ for _ , postedRoot := range postedRoots {
308
+ if postedRoot .ActivatedAt .Before (currTime ) {
309
+ return postedRoot .GetRewardDate (), postedRoot .RootIndex , nil
310
+ }
311
+ // There is no else here because on of last 10 root be
312
+ }
313
+ return "" , 0 , errors .New ("no active posted roots found" )
314
+ }
315
+
267
316
func convertClaimTokenLeaves (
268
317
claimTokenLeaves []contractrewardscoordinator.IRewardsCoordinatorTokenTreeMerkleLeaf ,
269
318
) []rewardscoordinator.IRewardsCoordinatorTokenTreeMerkleLeaf {
@@ -300,9 +349,7 @@ func readAndValidateClaimConfig(cCtx *cli.Context, logger logging.Logger) (*Clai
300
349
logger .Debugf ("Using Rewards Coordinator address: %s" , rewardsCoordinatorAddress )
301
350
302
351
claimTimestamp := cCtx .String (ClaimTimestampFlag .Name )
303
- if claimTimestamp != LatestClaimTimestamp {
304
- return nil , errors .New ("claim-timestamp must be 'latest'" )
305
- }
352
+ logger .Debugf ("Using claim timestamp from user: %s" , claimTimestamp )
306
353
307
354
recipientAddress := gethcommon .HexToAddress (cCtx .String (RecipientAddressFlag .Name ))
308
355
if recipientAddress == utils .ZeroAddress {
@@ -357,6 +404,7 @@ func readAndValidateClaimConfig(cCtx *cli.Context, logger logging.Logger) (*Clai
357
404
Environment : environment ,
358
405
RecipientAddress : recipientAddress ,
359
406
SignerConfig : signerConfig ,
407
+ ClaimTimestamp : claimTimestamp ,
360
408
}, nil
361
409
}
362
410
0 commit comments