Skip to content

Commit

Permalink
Adding implementation and tests for admin write commands. (#252)
Browse files Browse the repository at this point in the history
Co-authored-by: Brandon Chatham <[email protected]>
  • Loading branch information
bdchatham and Brandon Chatham authored Dec 11, 2024
1 parent c7ba0a2 commit b2a7aa7
Show file tree
Hide file tree
Showing 21 changed files with 1,023 additions and 27 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/Layr-Labs/eigenlayer-contracts v0.3.2-mainnet-rewards
github.com/Layr-Labs/eigenlayer-rewards-proofs v0.2.12
github.com/Layr-Labs/eigenpod-proofs-generation v0.0.14-stable.0.20240730152248-5c11a259293e
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210234612-fdae59339a81
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241211204646-f49e96f7ee7a
github.com/blang/semver/v4 v4.0.0
github.com/consensys/gnark-crypto v0.12.1
github.com/ethereum/go-ethereum v1.14.5
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210222107-c2ed40624db7 h1:1kehcG
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210222107-c2ed40624db7/go.mod h1:aYdNURUhaqeYOS+Cq12TfSdPbjFfiLaHkxPdR4Exq/s=
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210234612-fdae59339a81 h1:max9ka+a5hx9/i/mbH1Y9GToXOCEtfsrt1BX02CAdYA=
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210234612-fdae59339a81/go.mod h1:aYdNURUhaqeYOS+Cq12TfSdPbjFfiLaHkxPdR4Exq/s=
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241211204347-52f4546fdec2 h1:NY7ol96kHl0btYNS8IM8XLYa+PjHs8gMHoISwHGTWCg=
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241211204347-52f4546fdec2/go.mod h1:aYdNURUhaqeYOS+Cq12TfSdPbjFfiLaHkxPdR4Exq/s=
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241211204646-f49e96f7ee7a h1:U1pibFpUsMfL8h9EGrHtm/z94nKKuEvLdWEpkCkCZr4=
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241211204646-f49e96f7ee7a/go.mod h1:aYdNURUhaqeYOS+Cq12TfSdPbjFfiLaHkxPdR4Exq/s=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
Expand Down
125 changes: 124 additions & 1 deletion pkg/user/admin/accept.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,156 @@
package admin

import (
"context"
"sort"

"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/telemetry"
"github.com/Layr-Labs/eigenlayer-cli/pkg/utils"
"github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts"
"github.com/Layr-Labs/eigensdk-go/logging"
eigenSdkUtils "github.com/Layr-Labs/eigensdk-go/utils"
gethcommon "github.com/ethereum/go-ethereum/common"
gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"

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

func AcceptCmd() *cli.Command {
type AcceptAdminWriter interface {
AcceptAdmin(
ctx context.Context,
request elcontracts.AcceptAdminRequest,
) (*gethtypes.Receipt, error)
}

func AcceptCmd(generator func(logging.Logger, *acceptAdminConfig) (AcceptAdminWriter, error)) *cli.Command {
acceptCmd := &cli.Command{
Name: "accept-admin",
Usage: "user admin accept-admin --account-address <AccountAddress>",
UsageText: "Accepts a user to become admin who is currently pending admin acceptance.",
Description: `
Accepts a user to become admin who is currently pending admin acceptance.
`,
Action: func(c *cli.Context) error {
return acceptAdmin(c, generator)
},
After: telemetry.AfterRunAction(),
Flags: acceptFlags(),
}

return acceptCmd
}

func acceptAdmin(
cliCtx *cli.Context,
generator func(logging.Logger, *acceptAdminConfig) (AcceptAdminWriter, error),
) error {
ctx := cliCtx.Context
logger := common.GetLogger(cliCtx)

config, err := readAndValidateAcceptAdminConfig(cliCtx, logger)
if err != nil {
return eigenSdkUtils.WrapError("failed to read and validate user admin accept config", err)
}
cliCtx.App.Metadata["network"] = config.ChainID.String()
elWriter, err := generator(logger, config)
if err != nil {
return err
}

receipt, err := elWriter.AcceptAdmin(
ctx,
elcontracts.AcceptAdminRequest{AccountAddress: config.AccountAddress, WaitForReceipt: true},
)
if err != nil {
return err
}
common.PrintTransactionInfo(receipt.TxHash.String(), config.ChainID)
return nil
}

func readAndValidateAcceptAdminConfig(
cliContext *cli.Context,
logger logging.Logger,
) (*acceptAdminConfig, error) {
accountAddress := gethcommon.HexToAddress(cliContext.String(AccountAddressFlag.Name))
ethRpcUrl := cliContext.String(flags.ETHRpcUrlFlag.Name)
network := cliContext.String(flags.NetworkFlag.Name)
environment := cliContext.String(flags.EnvironmentFlag.Name)
if environment == "" {
environment = common.GetEnvFromNetwork(network)
}
signerConfig, err := common.GetSignerConfig(cliContext, logger)
if err != nil {
// 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)
}

chainID := utils.NetworkNameToChainId(network)
permissionManagerAddress := cliContext.String(PermissionControllerAddressFlag.Name)

if common.IsEmptyString(permissionManagerAddress) {
permissionManagerAddress, err = common.GetPermissionManagerAddress(utils.NetworkNameToChainId(network))
if err != nil {
return nil, err
}
}

logger.Debugf(
"Env: %s, network: %s, chain ID: %s, PermissionManager address: %s",
environment,
network,
chainID,
permissionManagerAddress,
)

return &acceptAdminConfig{
Network: network,
RPCUrl: ethRpcUrl,
AccountAddress: accountAddress,
PermissionManagerAddress: gethcommon.HexToAddress(permissionManagerAddress),
SignerConfig: *signerConfig,
ChainID: chainID,
Environment: environment,
}, nil
}

func acceptFlags() []cli.Flag {
cmdFlags := []cli.Flag{
&flags.VerboseFlag,
&AccountAddressFlag,
&flags.OutputTypeFlag,
&flags.OutputFileFlag,
&flags.NetworkFlag,
&flags.EnvironmentFlag,
&flags.ETHRpcUrlFlag,
&PermissionControllerAddressFlag,
}
sort.Sort(cli.FlagsByName(cmdFlags))
return append(cmdFlags, flags.GetSignerFlags()...)
}

func generateAcceptAdminWriter(
prompter utils.Prompter,
) func(logger logging.Logger, config *acceptAdminConfig) (AcceptAdminWriter, error) {
return func(logger logging.Logger, config *acceptAdminConfig) (AcceptAdminWriter, error) {
ethClient, err := ethclient.Dial(config.RPCUrl)
if err != nil {
return nil, eigenSdkUtils.WrapError("failed to create new eth client", err)
}
return common.GetELWriter(
config.AccountAddress,
&config.SignerConfig,
ethClient,
elcontracts.Config{
PermissionsControllerAddress: config.PermissionManagerAddress,
},
prompter,
config.ChainID,
logger,
)
}
}
106 changes: 106 additions & 0 deletions pkg/user/admin/accept_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package admin

import (
"context"
"errors"
"testing"

"github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts"
"github.com/Layr-Labs/eigensdk-go/logging"
gethcommon "github.com/ethereum/go-ethereum/common"
gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/assert"

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

type mockAcceptAdminWriter struct {
acceptAdminFunc func(ctx context.Context, request elcontracts.AcceptAdminRequest) (*gethtypes.Receipt, error)
}

func (m *mockAcceptAdminWriter) AcceptAdmin(
ctx context.Context,
request elcontracts.AcceptAdminRequest,
) (*gethtypes.Receipt, error) {
return m.acceptAdminFunc(ctx, request)
}

func generateMockAcceptAdminWriter(
receipt *gethtypes.Receipt,
err error,
) func(logging.Logger, *acceptAdminConfig) (AcceptAdminWriter, error) {
return func(logger logging.Logger, config *acceptAdminConfig) (AcceptAdminWriter, error) {
return &mockAcceptAdminWriter{
acceptAdminFunc: func(ctx context.Context, request elcontracts.AcceptAdminRequest) (*gethtypes.Receipt, error) {
return receipt, err
},
}, nil
}
}

func TestAcceptCmd_Success(t *testing.T) {
mockReceipt := &gethtypes.Receipt{
TxHash: gethcommon.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
}

app := cli.NewApp()
app.Commands = []*cli.Command{
AcceptCmd(generateMockAcceptAdminWriter(mockReceipt, nil)),
}

args := []string{
"TestAcceptCmd_Success",
"accept-admin",
"--account-address", "0xabcdef1234567890abcdef1234567890abcdef12",
"--eth-rpc-url", "https://ethereum-holesky.publicnode.com/",
"--network", "holesky",
"--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd",
}

err := app.Run(args)
assert.NoError(t, err)
}

func TestAcceptCmd_GeneratorError(t *testing.T) {
expectedError := "failed to create admin writer"
app := cli.NewApp()
app.Commands = []*cli.Command{
AcceptCmd(func(logger logging.Logger, config *acceptAdminConfig) (AcceptAdminWriter, error) {
return nil, errors.New(expectedError)
}),
}

args := []string{
"TestAcceptCmd_GeneratorError",
"accept-admin",
"--account-address", "0xabcdef1234567890abcdef1234567890abcdef12",
"--eth-rpc-url", "https://ethereum-holesky.publicnode.com/",
"--network", "holesky",
"--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd",
}

err := app.Run(args)
assert.Error(t, err)
assert.Contains(t, err.Error(), expectedError)
}

func TestAcceptCmd_AcceptAdminError(t *testing.T) {
expectedError := "error accepting admin"
app := cli.NewApp()
app.Commands = []*cli.Command{
AcceptCmd(generateMockAcceptAdminWriter(nil, errors.New(expectedError))),
}

args := []string{
"TestAcceptCmd_AcceptAdminError",
"accept-admin",
"--account-address", "0xabcdef1234567890abcdef1234567890abcdef12",
"--eth-rpc-url", "https://ethereum-holesky.publicnode.com/",
"--network", "holesky",
"--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd",
}

err := app.Run(args)
assert.Error(t, err)
assert.Contains(t, err.Error(), expectedError)
}
Loading

0 comments on commit b2a7aa7

Please sign in to comment.