From 2c1c048af083427f8c46388bb58bb35eb337f525 Mon Sep 17 00:00:00 2001 From: FromTheRain Date: Tue, 10 Dec 2024 14:49:33 -0800 Subject: [PATCH] Adding `appointee` `remove` and `set` command implementation and unit tests. (#250) Co-authored-by: Brandon Chatham --- cmd/eigenlayer/main.go | 2 +- go.mod | 3 +- go.sum | 4 +- pkg/user/appointee/appointee.go | 7 +- pkg/user/appointee/list_permissions_test.go | 1 + pkg/user/appointee/list_test.go | 1 + pkg/user/appointee/remove.go | 140 +++++++++++++++++++- pkg/user/appointee/remove_test.go | 108 +++++++++++++++ pkg/user/appointee/set.go | 140 +++++++++++++++++++- pkg/user/appointee/set_test.go | 107 +++++++++++++++ pkg/user/appointee/types.go | 27 ++++ pkg/users.go | 5 +- 12 files changed, 533 insertions(+), 12 deletions(-) create mode 100644 pkg/user/appointee/remove_test.go create mode 100644 pkg/user/appointee/set_test.go diff --git a/cmd/eigenlayer/main.go b/cmd/eigenlayer/main.go index a7f23519..29e414d8 100644 --- a/cmd/eigenlayer/main.go +++ b/cmd/eigenlayer/main.go @@ -43,7 +43,7 @@ func main() { app.Commands = append(app.Commands, pkg.RewardsCmd(prompter)) app.Commands = append(app.Commands, pkg.KeysCmd(prompter)) app.Commands = append(app.Commands, pkg.EigenPodCmd(prompter)) - app.Commands = append(app.Commands, pkg.UserCmd()) + app.Commands = append(app.Commands, pkg.UserCmd(prompter)) if err := app.Run(os.Args); err != nil { _, err := fmt.Fprintln(os.Stderr, err) diff --git a/go.mod b/go.mod index bb732316..e16d3a04 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,7 @@ require ( //<<<<<<< HEAD // github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241212190947-9985122d81fe //======= - github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210000422-beb1a3c4502f - //>>>>>>> 070a30e (feat: slashing commands) + github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210222107-c2ed40624db7 github.com/blang/semver/v4 v4.0.0 github.com/consensys/gnark-crypto v0.12.1 github.com/ethereum/go-ethereum v1.14.5 diff --git a/go.sum b/go.sum index 7def4b86..e01a1ba8 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/Layr-Labs/eigenlayer-rewards-proofs v0.2.12 h1:G5Q1SnLmFbEjhOkky3vIHk github.com/Layr-Labs/eigenlayer-rewards-proofs v0.2.12/go.mod h1:OlJd1QjqEW53wfWG/lJyPCGvrXwWVEjPQsP4TV+gttQ= github.com/Layr-Labs/eigenpod-proofs-generation v0.0.14-stable.0.20240730152248-5c11a259293e h1:DvW0/kWHV9mZsbH2KOjEHKTSIONNPUj6X05FJvUohy4= github.com/Layr-Labs/eigenpod-proofs-generation v0.0.14-stable.0.20240730152248-5c11a259293e/go.mod h1:T7tYN8bTdca2pkMnz9G2+ZwXYWw5gWqQUIu4KLgC/vM= -github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210000422-beb1a3c4502f h1:D94Vf+dALr9W0Ie18lZ8QDPvOAFX8FBbIpyVAtCUL1A= -github.com/Layr-Labs/eigensdk-go v0.1.14-0.20241210000422-beb1a3c4502f/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/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= diff --git a/pkg/user/appointee/appointee.go b/pkg/user/appointee/appointee.go index 1f1f4282..4e2a5d46 100644 --- a/pkg/user/appointee/appointee.go +++ b/pkg/user/appointee/appointee.go @@ -3,10 +3,11 @@ package appointee import ( "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/urfave/cli/v2" ) -func AppointeeCmd() *cli.Command { +func AppointeeCmd(prompter utils.Prompter) *cli.Command { appointeeCmd := &cli.Command{ Name: "appointee", Usage: "user appointee ", @@ -23,8 +24,8 @@ func AppointeeCmd() *cli.Command { canCallCmd(generateUserCanCallReader), ListCmd(generateListUsersReader), ListPermissionsCmd(generateListUserPermissionsReader), - RemoveCmd(), - SetCmd(), + RemoveCmd(generateRemoveUserPermissionWriter(prompter)), + SetCmd(generateSetUserPermissionWriter(prompter)), }, } diff --git a/pkg/user/appointee/list_permissions_test.go b/pkg/user/appointee/list_permissions_test.go index e7f71e3d..1fa90bdc 100644 --- a/pkg/user/appointee/list_permissions_test.go +++ b/pkg/user/appointee/list_permissions_test.go @@ -8,6 +8,7 @@ import ( "github.com/Layr-Labs/eigensdk-go/logging" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" + "github.com/urfave/cli/v2" ) diff --git a/pkg/user/appointee/list_test.go b/pkg/user/appointee/list_test.go index cbc6911c..8f240a43 100644 --- a/pkg/user/appointee/list_test.go +++ b/pkg/user/appointee/list_test.go @@ -8,6 +8,7 @@ import ( "github.com/Layr-Labs/eigensdk-go/logging" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" + "github.com/urfave/cli/v2" ) diff --git a/pkg/user/appointee/remove.go b/pkg/user/appointee/remove.go index 3cf7d684..0c7c3b54 100644 --- a/pkg/user/appointee/remove.go +++ b/pkg/user/appointee/remove.go @@ -1,14 +1,31 @@ package appointee 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 RemoveCmd() *cli.Command { +type RemoveUserPermissionWriter interface { + RemovePermission( + ctx context.Context, + request elcontracts.RemovePermissionRequest, + ) (*gethtypes.Receipt, error) +} + +func RemoveCmd(readerGenerator func(logging.Logger, *removeConfig) (RemoveUserPermissionWriter, error)) *cli.Command { removeCmd := &cli.Command{ Name: "remove", Usage: "user appointee remove --account-address --appointee-address --target-address --selector ", @@ -17,12 +34,130 @@ func RemoveCmd() *cli.Command { Remove a user's permission'. `, After: telemetry.AfterRunAction(), + Action: func(c *cli.Context) error { + return removeUserPermission(c, readerGenerator) + }, Flags: removeCommandFlags(), } return removeCmd } +func removeUserPermission( + cliCtx *cli.Context, + generator func(logging.Logger, *removeConfig) (RemoveUserPermissionWriter, error), +) error { + ctx := cliCtx.Context + logger := common.GetLogger(cliCtx) + + config, err := readAndValidateRemoveConfig(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() + permissionWriter, err := generator(logger, config) + if err != nil { + return err + } + receipt, err := permissionWriter.RemovePermission( + ctx, + elcontracts.RemovePermissionRequest{ + Account: config.AccountAddress, + UserAddress: config.UserAddress, + Target: config.Target, + Selector: config.Selector, + WaitForReceipt: true, + }, + ) + if err != nil { + return err + } + common.PrintTransactionInfo(receipt.TxHash.String(), config.ChainID) + return nil +} + +func generateRemoveUserPermissionWriter( + prompter utils.Prompter, +) func( + logger logging.Logger, + config *removeConfig, +) (RemoveUserPermissionWriter, error) { + return func(logger logging.Logger, config *removeConfig) (RemoveUserPermissionWriter, error) { + ethClient, err := ethclient.Dial(config.RPCUrl) + if err != nil { + return nil, eigenSdkUtils.WrapError("failed to create new eth client", err) + } + elWriter, err := common.GetELWriter( + config.AccountAddress, + &config.SignerConfig, + ethClient, + elcontracts.Config{ + PermissionsControllerAddress: config.PermissionManagerAddress, + }, + prompter, + config.ChainID, + logger, + ) + return elWriter, err + } +} + +func readAndValidateRemoveConfig(cliContext *cli.Context, logger logging.Logger) (*removeConfig, error) { + accountAddress := gethcommon.HexToAddress(cliContext.String(AccountAddressFlag.Name)) + userAddress := gethcommon.HexToAddress(cliContext.String(AppointeeAddressFlag.Name)) + ethRpcUrl := cliContext.String(flags.ETHRpcUrlFlag.Name) + network := cliContext.String(flags.NetworkFlag.Name) + environment := cliContext.String(flags.EnvironmentFlag.Name) + target := gethcommon.HexToAddress(cliContext.String(TargetAddressFlag.Name)) + selector := cliContext.String(SelectorFlag.Name) + selectorBytes, err := common.ValidateAndConvertSelectorString(selector) + if err != nil { + return nil, err + } + 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) + } + + if environment == "" { + environment = common.GetEnvFromNetwork(network) + } + + chainID := utils.NetworkNameToChainId(network) + cliContext.App.Metadata["network"] = chainID.String() + 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 &removeConfig{ + Network: network, + RPCUrl: ethRpcUrl, + AccountAddress: accountAddress, + UserAddress: userAddress, + Target: target, + Selector: selectorBytes, + SignerConfig: *signerConfig, + PermissionManagerAddress: gethcommon.HexToAddress(permissionManagerAddress), + ChainID: chainID, + Environment: environment, + }, nil +} + func removeCommandFlags() []cli.Flag { cmdFlags := []cli.Flag{ &flags.VerboseFlag, @@ -30,6 +165,9 @@ func removeCommandFlags() []cli.Flag { &AppointeeAddressFlag, &TargetAddressFlag, &SelectorFlag, + &flags.NetworkFlag, + &flags.EnvironmentFlag, + &flags.ETHRpcUrlFlag, } sort.Sort(cli.FlagsByName(cmdFlags)) return append(cmdFlags, flags.GetSignerFlags()...) diff --git a/pkg/user/appointee/remove_test.go b/pkg/user/appointee/remove_test.go new file mode 100644 index 00000000..f08d71b4 --- /dev/null +++ b/pkg/user/appointee/remove_test.go @@ -0,0 +1,108 @@ +package appointee + +import ( + "context" + "errors" + gethtypes "github.com/ethereum/go-ethereum/core/types" + "testing" + + "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/stretchr/testify/assert" + + "github.com/urfave/cli/v2" +) + +type mockRemoveUserPermissionWriter struct { + removePermissionFunc func(ctx context.Context, request elcontracts.RemovePermissionRequest) (*gethtypes.Receipt, error) +} + +func (m *mockRemoveUserPermissionWriter) RemovePermission( + ctx context.Context, + request elcontracts.RemovePermissionRequest, +) (*gethtypes.Receipt, error) { + return m.removePermissionFunc(ctx, request) +} + +func generateMockRemoveWriter(err error) func(logging.Logger, *removeConfig) (RemoveUserPermissionWriter, error) { + return func(logger logging.Logger, config *removeConfig) (RemoveUserPermissionWriter, error) { + return &mockRemoveUserPermissionWriter{ + removePermissionFunc: func(ctx context.Context, request elcontracts.RemovePermissionRequest) (*gethtypes.Receipt, error) { + return &gethtypes.Receipt{}, err + }, + }, nil + } +} + +func TestRemoveCmd_Success(t *testing.T) { + app := cli.NewApp() + app.Commands = []*cli.Command{ + RemoveCmd(generateMockRemoveWriter(nil)), + } + + args := []string{ + "TestRemoveCmd_Success", + "remove", + "--account-address", "0x1234567890abcdef1234567890abcdef12345678", + "--appointee-address", "0xabcdef1234567890abcdef1234567890abcdef12", + "--target-address", "0x9876543210fedcba9876543210fedcba98765432", + "--selector", "0x1A2B3C4D", + "--network", "holesky", + "--eth-rpc-url", "https://ethereum-holesky.publicnode.com/", + "--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + } + + err := app.Run(args) + assert.NoError(t, err) +} + +func TestRemoveCmd_GeneratorError(t *testing.T) { + expectedError := "failed to create permission writer" + app := cli.NewApp() + app.Commands = []*cli.Command{ + RemoveCmd(func(logger logging.Logger, config *removeConfig) (RemoveUserPermissionWriter, error) { + return nil, errors.New(expectedError) + }), + } + + args := []string{ + "TestRemoveCmd_GeneratorError", + "remove", + "--account-address", "0x1234567890abcdef1234567890abcdef12345678", + "--appointee-address", "0xabcdef1234567890abcdef1234567890abcdef12", + "--target-address", "0x9876543210fedcba9876543210fedcba98765432", + "--selector", "0x1A2B3C4D", + "--network", "holesky", + "--eth-rpc-url", "https://ethereum-holesky.publicnode.com/", + "--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + } + + err := app.Run(args) + assert.Error(t, err) + assert.Contains(t, err.Error(), expectedError) +} + +func TestRemoveCmd_RemovePermissionError(t *testing.T) { + expectedError := "error removing permission" + app := cli.NewApp() + app.Commands = []*cli.Command{ + RemoveCmd(generateMockRemoveWriter(errors.New(expectedError))), + } + + args := []string{ + "TestRemoveCmd_RemovePermissionError", + "remove", + "--account-address", "0x1234567890abcdef1234567890abcdef12345678", + "--appointee-address", "0xabcdef1234567890abcdef1234567890abcdef12", + "--target-address", "0x9876543210fedcba9876543210fedcba98765432", + "--selector", "0x1A2B3C4D", + "--network", "holesky", + "--eth-rpc-url", "https://ethereum-holesky.publicnode.com/", + "--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + "--path-to-key-store", "/path/to/keystore.json", + } + + err := app.Run(args) + assert.Error(t, err) + assert.Contains(t, err.Error(), expectedError) +} diff --git a/pkg/user/appointee/set.go b/pkg/user/appointee/set.go index 87e34d39..822d0867 100644 --- a/pkg/user/appointee/set.go +++ b/pkg/user/appointee/set.go @@ -1,14 +1,31 @@ package appointee 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 SetCmd() *cli.Command { +type SetUserPermissionWriter interface { + SetPermission( + ctx context.Context, + request elcontracts.SetPermissionRequest, + ) (*gethtypes.Receipt, error) +} + +func SetCmd(generator func(logging.Logger, *setConfig) (SetUserPermissionWriter, error)) *cli.Command { setCmd := &cli.Command{ Name: "set", Usage: "user appointee set --account-address --appointee-address --target-address --selector ", @@ -16,6 +33,9 @@ func SetCmd() *cli.Command { Description: ` Grant a user a permission.'. `, + Action: func(c *cli.Context) error { + return setUserPermission(c, generator) + }, After: telemetry.AfterRunAction(), Flags: setCommandFlags(), } @@ -23,6 +43,121 @@ func SetCmd() *cli.Command { return setCmd } +func setUserPermission( + cliCtx *cli.Context, + generator func(logging.Logger, *setConfig) (SetUserPermissionWriter, error), +) error { + ctx := cliCtx.Context + logger := common.GetLogger(cliCtx) + + config, err := readAndValidateSetConfig(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() + permissionWriter, err := generator(logger, config) + if err != nil { + return err + } + receipt, err := permissionWriter.SetPermission( + ctx, + elcontracts.SetPermissionRequest{ + Account: config.AccountAddress, + UserAddress: config.UserAddress, + Target: config.Target, + Selector: config.Selector, + WaitForReceipt: true, + }, + ) + if err != nil { + return err + } + common.PrintTransactionInfo(receipt.TxHash.String(), config.ChainID) + return nil +} + +func generateSetUserPermissionWriter( + prompter utils.Prompter, +) func( + logger logging.Logger, + config *setConfig, +) (SetUserPermissionWriter, error) { + return func(logger logging.Logger, config *setConfig) (SetUserPermissionWriter, error) { + ethClient, err := ethclient.Dial(config.RPCUrl) + if err != nil { + return nil, eigenSdkUtils.WrapError("failed to create new eth client", err) + } + elWriter, err := common.GetELWriter( + config.AccountAddress, + &config.SignerConfig, + ethClient, + elcontracts.Config{ + PermissionsControllerAddress: config.PermissionManagerAddress, + }, + prompter, + config.ChainID, + logger, + ) + return elWriter, err + } +} + +func readAndValidateSetConfig(cliContext *cli.Context, logger logging.Logger) (*setConfig, error) { + accountAddress := gethcommon.HexToAddress(cliContext.String(AccountAddressFlag.Name)) + userAddress := gethcommon.HexToAddress(cliContext.String(AppointeeAddressFlag.Name)) + ethRpcUrl := cliContext.String(flags.ETHRpcUrlFlag.Name) + network := cliContext.String(flags.NetworkFlag.Name) + environment := cliContext.String(flags.EnvironmentFlag.Name) + target := gethcommon.HexToAddress(cliContext.String(TargetAddressFlag.Name)) + selector := cliContext.String(SelectorFlag.Name) + selectorBytes, err := common.ValidateAndConvertSelectorString(selector) + if err != nil { + return nil, err + } + 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) + } + + if environment == "" { + environment = common.GetEnvFromNetwork(network) + } + + chainID := utils.NetworkNameToChainId(network) + cliContext.App.Metadata["network"] = chainID.String() + 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 &setConfig{ + Network: network, + RPCUrl: ethRpcUrl, + AccountAddress: accountAddress, + UserAddress: userAddress, + Target: target, + Selector: selectorBytes, + SignerConfig: *signerConfig, + PermissionManagerAddress: gethcommon.HexToAddress(permissionManagerAddress), + ChainID: chainID, + Environment: environment, + }, nil +} + func setCommandFlags() []cli.Flag { cmdFlags := []cli.Flag{ &flags.VerboseFlag, @@ -30,6 +165,9 @@ func setCommandFlags() []cli.Flag { &AppointeeAddressFlag, &TargetAddressFlag, &SelectorFlag, + &flags.NetworkFlag, + &flags.EnvironmentFlag, + &flags.ETHRpcUrlFlag, } sort.Sort(cli.FlagsByName(cmdFlags)) return append(cmdFlags, flags.GetSignerFlags()...) diff --git a/pkg/user/appointee/set_test.go b/pkg/user/appointee/set_test.go new file mode 100644 index 00000000..14a0b95f --- /dev/null +++ b/pkg/user/appointee/set_test.go @@ -0,0 +1,107 @@ +package appointee + +import ( + "context" + "errors" + gethtypes "github.com/ethereum/go-ethereum/core/types" + "testing" + + "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/stretchr/testify/assert" + + "github.com/urfave/cli/v2" +) + +type mockSetUserPermissionWriter struct { + setPermissionFunc func(ctx context.Context, request elcontracts.SetPermissionRequest) (*gethtypes.Receipt, error) +} + +func (m *mockSetUserPermissionWriter) SetPermission( + ctx context.Context, + request elcontracts.SetPermissionRequest, +) (*gethtypes.Receipt, error) { + return m.setPermissionFunc(ctx, request) +} + +func generateMockSetWriter(err error) func(logging.Logger, *setConfig) (SetUserPermissionWriter, error) { + return func(logger logging.Logger, config *setConfig) (SetUserPermissionWriter, error) { + return &mockSetUserPermissionWriter{ + setPermissionFunc: func(ctx context.Context, request elcontracts.SetPermissionRequest) (*gethtypes.Receipt, error) { + return &gethtypes.Receipt{}, err + }, + }, nil + } +} + +func TestSetCmd_Success(t *testing.T) { + app := cli.NewApp() + app.Commands = []*cli.Command{ + SetCmd(generateMockSetWriter(nil)), + } + + args := []string{ + "TestSetCmd_Success", + "set", + "--account-address", "0x1234567890abcdef1234567890abcdef12345678", + "--appointee-address", "0xabcdef1234567890abcdef1234567890abcdef12", + "--target-address", "0x9876543210fedcba9876543210fedcba98765432", + "--selector", "0x1A2B3C4D", + "--network", "holesky", + "--eth-rpc-url", "https://ethereum-holesky.publicnode.com/", + "--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + } + + err := app.Run(args) + assert.NoError(t, err) +} + +func TestSetCmd_GeneratorError(t *testing.T) { + expectedError := "failed to create permission writer" + app := cli.NewApp() + app.Commands = []*cli.Command{ + SetCmd(func(logger logging.Logger, config *setConfig) (SetUserPermissionWriter, error) { + return nil, errors.New(expectedError) + }), + } + + args := []string{ + "TestSetCmd_GeneratorError", + "set", + "--account-address", "0x1234567890abcdef1234567890abcdef12345678", + "--appointee-address", "0xabcdef1234567890abcdef1234567890abcdef12", + "--target-address", "0x9876543210fedcba9876543210fedcba98765432", + "--selector", "0x1A2B3C4D", + "--network", "holesky", + "--eth-rpc-url", "https://ethereum-holesky.publicnode.com/", + "--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + } + + err := app.Run(args) + assert.Error(t, err) + assert.Contains(t, err.Error(), expectedError) +} + +func TestSetCmd_SetPermissionError(t *testing.T) { + expectedError := "error setting permission" + app := cli.NewApp() + app.Commands = []*cli.Command{ + SetCmd(generateMockSetWriter(errors.New(expectedError))), + } + + args := []string{ + "TestSetCmd_SetPermissionError", + "set", + "--account-address", "0x1234567890abcdef1234567890abcdef12345678", + "--appointee-address", "0xabcdef1234567890abcdef1234567890abcdef12", + "--target-address", "0x9876543210fedcba9876543210fedcba98765432", + "--selector", "0x1A2B3C4D", + "--network", "holesky", + "--eth-rpc-url", "https://ethereum-holesky.publicnode.com/", + "--ecdsa-private-key", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + } + + err := app.Run(args) + assert.Error(t, err) + assert.Contains(t, err.Error(), expectedError) +} diff --git a/pkg/user/appointee/types.go b/pkg/user/appointee/types.go index 9ec83ffc..6e17194f 100644 --- a/pkg/user/appointee/types.go +++ b/pkg/user/appointee/types.go @@ -3,6 +3,7 @@ package appointee import ( "math/big" + "github.com/Layr-Labs/eigenlayer-cli/pkg/types" gethcommon "github.com/ethereum/go-ethereum/common" ) @@ -39,3 +40,29 @@ type listUserPermissionsConfig struct { ChainID *big.Int Environment string } + +type removeConfig struct { + Network string + RPCUrl string + AccountAddress gethcommon.Address + UserAddress gethcommon.Address + Target gethcommon.Address + SignerConfig types.SignerConfig + Selector [4]byte + PermissionManagerAddress gethcommon.Address + ChainID *big.Int + Environment string +} + +type setConfig struct { + Network string + RPCUrl string + AccountAddress gethcommon.Address + UserAddress gethcommon.Address + Target gethcommon.Address + SignerConfig types.SignerConfig + Selector [4]byte + PermissionManagerAddress gethcommon.Address + ChainID *big.Int + Environment string +} diff --git a/pkg/users.go b/pkg/users.go index 44b09b51..99448433 100644 --- a/pkg/users.go +++ b/pkg/users.go @@ -3,16 +3,17 @@ package pkg import ( "github.com/Layr-Labs/eigenlayer-cli/pkg/user/admin" "github.com/Layr-Labs/eigenlayer-cli/pkg/user/appointee" + "github.com/Layr-Labs/eigenlayer-cli/pkg/utils" "github.com/urfave/cli/v2" ) -func UserCmd() *cli.Command { +func UserCmd(prompter utils.Prompter) *cli.Command { var userCmd = &cli.Command{ Name: "user", Usage: "Manage user permissions", Subcommands: []*cli.Command{ admin.AdminCmd(), - appointee.AppointeeCmd(), + appointee.AppointeeCmd(prompter), }, }