Onboarding atómico
Del concepto a la integración. Cada decisión tiene una razón.
Capacidad opt-in. El módulo de onboarding necesita auditoría independiente y validación de despliegue antes de ofrecerse en producción.
executeOnboardingBatch ejecuta dos o más llamadas como una sola UserOperation, con exactamente una ceremonia biométrica sobre la operación final.
El caso de uso típico: desplegar la cuenta, aprobar un importe exacto y ejecutar la compra, sin pedirle al usuario tres aprobaciones seguidas para algo que él percibe como una sola acción.
const result = await wallet.executeOnboardingBatch({
intentId: crypto.randomUUID(), // un solo uso, emitido por tu backend
chainId: deployment.chainId,
sender: wallet.address,
nonce: accountNonce,
calls: [
{ to: token, value: "0", data: approveExactAmount },
{ to: router, value: "0", data: executeQuotedAction },
],
expiresAt: Math.floor(Date.now() / 1000) + 300,
deployAccount: false, // true solo para la primera operación
});El módulo revierte el batch entero si una llamada falla. No existe un estado donde el approve tuvo éxito y la acción siguiente no.
El método no acepta skipBiometric, ni un testigo, ni una aserción aportada por la aplicación.
Es una capacidad opt-in y no modifica cuentas existentes. Requiere que el deployment usado al crear la wallet incluyera la dirección del módulo de batch; si falta, la llamada aborta antes de abrir WebAuthn. Habilitar un módulo Safe privilegiado es una decisión de seguridad que exige auditoría independiente, dirección verificada por red y aprobación explícita: Nyx no proporciona una dirección por defecto ni lo activa al instalar el SDK.
Validación en el backend del integrador#
El SDK publica un validador puro, sin ninguna API de firma, para que tu backend contraste lo que recibe contra el intent que emitió:
import {
assertUserOperationMatchesOnboardingIntent,
hashOnboardingIntent,
} from "nyx_wallet/onboarding";
// Al emitir: persiste el intent canónico, su hash, usuario, sesión y wallet, con TTL corto.
const intentHash = hashOnboardingIntent(intent);
// Antes de retransmitir: compara igualdad, no reinterpretes la calldata.
assertUserOperationMatchesOnboardingIntent({ intent, userOperation, deployment });El deployment lo carga tu backend desde su propio registro por chainId. No se acepta desde el navegador: el validador demuestra correspondencia dentro de una configuración de confianza, no convierte una configuración manipulada en una garantía.
El consumo del intent debe ser atómico: issued → submitted una sola vez, guardando el userOpHash. Un reintento del mismo intent devuelve ese mismo hash; nunca se firma ni se retransmite una segunda operación.
