Skip to content

Commit

Permalink
feat: add calldata generation support to rewards method
Browse files Browse the repository at this point in the history
  • Loading branch information
shrimalmadhur committed Aug 1, 2024
1 parent 95fe596 commit 98c880a
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 52 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: 15 additions & 0 deletions pkg/internal/common/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"errors"
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi/bind"

"log/slog"
"math/big"
"os"
Expand All @@ -28,6 +30,7 @@ import (
eigenSdkUtils "github.com/Layr-Labs/eigensdk-go/utils"

"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 +428,15 @@ func GetLogger(cCtx *cli.Context) eigensdkLogger.Logger {
logger := eigensdkLogger.NewTextSLogger(os.Stdout, &eigensdkLogger.SLoggerOptions{Level: logLevel})
return logger
}

func oopSigner(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: oopSigner,
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
53 changes: 40 additions & 13 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 @@ -205,28 +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 {
_, _, contractBindings, err := elcontracts.BuildClients(elcontracts.Config{
RewardsCoordinatorAddress: config.RewardsCoordinatorAddress,
}, ethClient, nil, logger, nil)
if err != nil {
return err
}
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 {
return err
}

contractBindings.RewardsCoordinator.ProcessClaim(&bind.TransactOpts{}, elClaim, config.RecipientAddress)
solidityClaim := claimgen.FormatProofForSolidity(accounts.Root(), claim)
if !common.IsEmptyString(config.Output) {
jsonData, err := json.MarshalIndent(solidityClaim, "", " ")
unsignedTx, err := contractBindings.RewardsCoordinator.ProcessClaim(noSendTxOpts, elClaim, config.RecipientAddress)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return err
}

err = common.WriteToJSON(jsonData, 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
}
logger.Infof("Claim written to file: %s", config.Output)
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 @@ -257,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 @@ -319,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
56 changes: 46 additions & 10 deletions pkg/rewards/setclaimer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type SetClaimerConfig struct {
ChainID *big.Int
SignerConfig *types.SignerConfig
EarnerAddress gethcommon.Address
Output string
OutputType string
}

func SetClaimerCmd(p utils.Prompter) *cli.Command {
Expand All @@ -57,6 +59,7 @@ func getSetClaimerFlags() []cli.Flag {
&flags.NetworkFlag,
&flags.ETHRpcUrlFlag,
&flags.OutputFileFlag,
&flags.OutputTypeFlag,
&flags.BroadcastFlag,
&EarnerAddressFlag,
&RewardsCoordinatorAddressFlag,
Expand All @@ -81,20 +84,47 @@ func SetClaimer(cCtx *cli.Context, p utils.Prompter) error {
return fmt.Errorf("set claimer currently unsupported on mainnet")
}

if !config.Broadcast {
fmt.Printf(
"Claimer address %s will be set for earner %s\n",
config.ClaimerAddress.String(),
config.EarnerAddress.String(),
)
return nil
}

ethClient, err := ethclient.Dial(config.RPCUrl)
if err != nil {
return err
}

if !config.Broadcast {
if config.OutputType == string(common.OutputType_Calldata) {
_, _, contractBindings, err := elcontracts.BuildClients(elcontracts.Config{
RewardsCoordinatorAddress: config.RewardsCoordinatorAddress,
}, ethClient, nil, logger, nil)
if err != nil {
return err
}

noSendTxOpts := common.GetNoSendTxOpts(config.EarnerAddress)
unsignedTx, err := contractBindings.RewardsCoordinator.SetClaimerFor(noSendTxOpts, config.ClaimerAddress)
if err != nil {
return err
}
calldataHex := gethcommon.Bytes2Hex(unsignedTx.Data())
if !common.IsEmptyString(config.Output) {
err := common.WriteToFile([]byte(calldataHex), config.Output)
if err != nil {
return err
}
} else {
fmt.Println(calldataHex)
}
} else if config.OutputType == string(common.OutputType_Pretty) {
fmt.Printf(
"Claimer address %s will be set for earner %s\n",
config.ClaimerAddress.String(),
config.EarnerAddress.String(),
)
} else {
return fmt.Errorf("unsupported output type for this command %s", config.Output)
}

return nil
}

keyWallet, sender, err := common.GetWallet(
*config.SignerConfig,
config.EarnerAddress.Hex(),
Expand Down Expand Up @@ -150,6 +180,8 @@ func readAndValidateSetClaimerConfig(cCtx *cli.Context, logger logging.Logger) (
network := cCtx.String(flags.NetworkFlag.Name)
environment := cCtx.String(EnvironmentFlag.Name)
rpcUrl := cCtx.String(flags.ETHRpcUrlFlag.Name)
output := cCtx.String(flags.OutputFileFlag.Name)
outputType := cCtx.String(flags.OutputTypeFlag.Name)
earnerAddress := gethcommon.HexToAddress(cCtx.String(EarnerAddressFlag.Name))
broadcast := cCtx.Bool(flags.BroadcastFlag.Name)
claimerAddress := cCtx.String(ClaimerAddressFlag.Name)
Expand All @@ -174,7 +206,9 @@ func readAndValidateSetClaimerConfig(cCtx *cli.Context, logger logging.Logger) (
// Get SignerConfig
signerConfig, err := common.GetSignerConfig(cCtx, logger)
if err != nil {
return nil, err
// We don't want to throw error since people can still use it to generate the claim
// without broadcasting it
logger.Debugf("Failed to get signer config: %s", err)
}

return &SetClaimerConfig{
Expand All @@ -186,5 +220,7 @@ func readAndValidateSetClaimerConfig(cCtx *cli.Context, logger logging.Logger) (
ChainID: chainID,
SignerConfig: signerConfig,
EarnerAddress: earnerAddress,
Output: output,
OutputType: outputType,
}, nil
}

0 comments on commit 98c880a

Please sign in to comment.