diff --git a/cmd/obol/openclaw.go b/cmd/obol/openclaw.go index b5926052..f853595e 100644 --- a/cmd/obol/openclaw.go +++ b/cmd/obol/openclaw.go @@ -275,6 +275,36 @@ func openclawWalletCommand(cfg *config.Config) *cli.Command { }, getUI(cmd)) }, }, + { + Name: "address", + Usage: "Show the wallet address for an OpenClaw instance", + ArgsUsage: "[instance-name]", + Action: func(ctx context.Context, cmd *cli.Command) error { + args := cmd.Args().Slice() + + if len(args) == 0 { + addr, err := openclaw.ResolveWalletAddress(cfg) + if err != nil { + return err + } + getUI(cmd).Print(addr) + return nil + } + + id, _, err := openclaw.ResolveInstance(cfg, args) + if err != nil { + return err + } + + walletsUI := getUI(cmd) + walletInfo, err := openclaw.ReadWalletMetadata(openclaw.DeploymentPath(cfg, id)) + if err != nil { + return err + } + walletsUI.Print(walletInfo.Address) + return nil + }, + }, { Name: "list", Usage: "List wallets for OpenClaw instances", diff --git a/cmd/obol/openclaw_test.go b/cmd/obol/openclaw_test.go new file mode 100644 index 00000000..a078f2ab --- /dev/null +++ b/cmd/obol/openclaw_test.go @@ -0,0 +1,28 @@ +package main + +import "testing" + +func TestOpenClawWalletCommand_Structure(t *testing.T) { + cfg := newTestConfig(t) + cmd := openclawCommand(cfg) + wallet := findSubcommand(t, cmd, "wallet") + + expected := map[string]bool{ + "backup": false, + "restore": false, + "address": false, + "list": false, + } + + for _, sub := range wallet.Commands { + if _, ok := expected[sub.Name]; ok { + expected[sub.Name] = true + } + } + + for name, found := range expected { + if !found { + t.Errorf("missing wallet subcommand %q", name) + } + } +} diff --git a/internal/stack/stack.go b/internal/stack/stack.go index 7ea80f2e..aff0dff2 100644 --- a/internal/stack/stack.go +++ b/internal/stack/stack.go @@ -524,6 +524,11 @@ func syncDefaults(cfg *config.Config, u *ui.UI, kubeconfigPath string, dataDir s if err := openclaw.SetupDefault(cfg, u); err != nil { u.Warnf("Failed to set up default OpenClaw: %v", err) u.Dim(" You can manually set up OpenClaw later with: obol openclaw onboard") + } else if walletAddr, walletErr := openclaw.ResolveWalletAddress(cfg); walletErr == nil { + u.Blank() + u.Successf("Default agent wallet: %s", walletAddr) + u.Dim(" Fund this wallet for x402 buying or direct on-chain registration.") + u.Dim(" Retrieve later with: obol openclaw wallet address obol-agent") } // Apply agent capabilities (RBAC + heartbeat) to the default instance.