From fd7de0fdd9ebe685d983168a1f9f6ea2d3236029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Ram=C3=ADrez?= Date: Fri, 24 Jul 2026 19:32:32 -0300 Subject: [PATCH] fix(step-up): stop prompting where the flow already proves the passkey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit withdraw/prepare is followed by the admin EIP-712 the passkey must sign, and session-approve's payload is itself a passkey enable signature — the step-up assertion before them proved nothing extra and turned every collateral-funded send into three fingerprint prompts (the triple-prompt reports). PAN/CVV/PIN and bank-add keep step-up: there the cookie is the only proof. Pairs with peanut-api-ts dropping requireStepUp from the same routes; backend deploys first (enforcement would 401 clients that stop sending the header). --- src/services/rain.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/services/rain.ts b/src/services/rain.ts index 946a845f81..89d1e83c26 100644 --- a/src/services/rain.ts +++ b/src/services/rain.ts @@ -429,12 +429,15 @@ export const rainApi = { /** * Persist the serialized ZeroDev permission on the user's card so the * backend can submit session-key UserOps for collateral withdrawals. + * + * No step-up: the payload is itself a fresh passkey signature (the grant + * ceremony's enable sig) — an extra assertion here just doubles the + * fingerprint prompts on the grant flow. */ submitWithdrawSessionApproval: async (input: { serializedApproval: string }): Promise => { await rainRequest<{ ok: boolean }>({ method: 'POST', path: '/rain/cards/withdraw/session-approve', - stepUp: true, body: input, }) }, @@ -443,12 +446,16 @@ export const rainApi = { * Stage a Rain V2 withdrawal: backend fetches Rain's executor signature, * reads the current adminNonce from the collateral proxy, and persists a * short-lived prep record. Caller then signs the admin EIP-712 payload. + * + * No step-up: a prep is inert until the passkey produces the admin + * EIP-712 signature that follows it, so the flow proves user presence on + * its own. Step-up here made every collateral-funded send cost three + * fingerprint prompts instead of two (the 2026-07 triple-prompt reports). */ prepareWithdrawal: async (input: PrepareRainWithdrawalInput): Promise => { return rainRequest({ method: 'POST', path: '/rain/cards/withdraw/prepare', - stepUp: true, body: input, }) },