Skip to content

Commit

Permalink
Adding admin read commands with unit tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon Chatham committed Dec 11, 2024
1 parent 699d6a6 commit e7d3bfd
Show file tree
Hide file tree
Showing 13 changed files with 983 additions and 30 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.20241210222107-c2ed40624db7
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210234612-fdae59339a81
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
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210204558-54685ff8f493 h1:9HsmuJ
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210204558-54685ff8f493/go.mod h1:aYdNURUhaqeYOS+Cq12TfSdPbjFfiLaHkxPdR4Exq/s=
github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210222107-c2ed40624db7 h1:1kehcGgMyVloGzrd36CSibYz+fC2BkKV0fqeYCpovIQ=
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/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
8 changes: 4 additions & 4 deletions pkg/user/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ func AdminCmd() *cli.Command {
Subcommands: []*cli.Command{
AcceptCmd(),
AddPendingCmd(),
IsAdminCmd(),
IsPendingCmd(),
ListCmd(),
ListPendingCmd(),
IsAdminCmd(generateIsAdminReader),
IsPendingCmd(generateIsPendingAdminReader),
ListCmd(generateListAdminsReader),
ListPendingCmd(generateListPendingAdminsReader),
RemoveCmd(),
RemovePendingCmd(),
},
Expand Down
128 changes: 120 additions & 8 deletions pkg/user/admin/is_admin.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,138 @@
package admin

import (
"context"
"fmt"
"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"
"github.com/ethereum/go-ethereum/ethclient"

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

func IsAdminCmd() *cli.Command {
isAdmin := &cli.Command{
type IsAdminReader interface {
IsAdmin(
ctx context.Context,
accountAddress gethcommon.Address,
pendingAdminAddress gethcommon.Address,
) (bool, error)
}

func IsAdminCmd(readerGenerator func(logging.Logger, *isAdminConfig) (IsAdminReader, error)) *cli.Command {
cmd := &cli.Command{
Name: "is-admin",
Usage: "user admin is-admin --account-address <AccountAddress> --caller-address <CallerAddress>",
UsageText: "Checks if a user is an admin.",
Description: `
Checks if a user is an admin.
`,
After: telemetry.AfterRunAction(),
Flags: []cli.Flag{
&flags.VerboseFlag,
&AccountAddressFlag,
&CallerAddressFlag,
Action: func(c *cli.Context) error {
return isAdmin(c, readerGenerator)
},
After: telemetry.AfterRunAction(),
Flags: IsAdminFlags(),
}

return cmd
}

func isAdmin(cliCtx *cli.Context, generator func(logging.Logger, *isAdminConfig) (IsAdminReader, error)) error {
ctx := cliCtx.Context
logger := common.GetLogger(cliCtx)

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

result, err := elReader.IsAdmin(ctx, config.AccountAddress, config.AdminAddress)
if err != nil {
return err
}
fmt.Printf("IsAdmin Result: %v\n", result)
return nil
}

func readAndValidateIsAdminConfig(cliContext *cli.Context, logger logging.Logger) (*isAdminConfig, error) {
accountAddress := gethcommon.HexToAddress(cliContext.String(AccountAddressFlag.Name))
adminAddress := gethcommon.HexToAddress(cliContext.String(AdminAddressFlag.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)
}

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

var err error
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 isAdmin
return &isAdminConfig{
Network: network,
RPCUrl: ethRpcUrl,
AccountAddress: accountAddress,
AdminAddress: adminAddress,
PermissionManagerAddress: gethcommon.HexToAddress(permissionManagerAddress),
ChainID: chainID,
Environment: environment,
}, nil
}

func generateIsAdminReader(logger logging.Logger, config *isAdminConfig) (IsAdminReader, error) {
ethClient, err := ethclient.Dial(config.RPCUrl)
if err != nil {
return nil, eigenSdkUtils.WrapError("failed to create new eth client", err)
}
elReader, err := elcontracts.NewReaderFromConfig(
elcontracts.Config{
PermissionsControllerAddress: config.PermissionManagerAddress,
},
ethClient,
logger,
)
return elReader, err
}

func IsAdminFlags() []cli.Flag {
cmdFlags := []cli.Flag{
&flags.VerboseFlag,
&AccountAddressFlag,
&CallerAddressFlag,
&flags.OutputTypeFlag,
&flags.OutputFileFlag,
&PermissionControllerAddressFlag,
&flags.NetworkFlag,
&flags.EnvironmentFlag,
&flags.ETHRpcUrlFlag,
}
sort.Sort(cli.FlagsByName(cmdFlags))
return cmdFlags
}
116 changes: 116 additions & 0 deletions pkg/user/admin/is_admin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package admin

import (
"context"
"errors"
"testing"

"github.com/Layr-Labs/eigensdk-go/logging"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v2"
)

type mockIsAdminReader struct {
isAdminFunc func(ctx context.Context, accountAddress gethcommon.Address, adminAddress gethcommon.Address) (bool, error)
}

func (m *mockIsAdminReader) IsAdmin(
ctx context.Context,
accountAddress gethcommon.Address,
adminAddress gethcommon.Address,
) (bool, error) {
return m.isAdminFunc(ctx, accountAddress, adminAddress)
}

func generateMockIsAdminReader(result bool, err error) func(logging.Logger, *isAdminConfig) (IsAdminReader, error) {
return func(logger logging.Logger, config *isAdminConfig) (IsAdminReader, error) {
return &mockIsAdminReader{
isAdminFunc: func(ctx context.Context, accountAddress gethcommon.Address, adminAddress gethcommon.Address) (bool, error) {
return result, err
},
}, nil
}
}

func TestIsAdminCmd_Success(t *testing.T) {
app := cli.NewApp()
app.Commands = []*cli.Command{
IsAdminCmd(generateMockIsAdminReader(true, nil)),
}

args := []string{
"TestIsAdminCmd_Success",
"is-admin",
"--account-address", "0xabcdef1234567890abcdef1234567890abcdef12",
"--caller-address", "0x1234567890abcdef1234567890abcdef12345678",
"--eth-rpc-url", "https://ethereum-holesky.publicnode.com/",
"--network", "holesky",
}

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

func TestIsAdminCmd_NotAdmin(t *testing.T) {
app := cli.NewApp()
app.Commands = []*cli.Command{
IsAdminCmd(generateMockIsAdminReader(false, nil)),
}

args := []string{
"TestIsAdminCmd_NotAdmin",
"is-admin",
"--account-address", "0xabcdef1234567890abcdef1234567890abcdef12",
"--caller-address", "0x1234567890abcdef1234567890abcdef12345678",
"--eth-rpc-url", "https://ethereum-holesky.publicnode.com/",
"--network", "holesky",
}

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

func TestIsAdminCmd_GeneratorError(t *testing.T) {
expectedError := "failed to create admin reader"
app := cli.NewApp()
app.Commands = []*cli.Command{
IsAdminCmd(func(logger logging.Logger, config *isAdminConfig) (IsAdminReader, error) {
return nil, errors.New(expectedError)
}),
}

args := []string{
"TestIsAdminCmd_GeneratorError",
"is-admin",
"--account-address", "0xabcdef1234567890abcdef1234567890abcdef12",
"--caller-address", "0x1234567890abcdef1234567890abcdef12345678",
"--eth-rpc-url", "https://ethereum-holesky.publicnode.com/",
"--network", "holesky",
}

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

func TestIsAdminCmd_IsAdminError(t *testing.T) {
expectedError := "error checking admin status"
app := cli.NewApp()
app.Commands = []*cli.Command{
IsAdminCmd(generateMockIsAdminReader(false, errors.New(expectedError))),
}

args := []string{
"TestIsAdminCmd_IsAdminError",
"is-admin",
"--account-address", "0xabcdef1234567890abcdef1234567890abcdef12",
"--caller-address", "0x1234567890abcdef1234567890abcdef12345678",
"--eth-rpc-url", "https://ethereum-holesky.publicnode.com/",
"--network", "holesky",
}

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

0 comments on commit e7d3bfd

Please sign in to comment.