-
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
add missing arg
- Loading branch information
1 parent
16bf7db
commit 309a553
Showing
11 changed files
with
277 additions
and
25 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
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 ( | ||
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, snapshotDate string) ( | ||
[]byte, | ||
*rewardsCoordinator.IRewardsCoordinatorRewardsMerkleClaim, | ||
error, | ||
) { | ||
if snapshotDate == "" { | ||
snapshotDate = "latest" | ||
} | ||
|
||
distributionRoot, err := rps.rewardsCalculator.FindClaimableDistributionRoot(snapshotDate) | ||
if err != nil { | ||
rps.logger.Sugar().Errorf("Failed to find most claimable distribution root", zap.Error(err)) | ||
return nil, nil, err | ||
} | ||
if snapshotDate == "latest" { | ||
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) | ||
rootIndex := distributionRoot.RootIndex | ||
|
||
claim, err := claimgen.GetProofForEarner( | ||
proofData.Distribution, | ||
uint32(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 | ||
} |
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,51 @@ | ||
package rpcServer | ||
|
||
import ( | ||
"context" | ||
"github.com/Layr-Labs/eigenlayer-rewards-proofs/pkg/claimgen" | ||
sidecarV1 "github.com/Layr-Labs/protocol-apis/gen/protos/eigenlayer/sidecar/v1" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
func convertClaimProofToRPCResponse(solidityProof *claimgen.IRewardsCoordinatorRewardsMerkleClaimStrings) *sidecarV1.Proof { | ||
tokenLeaves := make([]*sidecarV1.TokenLeaf, 0) | ||
|
||
for _, l := range solidityProof.TokenLeaves { | ||
tokenLeaves = append(tokenLeaves, &sidecarV1.TokenLeaf{ | ||
Token: l.Token.String(), | ||
CumulativeEarnings: l.CumulativeEarnings, | ||
}) | ||
} | ||
|
||
return &sidecarV1.Proof{ | ||
Root: solidityProof.Root, | ||
RootIndex: solidityProof.RootIndex, | ||
EarnerIndex: solidityProof.EarnerIndex, | ||
EarnerTreeProof: solidityProof.EarnerTreeProof, | ||
EarnerLeaf: &sidecarV1.EarnerLeaf{ | ||
Earner: solidityProof.EarnerLeaf.Earner.String(), | ||
EarnerTokenRoot: solidityProof.EarnerLeaf.EarnerTokenRoot, | ||
}, | ||
LeafIndices: solidityProof.TokenIndices, | ||
TokenTreeProofs: solidityProof.TokenTreeProofs, | ||
TokenLeaves: tokenLeaves, | ||
} | ||
} | ||
|
||
func (rpc *RpcServer) GenerateClaimProof(ctx context.Context, req *sidecarV1.GenerateClaimProofRequest) (*sidecarV1.GenerateClaimProofResponse, error) { | ||
earner := req.GetEarnerAddress() | ||
tokens := req.GetTokens() | ||
snapshotDate := req.GetSnapshot() | ||
|
||
root, claim, err := rpc.rewardsProofs.GenerateRewardsClaimProof(earner, tokens, snapshotDate) | ||
if err != nil { | ||
return nil, status.Errorf(codes.Internal, "Failed to generate claim proof %s", err.Error()) | ||
} | ||
|
||
solidityClaim := claimgen.FormatProofForSolidity(root, claim) | ||
|
||
return &sidecarV1.GenerateClaimProofResponse{ | ||
Proof: convertClaimProofToRPCResponse(solidityClaim), | ||
}, nil | ||
} |
Oops, something went wrong.