Skip to content

Fix flow-11 buyer wallet reuse#380

Draft
bussyjd wants to merge 3 commits intomainfrom
fix/flow11-injected-buyer-wallet
Draft

Fix flow-11 buyer wallet reuse#380
bussyjd wants to merge 3 commits intomainfrom
fix/flow11-injected-buyer-wallet

Conversation

@bussyjd
Copy link
Copy Markdown
Collaborator

@bussyjd bussyjd commented Apr 24, 2026

Summary

This PR fixes flow-11 so Bob buys with the already-funded second deterministic wallet instead of a generated throwaway remote-signer wallet.

Key changes:

  • Add obol openclaw wallet import-private-key <instance> --private-key-file ... --force.
  • Import the second deterministic key into Bob's remote-signer during flow-11-dual-stack.sh and assert bobSigner == BOB_WALLET.
  • Patch the in-cluster remote-signer-keystore-password Secret during wallet import/restore before restarting remote-signer.
  • Pin eRPC write routing for explicit network add --endpoint ... --allow-writes RPCs so ERC-8004 transactions do not route to flaky built-ins.
  • Add conservative ERC-8004 registration recovery/retry for transient RPC 5xx/timeouts.
  • Remove the old throwaway-wallet funding path from flow-11 and update the Obol Stack development skill note.

Flow

sequenceDiagram
  participant Env as .env REMOTE_SIGNER_PRIVATE_KEY
  participant Alice as Alice stack
  participant BobFlow as flow-11
  participant BobSigner as Bob remote-signer
  participant Buyer as buy.py / x402-buyer
  participant Chain as Base Sepolia

  Env->>Alice: first key sells/registers
  Alice->>Chain: ERC-8004 register + metadata
  Env->>BobFlow: derive second key
  BobFlow->>Chain: assert second key has USDC
  BobFlow->>BobSigner: import-private-key(second key)
  BobSigner-->>BobFlow: address == BOB_WALLET
  Buyer->>BobSigner: sign ERC-3009 auths
  Buyer->>Alice: paid inference via paid/qwen3.5:9b
  Alice->>Chain: settle 1000 micro-USDC
Loading

Validation

  • bash -n flows/flow-11-dual-stack.sh
  • go test ./cmd/obol -run 'TestIsTransientRegistrationError|TestSellRegister_Flags|TestOpenClawWalletCommand_Structure' -count=1
  • go test ./internal/openclaw ./internal/network -count=1
  • go test ./...
  • Live full flow: FLOW11_BASE_SEPOLIA_RPC=https://base-sepolia-rpc.publicnode.com ./flows/flow-11-dual-stack.sh

Live receipts from .tmp/flow-11-20260424-230033/receipt-summary.json:

  • Agent ID: 5183
  • Alice: 0xC0De030F6C37f490594F93fB99e2756703c4297E
  • Bob / Bob signer: 0x57b0eF875DeB5A37301F1640E469a2129Da9490E
  • Registration tx: 0x2a64bc1aeb27e077fef49e435b6349cca61ead598300e918c5cef8caebb5368f
  • Metadata tx: 0xe43d773ae7cfe7fff3b79dded65c7d38e190bc02d61940c02673b9b12ad2696f
  • Settlement tx: 0x9caf938393ef4b40bc6ff5817c4d620bb9847fef6ff72aac22ec113ad491f516
  • Funding tx: empty, because Bob used the pre-funded derived wallet
  • Balance check: Alice 9167000 -> 9168000 micro-USDC, Bob signer 4997000 -> 4996000 micro-USDC

@bussyjd bussyjd requested a review from OisinKyne April 24, 2026 15:12
Comment thread cmd/obol/openclaw.go Outdated
},
},
{
Name: "import-private-key",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Name: "import-private-key",
Name: "import",

Comment thread internal/openclaw/wallet_backup.go Outdated
if entry.IsDir() || entry.Name() == keep || !strings.HasSuffix(entry.Name(), ".json") {
continue
}
if err := os.Remove(filepath.Join(dir, entry.Name())); err != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want to be wiping private keys? as far as i can tell this code wipes any its not immediately creating, no?

return nil
}

func restartRemoteSigner(cfg *config.Config, id string, u *ui.UI) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine this is done to pick up changes.

Thinking ahead, to when maybe we want an agent to mess with wallets; they won't have kubeconfig access. should we consider fixing whatever reload this is working around on the remote-signer code side? so that when we don't have a kubeconfig to restart pods, we can still get the thing to work?

@OisinKyne
Copy link
Copy Markdown
Contributor

Screenshot 2026-04-24 at 16 58 50 Screenshot 2026-04-24 at 16 59 14 Screenshot 2026-04-24 at 17 00 16

@bussyjd bussyjd marked this pull request as draft April 24, 2026 16:38
@bussyjd
Copy link
Copy Markdown
Collaborator Author

bussyjd commented Apr 24, 2026

Context on this PR:

The original bug is flow/test setup: flow-11 was letting Bob's remote-signer use a generated throwaway wallet, then funding that wallet. What we actually need is for Bob to use deterministic derived wallet #2, because that is the wallet the flow already funds/checks.

That said, adding obol openclaw wallet import-private-key creates a real user-facing wallet lifecycle path, so the UX/security concerns are valid. Replacing an instance wallet touches key retention, metadata, password secrets, and remote-signer reload behavior. We should keep those semantics conservative rather than baking in test-only assumptions.

I think the right shape is:

  • keep the deterministic flow fix: Bob uses derived wallet Add helm to obolup #2; no throwaway-wallet funding path
  • rename the command to wallet import if we keep a user-facing command
  • avoid silently pruning unrelated keystores; either leave old keystores alone or make deletion explicit and logged
  • factor the shared wallet post-provisioning steps so restore/import do not drift
  • treat remote-signer hot reload as a follow-up unless it is required for this PR, since that likely belongs in remote-signer/API behavior rather than the flow script

I'm also checking whether flow-11 can be set up better by creating/provisioning Bob's desired wallet first, so this PR may not need as much user-facing wallet-import surface area.

@bussyjd
Copy link
Copy Markdown
Collaborator Author

bussyjd commented Apr 24, 2026

Follow-up from checking the flow setup: there is a cleaner shape that avoids replacing a live remote-signer wallet.

stack up eventually calls openclaw.SetupDefault, and that path respects an existing config/applications/openclaw/obol-agent deployment directory plus existing wallet.json / values-remote-signer.yaml. So flow-11 can pre-seed Bob's desired wallet before the default OpenClaw instance is deployed.

Preferred patch shape:

  • add an initial-wallet option to onboarding, e.g. obol openclaw onboard --id obol-agent --no-sync --wallet-private-key-file <file>
  • in flow-11, split Bob setup into stack init -> rewrite ports -> scaffold obol-agent with Bob's derived key -> stack up
  • then remote-signer starts with Bob's funded derived wallet; no post-start import, no rollout restart, and no live wallet replacement needed for the test
  • keep any live wallet import UX conservative or move it to a follow-up

That would better match the original test need: create the correct wallet first, instead of creating a generated wallet and then replacing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants