import { type SmartAccountAuthenticator, type AuthorizationRequest } from "@aa-sdk/core"; import { type GetTransactionType, type Hex, type IsNarrowable, type LocalAccount, type SerializeTransactionFn, type SignableMessage, type SignedAuthorization, type TransactionSerializable, type TransactionSerialized, type TypedData, type TypedDataDefinition } from "viem"; import type { BaseSignerClient } from "./client/base"; import { type MfaFactor, type OauthConfig, type User, type VerifyMfaParams, type AddMfaParams, type AddMfaResult, type RemoveMfaParams, type AuthLinkingPrompt, type OauthProviderInfo, type AuthMethods } from "./client/types.js"; import { type SessionManagerParams } from "./session/manager.js"; import type { AuthParams } from "./signer"; import { SolanaSigner } from "./solanaSigner.js"; import { type AlchemySignerEvent, type AlchemySignerEvents, type ErrorInfo, type ValidateMultiFactorsArgs } from "./types.js"; export interface BaseAlchemySignerParams { client: TClient; sessionConfig?: Omit; initialError?: ErrorInfo; initialAuthLinkingPrompt?: AuthLinkingPrompt; } export type EmailConfig = { mode?: "MAGIC_LINK" | "OTP"; }; export type SignerConfig = { email: EmailConfig; }; type GetUserParams = { type: "email"; value: string; } | { type: "phone"; value: string; }; type VerificationParams = { verificationCode: string; }; /** * Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts. * Implements the `SmartAccountAuthenticator` interface and handles various signer events. */ export declare abstract class BaseAlchemySigner implements SmartAccountAuthenticator { signerType: "alchemy-signer" | "rn-alchemy-signer"; inner: TClient; private sessionManager; private store; private config; /** * Initializes an instance with the provided client and session configuration. * This function sets up the internal store, initializes the session manager, * registers listeners and initializes the session manager to manage session state. * * @param {BaseAlchemySignerParams} param0 Object containing the client and session configuration * @param {TClient} param0.client The client instance to be used internally * @param {SessionConfig} param0.sessionConfig Configuration for managing sessions * @param {ErrorInfo | undefined} param0.initialError Error already present on the signer when initialized, if any */ constructor({ client, sessionConfig, initialError, initialAuthLinkingPrompt, }: BaseAlchemySignerParams); /** * Allows you to subscribe to events emitted by the signer * * @param {AlchemySignerEvent} event the event to subscribe to * @param {AlchemySignerEvents[AlchemySignerEvent]} listener the function to run when the event is emitted * @returns {() => void} a function to remove the listener */ on: (event: E, listener: AlchemySignerEvents[E]) => () => void; /** * Prepares the config needed to use popup-based OAuth login. This must be * called before calling `.authenticate` with params `{ type: "oauth", mode: * "popup" }`, and is recommended to be called on page load. * * This method exists because browsers may prevent popups from opening unless * triggered by user interaction, and so the OAuth config must already have * been fetched at the time a user clicks a social login button. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * await signer.preparePopupOauth(); * ``` * @returns {Promise} the config which must be loaded before * using popup-based OAuth */ preparePopupOauth: () => Promise; /** * Authenticate a user with either an email or a passkey and create a session for that user * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const result = await signer.authenticate({ * type: "email", * email: "foo@mail.com", * }); * ``` * * @param {AuthParams} params - undefined if passkey login, otherwise an object with email and bundle to resolve * @returns {Promise} the user that was authenticated */ authenticate: (params: AuthParams) => Promise; private trackAuthenticateType; /** * Clear a user session and log them out * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * await signer.disconnect(); * ``` * * @returns {Promise} a promise that resolves when the user is logged out */ disconnect: () => Promise; /** * Gets the current logged in user * If a user has an ongoing session, it will use that session and * try to authenticate * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * // throws if not logged in * const user = await signer.getAuthDetails(); * ``` * * @throws if there is no user logged in * @returns {Promise} the current user */ getAuthDetails: () => Promise; /** * Retrieves the address of the current user by calling the `whoami` method on `this.inner`. * * @returns {Promise} A promise that resolves to the address of the current user. */ getAddress: () => Promise<`0x${string}`>; /** * Signs a raw message after hashing it. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const signature = await signer.signMessage("Hello, world!"); * ``` * * @param {string} msg the message to be hashed and then signed * @returns {Promise} a promise that resolves to the signed message */ signMessage: (msg: SignableMessage) => Promise<`0x${string}`>; /** * Signs a typed message by first hashing it and then signing the hashed message using the `signRawMessage` method. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const signature = await signer.signTypedData({ * domain: {}, * types: {}, * primaryType: "", * message: {}, * }); * ``` * * @param {TypedDataDefinition} params The parameters for the typed message to be hashed and signed * @returns {Promise} A promise that resolves to the signed message */ signTypedData: , TPrimaryType extends keyof TTypedData | "EIP712Domain" = keyof TTypedData>(params: TypedDataDefinition) => Promise; /** * Serializes a transaction, signs it with a raw message, and then returns the serialized transaction with the signature. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const tx = await signer.signTransaction({ * to: "0x1234", * value: "0x1234", * data: "0x1234", * }); * ``` * * @param {Transaction} tx the transaction to be serialized and signed * @param {{serializer?: SerializeTransactionFn}} args options for serialization * @param {() => Hex} [args.serializer] an optional serializer function. If not provided, the default `serializeTransaction` function will be used * @returns {Promise} a promise that resolves to the serialized transaction with the signature */ signTransaction: = SerializeTransactionFn, transaction extends Parameters[0] = Parameters[0]>(transaction: transaction, options?: { serializer?: serializer | undefined; } | undefined) => Promise>, Hex> extends true ? TransactionSerialized> : Hex>; /** * Signs an EIP-7702 Authorization and then returns the authorization with the signature. * * @example * ```ts twoslash * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const tx = await signer.signAuthorization({ * contractAddress: "0x1234123412341234123412341234123412341234", * chainId: 1, * nonce: 0, * }); * ``` * * @param {AuthorizationRequest} unsignedAuthorization the authorization to be signed * @returns {Promise> | undefined} a promise that resolves to the authorization with the signature */ signAuthorization: (unsignedAuthorization: AuthorizationRequest) => Promise>; /** * Gets the current MFA status * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const mfaStatus = signer.getMfaStatus(); * if (mfaStatus === AlchemyMfaStatus.REQUIRED) { * // Handle MFA requirement * } * ``` * * @returns {{ mfaRequired: boolean; mfaFactorId?: string }} The current MFA status */ getMfaStatus: () => { mfaRequired: boolean; mfaFactorId?: string; }; /** * Unauthenticated call to look up a user's organizationId by email * * @deprecated Use getUser({ type: "email", value: email }) instead * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const result = await signer.getUser("foo@mail.com"); * ``` * * @param {string} email the email to lookup * @returns {Promise<{orgId: string}>} the organization id for the user if they exist */ getUser(email: string): Promise<{ orgId: string; } | null>; /** * Unauthenticated call to look up a user's organizationId by email or phone * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const result = await signer.getUser({ type: "email", value: "foo@mail.com" }); * ``` * * @param {string} email the email to lookup * @returns {Promise<{orgId: string}>} the organization id for the user if they exist */ getUser(params: GetUserParams): Promise<{ orgId: string; } | null>; /** * Sets the email for the authenticated user, allowing them to login with that * email. * * @deprecated You must contact Alchemy to enable this feature for your team, * as there are important security considerations. In particular, you must not * call this without first validating that the user owns this email account. * It is recommended to now use the email verification flow instead. * * @param {string} email The email to set for the user * @returns {Promise} A promise that resolves to the updated email address * @throws {NotAuthenticatedError} If the user is not authenticated */ setEmail(email: string): Promise; /** * Uses a verification code to update a user's email, allowing them to login * with that email. `sendVerificationCode` should be called first to obtain * the code. * * @param {VerificationParams} params An object containing the verification code * @param {string} params.verificationCode The OTP verification code * @returns {Promise} A promise that resolves to the updated email address * @throws {NotAuthenticatedError} If the user is not authenticated */ setEmail(params: VerificationParams): Promise; /** * Removes the email for the authenticated user, disallowing them from login with that email. * * @returns {Promise} A promise that resolves when the email is removed * @throws {NotAuthenticatedError} If the user is not authenticated */ removeEmail: () => Promise; /** * Sets the phone number for the authenticated user, allowing them to login with that * phone number. `sendVerificationCode` should be called first to obtain the code. * * @param {VerificationParams} params An object containing the verification code * @param {string} params.verificationCode The OTP verification code * @returns {Promise} A promise that resolves when the phone number is set * @throws {NotAuthenticatedError} If the user is not authenticated */ setPhoneNumber: (params: VerificationParams) => Promise; /** * Removes the phone number for the authenticated user, disallowing them from login with that phone number. * * @returns {Promise} A promise that resolves when the phone number is removed * @throws {NotAuthenticatedError} If the user is not authenticated */ removePhoneNumber: () => Promise; /** * Initiates an OTP (One-Time Password) verification process for a user contact. * Use this method before calling `setEmail` with verification code to verify ownership of the email address. * * @param {"email" | "sms"} type The type of OTP to send, either "email" or "sms" * @param {string} contact The email address or phone number to send the OTP to * @returns {Promise<{ otpId: string }>} A promise that resolves to an object containing the OTP ID * @throws {NotAuthenticatedError} If the user is not authenticated */ sendVerificationCode: (type: "email" | "sms", contact: string) => Promise<{ otpId: string; }>; /** * Adds a passkey to the user's account * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const result = await signer.addPasskey() * ``` * * @param {CredentialCreationOptions | undefined} params optional parameters for the passkey creation * @returns {Promise} an array of the authenticator ids added to the user */ addPasskey: (params?: CredentialCreationOptions) => Promise; /** * Removes a passkey from a user's account * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const authMethods = await signer.listAuthMethods(); * const passkey = authMethods.passkeys[0]; * * const result = await signer.removePasskey(passkey.authenticatorId); * ``` * * @param {CredentialCreationOptions | undefined} params optional parameters for the passkey creation * @returns {Promise} an array of the authenticator ids added to the user */ removePasskey: (authenticatorId: string) => Promise; getPasskeyStatus: () => Promise<{ isPasskeyAdded: boolean; }>; /** * Used to export the wallet for a given user * If the user is authenticated with an Email, this will return a seed phrase * If the user is authenticated with a Passkey, this will return a private key * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * // the params passed to this are different based on the specific signer * const result = signer.exportWallet() * ``` * * @param {unknown} params exportWallet parameters * @returns {Promise} the result of the wallet export operation */ exportWallet: TClient["exportWallet"]; /** * Exports a private key for a given account * * @param {ExportPrivateKeyParams} opts the parameters for the export * @returns {Promise} the private key */ exportPrivateKey: TClient["exportPrivateKey"]; /** * Exports a private key for a given account encrypted with the provided public key * * @param {ExportPrivateKeyParams} opts the parameters for the export * @returns {Promise} the private key */ exportPrivateKeyEncrypted: TClient["exportPrivateKeyEncrypted"]; /** * This method lets you adapt your AlchemySigner to a viem LocalAccount, which * will let you use the signer as an EOA directly. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const account = signer.toViemAccount(); * ``` * * @throws if your signer is not authenticated * @returns {LocalAccount} a LocalAccount object that can be used with viem's wallet client */ toViemAccount: () => LocalAccount; /** * Creates a new instance of `SolanaSigner` using the provided inner value. * This requires the signer to be authenticated first * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const solanaSigner = signer.toSolanaSigner(); * ``` * * @returns {SolanaSigner} A new instance of `SolanaSigner` */ toSolanaSigner: () => SolanaSigner; private authenticateWithEmail; private authenticateWithSms; private authenticateWithPasskey; private authenticateWithOauth; /** * Handles OAuth authentication by augmenting the provided arguments with a type and performing authentication based on the OAuth mode (either using redirect or popup). * * @param {Omit, "type">} args Authentication parameters omitting the type, which will be set to "oauth" * @returns {Promise} A promise that resolves to an `OauthProviderInfo` object containing provider information and the ID token. */ addOauthProvider: (args: Omit, "type">) => Promise; /** * Removes an OAuth provider by its ID if the user is authenticated. * * @param {string} providerId The ID of the OAuth provider to be removed, as obtained from `listOauthProviders` * @returns {Promise} A promise indicating the result of the removal process * @throws {NotAuthenticatedError} Thrown if the user is not authenticated */ removeOauthProvider: (providerId: string) => Promise; /** * Retrieves a list of auth methods associated with the authenticated user. * * @returns {Promise} A promise that resolves to an `AuthMethods` object containing the user's email, OAuth providers, and passkeys. * @throws {NotAuthenticatedError} Thrown if the user is not authenticated */ listAuthMethods: () => Promise; private authenticateWithJwt; private authenticateWithOtp; private setAwaitingEmailAuth; private setAwaitingSmsAuth; private handleOauthReturn; private handleMfaRequired; private getExpirationSeconds; private registerListeners; private emitNewUserEvent; private initOrCreateEmailUser; private initOrCreateSmsUser; private completeEmailAuth; /** * Retrieves the list of MFA factors configured for the current user. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const { multiFactors } = await signer.getMfaFactors(); * ``` * * @throws {NotAuthenticatedError} If no user is authenticated * @returns {Promise<{ multiFactors: Array }>} A promise that resolves to an array of configured MFA factors */ getMfaFactors: () => Promise<{ multiFactors: MfaFactor[]; }>; /** * Initiates the setup of a new MFA factor for the current user. * The factor will need to be verified using verifyMfa before it becomes active. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const result = await signer.addMfa({ multiFactorType: "totp" }); * // Result contains multiFactorTotpUrl to display as QR code * ``` * * @param {AddMfaParams} params The parameters required to enable a new MFA factor * @throws {NotAuthenticatedError} If no user is authenticated * @returns {Promise} A promise that resolves to the factor setup information */ addMfa: (params: AddMfaParams) => Promise; /** * Verifies a newly created MFA factor to complete the setup process. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const result = await signer.verifyMfa({ * multiFactorId: "factor-id", * multiFactorCode: "123456" // 6-digit code from authenticator app * }); * ``` * * @param {VerifyMfaParams} params The parameters required to verify the MFA factor * @throws {NotAuthenticatedError} If no user is authenticated * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors */ verifyMfa: (params: VerifyMfaParams) => Promise<{ multiFactors: MfaFactor[]; }>; /** * Removes existing MFA factors by their IDs. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * const result = await signer.removeMfa({ * multiFactorIds: ["factor-id-1", "factor-id-2"] * }); * ``` * * @param {RemoveMfaParams} params The parameters specifying which factors to disable * @throws {NotAuthenticatedError} If no user is authenticated * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors */ removeMfa: (params: RemoveMfaParams) => Promise<{ multiFactors: MfaFactor[]; }>; /** * Validates MFA factors that were required during authentication. * This function should be called after MFA is required and the user has provided their MFA code. * It completes the authentication process by validating the MFA factors and completing the auth bundle. * * @example * ```ts * import { AlchemyWebSigner } from "@account-kit/signer"; * * const signer = new AlchemyWebSigner({ * client: { * connection: { * rpcUrl: "/api/rpc", * }, * iframeConfig: { * iframeContainerId: "alchemy-signer-iframe-container", * }, * }, * }); * * // After MFA is required and user provides code * const user = await signer.validateMultiFactors({ * multiFactorCode: "123456", // 6-digit code from authenticator app * multiFactorId: "factor-id" * }); * ``` * * @param {ValidateMultiFactorsArgs} params - Parameters for validating MFA factors * @throws {Error} If there is no pending MFA context or if orgId is not found * @returns {Promise} A promise that resolves to the authenticated user */ validateMultiFactors(params: ValidateMultiFactorsArgs): Promise; protected initConfig: () => Promise; /** * Returns the signer configuration while fetching it if it's not already initialized. * * @returns {Promise} A promise that resolves to the signer configuration */ getConfig: () => Promise; protected fetchConfig: () => Promise; private setAuthLinkingPrompt; private waitForConnected; } export {}; //# sourceMappingURL=base.d.ts.map