-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add rpc for generating rewards claim proofs (#172)
- Loading branch information
Showing
13 changed files
with
393 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"crypto/tls" | ||
"fmt" | ||
v1 "github.com/Layr-Labs/protocol-apis/gen/protos/eigenlayer/sidecar/v1" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/credentials" | ||
"google.golang.org/grpc/credentials/insecure" | ||
"log" | ||
"strings" | ||
) | ||
|
||
func NewSidecarClient(url string, insecureConn bool) (v1.RewardsClient, error) { | ||
var creds grpc.DialOption | ||
if strings.Contains(url, "localhost:") || strings.Contains(url, "127.0.0.1:") || insecureConn { | ||
creds = grpc.WithTransportCredentials(insecure.NewCredentials()) | ||
} else { | ||
creds = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: false})) | ||
} | ||
|
||
grpcClient, err := grpc.NewClient(url, creds) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return v1.NewRewardsClient(grpcClient), nil | ||
} | ||
|
||
func main() { | ||
earnerAddress := "0x111116fe4f8c2f83e3eb2318f090557b7cd0bf76" | ||
tokens := []string{"0xdeeeeE2b48C121e6728ed95c860e296177849932"} | ||
|
||
client, err := NewSidecarClient("localhost:7100", true) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
res, err := client.GenerateClaimProof(context.Background(), &v1.GenerateClaimProofRequest{ | ||
EarnerAddress: earnerAddress, | ||
Tokens: tokens, | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
fmt.Printf("Proof: %+v\n", res.Proof) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package proofs | ||
|
||
import ( | ||
"fmt" | ||
rewardsCoordinator "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IRewardsCoordinator" | ||
"github.com/Layr-Labs/eigenlayer-rewards-proofs/pkg/claimgen" | ||
"github.com/Layr-Labs/eigenlayer-rewards-proofs/pkg/distribution" | ||
"github.com/Layr-Labs/sidecar/pkg/rewards" | ||
"github.com/Layr-Labs/sidecar/pkg/utils" | ||
gethcommon "github.com/ethereum/go-ethereum/common" | ||
"github.com/wealdtech/go-merkletree/v2" | ||
"go.uber.org/zap" | ||
) | ||
|
||
type RewardsProofsStore struct { | ||
rewardsCalculator *rewards.RewardsCalculator | ||
logger *zap.Logger | ||
rewardsData map[string]*ProofData | ||
} | ||
|
||
type ProofData struct { | ||
SnapshotDate string | ||
AccountTree *merkletree.MerkleTree | ||
TokenTree map[gethcommon.Address]*merkletree.MerkleTree | ||
Distribution *distribution.Distribution | ||
} | ||
|
||
func NewRewardsProofsStore( | ||
rc *rewards.RewardsCalculator, | ||
l *zap.Logger, | ||
) *RewardsProofsStore { | ||
return &RewardsProofsStore{ | ||
rewardsCalculator: rc, | ||
logger: l, | ||
rewardsData: make(map[string]*ProofData), | ||
} | ||
} | ||
|
||
func (rps *RewardsProofsStore) getRewardsDataForSnapshot(snapshot string) (*ProofData, error) { | ||
data, ok := rps.rewardsData[snapshot] | ||
if !ok { | ||
accountTree, tokenTree, distro, err := rps.rewardsCalculator.MerkelizeRewardsForSnapshot(snapshot) | ||
if err != nil { | ||
rps.logger.Sugar().Errorw("Failed to fetch rewards for snapshot", | ||
zap.String("snapshot", snapshot), | ||
zap.Error(err), | ||
) | ||
return nil, err | ||
} | ||
|
||
data = &ProofData{ | ||
SnapshotDate: snapshot, | ||
AccountTree: accountTree, | ||
TokenTree: tokenTree, | ||
Distribution: distro, | ||
} | ||
rps.rewardsData[snapshot] = data | ||
} | ||
return data, nil | ||
} | ||
|
||
func (rps *RewardsProofsStore) GenerateRewardsClaimProof(earnerAddress string, tokenAddresses []string, rootIndex int64) ( | ||
[]byte, | ||
*rewardsCoordinator.IRewardsCoordinatorRewardsMerkleClaim, | ||
error, | ||
) { | ||
distributionRoot, err := rps.rewardsCalculator.FindClaimableDistributionRoot(rootIndex) | ||
if err != nil { | ||
rps.logger.Sugar().Errorf("Failed to find claimable distribution root for root_index", | ||
zap.Int64("rootIndex", rootIndex), | ||
zap.Error(err), | ||
) | ||
return nil, nil, err | ||
} | ||
if distributionRoot == nil { | ||
return nil, nil, fmt.Errorf("No claimable distribution root found for root index %d", rootIndex) | ||
} | ||
snapshotDate := distributionRoot.GetSnapshotDate() | ||
|
||
// Make sure rewards have been generated for this snapshot. | ||
// Any snapshot that is >= the provided date is valid since we'll select only data up | ||
// to the snapshot/cutoff date | ||
generatedSnapshot, err := rps.rewardsCalculator.GetGeneratedRewardsForSnapshotDate(snapshotDate) | ||
if err != nil { | ||
rps.logger.Sugar().Errorf("Failed to get generated rewards for snapshot date", zap.Error(err)) | ||
return nil, nil, err | ||
} | ||
rps.logger.Sugar().Infow("Using snapshot for rewards proof", | ||
zap.String("requestedSnapshot", snapshotDate), | ||
zap.String("snapshot", generatedSnapshot.SnapshotDate), | ||
) | ||
|
||
proofData, err := rps.getRewardsDataForSnapshot(snapshotDate) | ||
if err != nil { | ||
rps.logger.Sugar().Error("Failed to get rewards data for snapshot", | ||
zap.String("snapshot", snapshotDate), | ||
zap.Error(err), | ||
) | ||
return nil, nil, err | ||
} | ||
|
||
tokens := utils.Map(tokenAddresses, func(addr string, i uint64) gethcommon.Address { | ||
return gethcommon.HexToAddress(addr) | ||
}) | ||
earner := gethcommon.HexToAddress(earnerAddress) | ||
|
||
claim, err := claimgen.GetProofForEarner( | ||
proofData.Distribution, | ||
uint32(distributionRoot.RootIndex), | ||
proofData.AccountTree, | ||
proofData.TokenTree, | ||
earner, | ||
tokens, | ||
) | ||
if err != nil { | ||
rps.logger.Sugar().Error("Failed to generate claim proof for earner", zap.Error(err)) | ||
return nil, nil, err | ||
} | ||
|
||
return proofData.AccountTree.Root(), claim, nil | ||
} |
Oops, something went wrong.