Skip to content

Commit

Permalink
fix: delegation approver functions
Browse files Browse the repository at this point in the history
  • Loading branch information
shrimalmadhur committed Oct 24, 2024
1 parent 4af04b1 commit aa56e08
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 168 deletions.
2 changes: 1 addition & 1 deletion pkg/internal/common/flags/general.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ var (

ExpiryFlag = cli.Int64Flag{
Name: "expiry",
Aliases: []string{"e"},
Aliases: []string{"exp"},
Usage: "expiry in seconds",
EnvVars: []string{"EXPIRY"},
Value: 3600,
Expand Down
167 changes: 0 additions & 167 deletions pkg/operator/get_approval.go

This file was deleted.

222 changes: 222 additions & 0 deletions pkg/operator/get_delegation_approval.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package operator

import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"

"math/big"
"time"

"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common"
"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common/flags"
"github.com/Layr-Labs/eigenlayer-cli/pkg/keys"
"github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry"
"github.com/Layr-Labs/eigenlayer-cli/pkg/types"
"github.com/Layr-Labs/eigenlayer-cli/pkg/utils"

"github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts"
elContracts "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts"
eigenSdkUtils "github.com/Layr-Labs/eigensdk-go/utils"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"

"github.com/urfave/cli/v2"
)

func GetApprovalCmd(p utils.Prompter) *cli.Command {
getApprovalCmd := &cli.Command{
Name: "get-delegation-approval",
Usage: "Generate the delegation approval details for the delegateTo method for stakers",
UsageText: "get-delegation-approval <configuration-file> <staker-address>",
Description: `
Generate the smart contract approval details for the delegateTo method.
It expects the same configuration yaml file as an argument to the register command, along with the staker address.
For delegation approval signing, it requires the private key or keystore file path for delegation approver via flags.
If those are not provided, it will output unsigned hash for manual signing.
Use the --expiry flag to override the default expiration of 3600 seconds.
`,
After: telemetry.AfterRunAction(),
Flags: []cli.Flag{
&flags.VerboseFlag,
&flags.ExpiryFlag,
&flags.EcdsaPrivateKeyFlag,
&flags.PathToKeyStoreFlag,
},
Action: func(cCtx *cli.Context) error {
logger := common.GetLogger(cCtx)

approvalConfig, err := getApprovalConfig(cCtx)
if err != nil {
return err
}

operatorCfg, err := common.ReadConfigFile(approvalConfig.OperatorConfigFilePath)
if err != nil {
return err
}
cCtx.App.Metadata["network"] = operatorCfg.ChainId.String()

logger.Infof(
"%s Operator configuration file read successfully %s",
utils.EmojiCheckMark,
operatorCfg.Operator.Address,
)
logger.Info("%s validating operator config: %s", utils.EmojiWait, operatorCfg.Operator.Address)

ethClient, err := ethclient.Dial(operatorCfg.EthRPCUrl)
if err != nil {
return err
}
id, err := ethClient.ChainID(context.Background())
if err != nil {
return err
}

if id.Cmp(&operatorCfg.ChainId) != 0 {
return fmt.Errorf(
"%w: chain ID in config file %d does not match the chain ID of the network %d",
ErrInvalidYamlFile,
&operatorCfg.ChainId,
id,
)
}

logger.Infof(
"%s Operator configuration file validated successfully %s",
utils.EmojiCheckMark,
operatorCfg.Operator.Address,
)

contractCfg := elcontracts.Config{
DelegationManagerAddress: gethcommon.HexToAddress(operatorCfg.ELDelegationManagerAddress),
AvsDirectoryAddress: gethcommon.HexToAddress(operatorCfg.ELAVSDirectoryAddress),
}
reader, err := elContracts.NewReaderFromConfig(
contractCfg,
ethClient,
logger,
)
if err != nil {
return err
}

staker := gethcommon.HexToAddress(approvalConfig.StakerAddress)
operator := gethcommon.HexToAddress(operatorCfg.Operator.Address)
delegationApprover := gethcommon.HexToAddress(operatorCfg.Operator.DelegationApproverAddress)
salt := make([]byte, 32)

if _, err := rand.Read(salt); err != nil {
return err
}
expiry := new(big.Int).SetInt64(time.Now().Unix() + approvalConfig.Expiry)

callOpts := &bind.CallOpts{Context: context.Background()}

hash, err := reader.CalculateDelegationApprovalDigestHash(
callOpts,
staker,
operator,
delegationApprover,
[32]byte(salt),
expiry,
)
if err != nil {
return err
}

signed, err := common.Sign(hash[:], approvalConfig.SignerConfig, p)
if err != nil {
fmt.Println("unable to sign with the provided signer config. please sign the hash manually", err)
fmt.Println(
"--------------------------- CalculateDelegationApprovalDigestHash details ---------------------------",
)
fmt.Println()
fmt.Printf("staker: %s\n", staker)
fmt.Printf("operator: %s\n", operator)
fmt.Printf("_delegationApprover: %s\n", delegationApprover)
fmt.Printf("approverSalt: %s\n", eigenSdkUtils.Add0x(hex.EncodeToString(salt)))
fmt.Printf("expiry: %d\n", expiry)
fmt.Println()
fmt.Printf("hash: %s\n", eigenSdkUtils.Add0x(hex.EncodeToString(hash[:])))
fmt.Println()
fmt.Println("------------------------------------------------------------------------")
fmt.Println()
return nil
}

fmt.Println()
fmt.Println("--------------------------- delegateTo for the staker ---------------------------")
fmt.Println()
fmt.Printf("operator: %s\n", operator)
fmt.Printf("approverSignatureAndExpiry.signature: %s\n", eigenSdkUtils.Add0x(hex.EncodeToString(signed)))
fmt.Printf("approverSignatureAndExpiry.expiry: %d\n", expiry)
fmt.Printf("approverSalt: %s\n", eigenSdkUtils.Add0x(hex.EncodeToString(salt)))
fmt.Println()

return nil
},
}
return getApprovalCmd
}

type ApprovalConfig struct {
OperatorConfigFilePath string
StakerAddress string
Expiry int64
SignerConfig types.SignerConfig
}

func getApprovalConfig(cCtx *cli.Context) (*ApprovalConfig, error) {
args := cCtx.Args()
if args.Len() != 2 {
return nil, fmt.Errorf("%w: accepts 2 arg, received %d", keys.ErrInvalidNumberOfArgs, args.Len())
}

expirySeconds := cCtx.Int64(flags.ExpiryFlag.Name)

configurationFilePath := args.Get(0)
stakerAddress := args.Get(1)

if !eigenSdkUtils.IsValidEthereumAddress(stakerAddress) {
return nil, fmt.Errorf("staker address %s is not valid address", stakerAddress)
}

privateKeyHex := cCtx.String(flags.EcdsaPrivateKeyFlag.Name)
keystoreFilePath := cCtx.String(flags.PathToKeyStoreFlag.Name)
if privateKeyHex == "" && keystoreFilePath == "" {
return nil, fmt.Errorf("either private key or keystore file path is required. other signer not supported")
}

if privateKeyHex != "" {
privateKey, err := crypto.HexToECDSA(privateKeyHex)
if err != nil {
return nil, err
}
return &ApprovalConfig{
OperatorConfigFilePath: configurationFilePath,
StakerAddress: stakerAddress,
Expiry: expirySeconds,
SignerConfig: types.SignerConfig{
PrivateKey: privateKey,
SignerType: types.PrivateKeySigner,
},
}, nil
}

return &ApprovalConfig{
OperatorConfigFilePath: configurationFilePath,
StakerAddress: stakerAddress,
Expiry: expirySeconds,
SignerConfig: types.SignerConfig{
PrivateKeyStorePath: keystoreFilePath,
SignerType: types.LocalKeystoreSigner,
},
}, nil
}

0 comments on commit aa56e08

Please sign in to comment.