Skip to content

Commit

Permalink
feat: add calldata format support for rewards commands (#177)
Browse files Browse the repository at this point in the history
* init

* feat: add calldata generation support to rewards method

* fmt

* fix
  • Loading branch information
shrimalmadhur authored Aug 1, 2024
1 parent 2405b11 commit 0f00b7c
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 59 deletions.
2 changes: 1 addition & 1 deletion pkg/eigenpod/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func status(cCtx *cli.Context, p utils.Prompter) error {
}

if cfg.outputFile != "" {
err := common.WriteToJSON(jsonData, cfg.outputFile)
err := common.WriteToFile(jsonData, cfg.outputFile)
if err != nil {
return err
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/internal/common/constants.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package common

type OutputType string

const (
// MaxAddressLength Magic number 42 is the max length of an address.
// But it's also answer to the life, universe and everything.
MaxAddressLength = 42

OutputType_Calldata OutputType = "calldata"
OutputType_Pretty OutputType = "pretty"
OutputType_Json OutputType = "json"
)
2 changes: 1 addition & 1 deletion pkg/internal/common/fileio.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/gocarina/gocsv"
)

func WriteToJSON(data []byte, filePath string) error {
func WriteToFile(data []byte, filePath string) error {
dir := path.Dir(filePath)
// Ensure the directory exists
err := ensureDir(dir)
Expand Down
2 changes: 1 addition & 1 deletion pkg/internal/common/flags/general.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var (
Name: "output-type",
Aliases: []string{"ot"},
Value: "pretty",
Usage: "Output type to for that respective command. One of 'pretty' or 'json'",
Usage: "Output format of the command. One of 'pretty', 'json' or 'calldata'",
EnvVars: []string{"OUTPUT_TYPE"},
}

Expand Down
15 changes: 14 additions & 1 deletion pkg/internal/common/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"fmt"

"log/slog"
"math/big"
"os"
Expand All @@ -27,7 +26,9 @@ import (
eigensdkTypes "github.com/Layr-Labs/eigensdk-go/types"
eigenSdkUtils "github.com/Layr-Labs/eigensdk-go/utils"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"

Expand Down Expand Up @@ -425,3 +426,15 @@ func GetLogger(cCtx *cli.Context) eigensdkLogger.Logger {
logger := eigensdkLogger.NewTextSLogger(os.Stdout, &eigensdkLogger.SLoggerOptions{Level: logLevel})
return logger
}

func noopSigner(addr common.Address, tx *gethtypes.Transaction) (*gethtypes.Transaction, error) {
return tx, nil
}

func GetNoSendTxOpts(from common.Address) *bind.TransactOpts {
return &bind.TransactOpts{
From: from,
Signer: noopSigner,
NoSend: true,
}
}
54 changes: 28 additions & 26 deletions pkg/rewards/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,29 @@ USAGE:
eigenlayer rewards claim [command options]

OPTIONS:
--network value, -n value Network to use. Currently supports 'holesky' and 'mainnet' (default: "holesky") [$NETWORK]
--eth-rpc-url value, -r value URL of the Ethereum RPC [$ETH_RPC_URL]
--output-file value, -o value Output file to write the data [$OUTPUT_FILE]
--broadcast, -b Use this flag to broadcast the transaction (default: false) [$BROADCAST]
--earner-address value, --ea value Address of the earner [$REWARDS_EARNER_ADDRESS]
--environment value, --env value Environment to use. Currently supports 'preprod' ,'testnet' and 'prod'. If not provided, it will be inferred based on network [$ENVIRONMENT]
--recipient-address value, --ra value Specify the address of the recipient. If this is not provided, the earner address will be used [$RECIPIENT_ADDRESS]
--token-addresses value, -t value Specify the addresses of the tokens to claim. Comma separated list of addresses [$TOKEN_ADDRESSES]
--rewards-coordinator-address value, --rc value Specify the address of the rewards coordinator. If not provided, the address will be used based on provided network [$REWARDS_COORDINATOR_ADDRESS]
--claim-timestamp value, -c value Specify the timestamp. Only 'latest' is supported (default: "latest") [$CLAIM_TIMESTAMP]
--proof-store-base-url value, --psbu value Specify the base URL of the proof store. If not provided, the value based on network will be used [$PROOF_STORE_BASE_URL]
--path-to-key-store value, -k value Path to the key store used to send transactions [$PATH_TO_KEY_STORE]
--earner-address value, --ea value Address of the earner [$REWARDS_EARNER_ADDRESS]
--ecdsa-private-key value, -e value ECDSA private key hex to send transaction [$ECDSA_PRIVATE_KEY]
--environment value, --env value Environment to use. Currently supports 'preprod' ,'testnet' and 'prod'. If not provided, it will be inferred based on network [$ENVIRONMENT]
--eth-rpc-url value, -r value URL of the Ethereum RPC [$ETH_RPC_URL]
--fireblocks-api-key value, --ff value Fireblocks API key [$FIREBLOCKS_API_KEY]
--fireblocks-secret-key value, --fs value Fireblocks secret key. If you are using AWS Secret Manager, this should be the secret name. [$FIREBLOCKS_SECRET_KEY]
--fireblocks-aws-region value, --fa value AWS region if secret is stored in AWS KMS (default: "us-east-1") [$FIREBLOCKS_AWS_REGION]
--fireblocks-base-url value, --fb value Fireblocks base URL [$FIREBLOCKS_BASE_URL]
--fireblocks-vault-account-name value, --fv value Fireblocks vault account name [$FIREBLOCKS_VAULT_ACCOUNT_NAME]
--fireblocks-timeout value, --ft value Fireblocks timeout (default: 30) [$FIREBLOCKS_TIMEOUT]
--fireblocks-secret-key value, --fs value Fireblocks secret key. If you are using AWS Secret Manager, this should be the secret name. [$FIREBLOCKS_SECRET_KEY]
--fireblocks-secret-storage-type value, --fst value Fireblocks secret storage type. Supported values are 'plaintext' and 'aws_secret_manager' [$FIREBLOCKS_SECRET_STORAGE_TYPE]
--fireblocks-aws-region value, --fa value AWS region if secret is stored in AWS KMS (default: "us-east-1") [$FIREBLOCKS_AWS_REGION]
--web3signer-url value, -w value URL of the Web3Signer [$WEB3SIGNER_URL]
--fireblocks-timeout value, --ft value Fireblocks timeout (default: 30) [$FIREBLOCKS_TIMEOUT]
--fireblocks-vault-account-name value, --fv value Fireblocks vault account name [$FIREBLOCKS_VAULT_ACCOUNT_NAME]
--network value, -n value Network to use. Currently supports 'holesky' and 'mainnet' (default: "holesky") [$NETWORK]
--output-file value, -o value Output file to write the data [$OUTPUT_FILE]
--output-type value, --ot value Output format of the command. One of 'pretty', 'json' or 'calldata' (default: "pretty") [$OUTPUT_TYPE]
--path-to-key-store value, -k value Path to the key store used to send transactions [$PATH_TO_KEY_STORE]
--proof-store-base-url value, --psbu value Specify the base URL of the proof store. If not provided, the value based on network will be used [$PROOF_STORE_BASE_URL]
--recipient-address value, --ra value Specify the address of the recipient. If this is not provided, the earner address will be used [$RECIPIENT_ADDRESS]
--rewards-coordinator-address value, --rc value Specify the address of the rewards coordinator. If not provided, the address will be used based on provided network [$REWARDS_COORDINATOR_ADDRESS]
--token-addresses value, -t value Specify the addresses of the tokens to claim. Comma separated list of addresses [$TOKEN_ADDRESSES]
--verbose, -v Enable verbose logging (default: false) [$VERBOSE]
--web3signer-url value, -w value URL of the Web3Signer [$WEB3SIGNER_URL]
--help, -h show help
```
Expand Down Expand Up @@ -76,24 +77,25 @@ DESCRIPTION:


OPTIONS:
--network value, -n value Network to use. Currently supports 'holesky' and 'mainnet' (default: "holesky") [$NETWORK]
--eth-rpc-url value, -r value URL of the Ethereum RPC [$ETH_RPC_URL]
--output-file value, -o value Output file to write the data [$OUTPUT_FILE]
--broadcast, -b Use this flag to broadcast the transaction (default: false) [$BROADCAST]
--earner-address value, --ea value Address of the earner [$REWARDS_EARNER_ADDRESS]
--rewards-coordinator-address value, --rc value Specify the address of the rewards coordinator. If not provided, the address will be used based on provided network [$REWARDS_COORDINATOR_ADDRESS]
--claimer-address value, -a value Address of the claimer [$NODE_OPERATOR_CLAIMER_ADDRESS]
--path-to-key-store value, -k value Path to the key store used to send transactions [$PATH_TO_KEY_STORE]
--earner-address value, --ea value Address of the earner [$REWARDS_EARNER_ADDRESS]
--ecdsa-private-key value, -e value ECDSA private key hex to send transaction [$ECDSA_PRIVATE_KEY]
--eth-rpc-url value, -r value URL of the Ethereum RPC [$ETH_RPC_URL]
--fireblocks-api-key value, --ff value Fireblocks API key [$FIREBLOCKS_API_KEY]
--fireblocks-secret-key value, --fs value Fireblocks secret key. If you are using AWS Secret Manager, this should be the secret name. [$FIREBLOCKS_SECRET_KEY]
--fireblocks-aws-region value, --fa value AWS region if secret is stored in AWS KMS (default: "us-east-1") [$FIREBLOCKS_AWS_REGION]
--fireblocks-base-url value, --fb value Fireblocks base URL [$FIREBLOCKS_BASE_URL]
--fireblocks-vault-account-name value, --fv value Fireblocks vault account name [$FIREBLOCKS_VAULT_ACCOUNT_NAME]
--fireblocks-timeout value, --ft value Fireblocks timeout (default: 30) [$FIREBLOCKS_TIMEOUT]
--fireblocks-secret-key value, --fs value Fireblocks secret key. If you are using AWS Secret Manager, this should be the secret name. [$FIREBLOCKS_SECRET_KEY]
--fireblocks-secret-storage-type value, --fst value Fireblocks secret storage type. Supported values are 'plaintext' and 'aws_secret_manager' [$FIREBLOCKS_SECRET_STORAGE_TYPE]
--fireblocks-aws-region value, --fa value AWS region if secret is stored in AWS KMS (default: "us-east-1") [$FIREBLOCKS_AWS_REGION]
--web3signer-url value, -w value URL of the Web3Signer [$WEB3SIGNER_URL]
--fireblocks-timeout value, --ft value Fireblocks timeout (default: 30) [$FIREBLOCKS_TIMEOUT]
--fireblocks-vault-account-name value, --fv value Fireblocks vault account name [$FIREBLOCKS_VAULT_ACCOUNT_NAME]
--network value, -n value Network to use. Currently supports 'holesky' and 'mainnet' (default: "holesky") [$NETWORK]
--output-file value, -o value Output file to write the data [$OUTPUT_FILE]
--output-type value, --ot value Output format of the command. One of 'pretty', 'json' or 'calldata' (default: "pretty") [$OUTPUT_TYPE]
--path-to-key-store value, -k value Path to the key store used to send transactions [$PATH_TO_KEY_STORE]
--rewards-coordinator-address value, --rc value Specify the address of the rewards coordinator. If not provided, the address will be used based on provided network [$REWARDS_COORDINATOR_ADDRESS]
--verbose, -v Enable verbose logging (default: false) [$VERBOSE]
--web3signer-url value, -w value URL of the Web3Signer [$WEB3SIGNER_URL]
--help, -h show help
```
Expand Down
73 changes: 54 additions & 19 deletions pkg/rewards/claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type ClaimConfig struct {
EarnerAddress gethcommon.Address
RecipientAddress gethcommon.Address
Output string
OutputType string
Broadcast bool
TokenAddresses []gethcommon.Address
RewardsCoordinatorAddress gethcommon.Address
Expand Down Expand Up @@ -72,6 +73,7 @@ func getClaimFlags() []cli.Flag {
&flags.NetworkFlag,
&flags.ETHRpcUrlFlag,
&flags.OutputFileFlag,
&flags.OutputTypeFlag,
&flags.BroadcastFlag,
&EarnerAddressFlag,
&EnvironmentFlag,
Expand Down Expand Up @@ -148,11 +150,23 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error {
config.TokenAddresses,
rootIndex,
)

if err != nil {
return eigenSdkUtils.WrapError("failed to generate claim proof for earner", err)
}

elClaim := rewardscoordinator.IRewardsCoordinatorRewardsMerkleClaim{
RootIndex: claim.RootIndex,
EarnerIndex: claim.EarnerIndex,
EarnerTreeProof: claim.EarnerTreeProof,
EarnerLeaf: rewardscoordinator.IRewardsCoordinatorEarnerTreeMerkleLeaf{
Earner: claim.EarnerLeaf.Earner,
EarnerTokenRoot: claim.EarnerLeaf.EarnerTokenRoot,
},
TokenIndices: claim.TokenIndices,
TokenTreeProofs: claim.TokenTreeProofs,
TokenLeaves: convertClaimTokenLeaves(claim.TokenLeaves),
}

if config.Broadcast {
if config.SignerConfig == nil {
return errors.New("signer is required for broadcasting")
Expand Down Expand Up @@ -185,18 +199,6 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error {
return eigenSdkUtils.WrapError("failed to create new writer from config", err)
}

elClaim := rewardscoordinator.IRewardsCoordinatorRewardsMerkleClaim{
RootIndex: claim.RootIndex,
EarnerIndex: claim.EarnerIndex,
EarnerTreeProof: claim.EarnerTreeProof,
EarnerLeaf: rewardscoordinator.IRewardsCoordinatorEarnerTreeMerkleLeaf{
Earner: claim.EarnerLeaf.Earner,
EarnerTokenRoot: claim.EarnerLeaf.EarnerTokenRoot,
},
TokenIndices: claim.TokenIndices,
TokenTreeProofs: claim.TokenTreeProofs,
TokenLeaves: convertClaimTokenLeaves(claim.TokenLeaves),
}
receipt, err := eLWriter.ProcessClaim(ctx, elClaim, config.RecipientAddress)
if err != nil {
return eigenSdkUtils.WrapError("failed to process claim", err)
Expand All @@ -205,20 +207,51 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error {
logger.Infof("Claim transaction submitted successfully")
common.PrintTransactionInfo(receipt.TxHash.String(), config.ChainID)
} else {
solidityClaim := claimgen.FormatProofForSolidity(accounts.Root(), claim)
if !common.IsEmptyString(config.Output) {
jsonData, err := json.MarshalIndent(solidityClaim, "", " ")
if config.OutputType == string(common.OutputType_Calldata) {
noSendTxOpts := common.GetNoSendTxOpts(config.EarnerAddress)
_, _, contractBindings, err := elcontracts.BuildClients(elcontracts.Config{
RewardsCoordinatorAddress: config.RewardsCoordinatorAddress,
}, ethClient, nil, logger, nil)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return err
}

err = common.WriteToJSON(jsonData, config.Output)
unsignedTx, err := contractBindings.RewardsCoordinator.ProcessClaim(noSendTxOpts, elClaim, config.RecipientAddress)
if err != nil {
return err
}
logger.Infof("Claim written to file: %s", config.Output)

calldataHex := gethcommon.Bytes2Hex(unsignedTx.Data())

if !common.IsEmptyString(config.Output) {
err = common.WriteToFile([]byte(calldataHex), config.Output)
if err != nil {
return err
}
logger.Infof("Call data written to file: %s", config.Output)
} else {
fmt.Println(calldataHex)
}
} else if config.OutputType == string(common.OutputType_Json) {
solidityClaim := claimgen.FormatProofForSolidity(accounts.Root(), claim)
jsonData, err := json.MarshalIndent(solidityClaim, "", " ")
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return err
}
if !common.IsEmptyString(config.Output) {
err = common.WriteToFile(jsonData, config.Output)
if err != nil {
return err
}
logger.Infof("Claim written to file: %s", config.Output)
} else {
fmt.Println(string(jsonData))
fmt.Println()
fmt.Println("To write to a file, use the --output flag")
}
} else {
solidityClaim := claimgen.FormatProofForSolidity(accounts.Root(), claim)
fmt.Println("------- Claim generated -------")
common.PrettyPrintStruct(*solidityClaim)
fmt.Println("-------------------------------")
Expand Down Expand Up @@ -249,6 +282,7 @@ func readAndValidateClaimConfig(cCtx *cli.Context, logger logging.Logger) (*Clai
rpcUrl := cCtx.String(flags.ETHRpcUrlFlag.Name)
earnerAddress := gethcommon.HexToAddress(cCtx.String(EarnerAddressFlag.Name))
output := cCtx.String(flags.OutputFileFlag.Name)
outputType := cCtx.String(flags.OutputTypeFlag.Name)
broadcast := cCtx.Bool(flags.BroadcastFlag.Name)
tokenAddresses := cCtx.String(TokenAddressesFlag.Name)
tokenAddressArray := stringToAddressArray(strings.Split(tokenAddresses, ","))
Expand Down Expand Up @@ -311,6 +345,7 @@ func readAndValidateClaimConfig(cCtx *cli.Context, logger logging.Logger) (*Clai
RPCUrl: rpcUrl,
EarnerAddress: earnerAddress,
Output: output,
OutputType: outputType,
Broadcast: broadcast,
TokenAddresses: tokenAddressArray,
RewardsCoordinatorAddress: gethcommon.HexToAddress(rewardsCoordinatorAddress),
Expand Down
Loading

0 comments on commit 0f00b7c

Please sign in to comment.