Skip to content

feat(lit-api-server): unsigned POST /prepare_wallet derived-address endpoint#576

Open
clawdbot-glitch003 wants to merge 3 commits into
mainfrom
glitch003/derived-wallet-address-endpoint
Open

feat(lit-api-server): unsigned POST /prepare_wallet derived-address endpoint#576
clawdbot-glitch003 wants to merge 3 commits into
mainfrom
glitch003/derived-wallet-address-endpoint

Conversation

@clawdbot-glitch003

Copy link
Copy Markdown
Collaborator

What

Adds POST /core/v1/prepare_wallet — the no-signature equivalent of create_wallet_with_signature. It returns a freshly derived { wallet_address, derivation_path } with no EIP-712 signature and no API key, so a ChainSecured client can obtain a PKP address before registering it on-chain and fold the whole owner ceremony into a single signed bind UserOp.

Addresses the Chipotle "derived-wallet-address endpoint" side of flows#532:

  • New EVM wallet: 3 → 1 passkey prompts
  • First exchange connect: 2 → 1

Why this is safe (and why it's just a new endpoint)

The existing *_with_signature "mint" endpoints don't mint anything on-chain — they generate a random derivation path, derive the key deterministically from the TEE/dstack KDF, and return the address. The client does the real authorization step itself: an on-chain registerWalletDerivation inside its owner-signed UserOp. The EIP-712 signature authorizes nothing durable — it only gates the mint API's shape and is trivially self-signed. Dropping it removes UX friction, not a security check. An un-registered response is equivalent to a discarded keypair (compute-only cost).

The xpub/client-side-derivation alternative was ruled out: the current derivation is hardened-KDF (no EC structure to retrofit), and Chipotle exports derived secrets as usage API keys, so a published xpub + one leaked child key would compromise the whole tree.

Design choices

  • Server-generated path only (not client-supplied). Guarantees 256-bit CSPRNG entropy and sidesteps the cross-account path-collision vector in the security issue below.
  • Unauthenticated, matching its _with_signature siblings — the ChainSecured ceremony has no API key at this point.
  • CpuAvailable load-shedding guard (same one lit_action uses): since it's unauthenticated and drives a dstack KDF call per request, this bounds an anonymous caller under CPU saturation.
  • NOT idempotent — documented prominently: every call mints a new wallet, retries return a different address, concurrent callers each get their own wallet with no server-side dedup. There is no collision risk (independent 256-bit paths), only non-idempotency.

Changes

  • prepare_wallet() handler + PrepareWalletResponse model, route + OpenAPI registration.
  • e2e test (e2e/tests/api/prepare-wallet.spec.ts) + client method: asserts well-formed address/path and non-idempotency.
  • Docs: new POST /prepare_wallet section in docs/management/api_direct.mdx with the concurrency Warning.
  • Plan: plans/prepare-wallet-endpoint.md.

Codex adversarial review

Ran codex challenge (high). 3 findings, all addressed:

  1. [P1] Unauthenticated unthrottled KDF trigger (DoS) → added the CpuAvailable guard.
  2. [P1] On-chain registration isn't a robust auth boundary (cross-account path hijack) → this is pre-existing and independent of this endpoint (paths/addresses are already public); corrected the code comment to stop implying it's airtight and cross-referenced the issue. Filed separately as Security: public derivation paths + per-account-only uniqueness let any account hijack another account's PKP wallet #575.
  3. [P2] Docs overclaimed "no collision / clean revert" → reworded to "cryptographically negligible" and clarified the revert is per-account.

Testing

  • cargo check -p lit-api-server passes.
  • Playwright e2e not run here (needs a live server) — please run against a dev instance before merge.

Follow-ups (out of scope)

🤖 Generated with Claude Code

… endpoint

Adds the no-signature equivalent of `create_wallet_with_signature`: returns a
freshly derived `{wallet_address, derivation_path}` with no EIP-712 signature
and no API key, so a ChainSecured client can obtain a PKP address before
registering it on-chain and collapse the owner ceremony into a single signed
bind UserOp (flows#532: new EVM wallet 3->1 prompts, first exchange connect
2->1).

The EIP-712 signature on the sibling endpoint authorizes nothing durable (it
only gates the mint API's shape and is trivially self-signed); the real
attach step is the client's own on-chain `registerWalletDerivation`. Dropping
it removes UX friction, not a security check.

Server generates the derivation path (256-bit CSPRNG); clients cannot supply
their own, which avoids low-entropy keys and the cross-account path-collision
vector tracked in chipotle#575. The endpoint carries the same `CpuAvailable`
load-shedding guard as `lit_action` since it is unauthenticated and drives a
dstack KDF call per request.

Docs + code comments call out that the endpoint is NOT idempotent: every call
mints a new wallet, retries return a different address, and concurrent callers
each get their own wallet with no server-side dedup.

Codex adversarial review: DoS exposure (added CpuAvailable guard), auth-boundary
overclaim (corrected comment, cross-ref #575), collision-doc overclaim (reworded).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clawdbot-glitch003
clawdbot-glitch003 requested a review from a team July 14, 2026 19:13
@mintlify

mintlify Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
chipotle 🟢 Ready View Preview Jul 14, 2026, 7:13 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@mintlify

mintlify Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
chipotle-dev 🟢 Ready View Preview Jul 14, 2026, 7:13 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

glitch003 and others added 2 commits July 15, 2026 11:44
Adds the prepare_wallet operation to spec.json and the generated k6
TypeScript client, fixing the openapi-to-k6 drift CI check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Pass `derivation_path` verbatim into `registerWalletDerivation(adminHash, wallet_address, derivation_path, name, description)` on the AccountConfig contract — until that lands, the PKP exists in MPC but is not registered to any account.

<Note>

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 want any additional documentation around "why" you might do this ?

It's very much a flows thing ATM ...

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.

3 participants