Skip to main content

Usage

const {
  updateWalletEncryption,
  updateWalletEncryptionAsync,
  data,
  isLoading,
  isError,
  error,
  isSuccess,
  reset,
} = useUpdateWalletEncryption();

Parameters

The mutation accepts an object with:
ParameterTypeRequiredDescription
externalUserIdstringYesYour app’s user ID
newEncryptedPrivateKeystringYesThe wallet private key re-encrypted with the new passkey or PIN
publicKeystringNoWallet public key; required when the user has multiple wallets
bearerTokenstringYesAuth token from your provider

Return Value

PropertyTypeDescription
updateWalletEncryption(input) => voidFire-and-forget update
updateWalletEncryptionAsync(input) => Promise<UpdateWalletEncryptionResponse>Promise-based update
dataUpdateWalletEncryptionResponse | undefinedResponse from the API
isLoadingbooleanTrue while the update is in progress
isErrorbooleanTrue if the update failed
isSuccessbooleanTrue if the update succeeded
errorError | nullError details
reset() => voidReset mutation state

UpdateWalletEncryptionResponse

PropertyTypeDescription
successbooleanWhether the update succeeded

How It Works

  1. The client re-encrypts the wallet private key with a new passkey or PIN
  2. updateWalletEncryption sends the new ciphertext to the Chipi backend
  3. The backend replaces the stored encrypted private key
  4. The wallet query cache is automatically invalidated so subsequent reads return fresh data
After calling this hook, any previous passkey or PIN used to encrypt the private key will no longer work. Make sure the new encryption is persisted before discarding the old key material.

Example Implementation

import { useUpdateWalletEncryption } from "@chipi-stack/chipi-react";
import { usePasskeySetup } from "@chipi-stack/chipi-passkey/hooks";
import { useAuth } from "@clerk/nextjs";

export function RotatePasskey({ wallet, userId }: {
  wallet: WalletData;
  userId: string;
}) {
  const { getToken } = useAuth();
  const { setupPasskey } = usePasskeySetup();
  const {
    updateWalletEncryptionAsync,
    isLoading,
    isSuccess,
    error,
  } = useUpdateWalletEncryption();

  const handleRotate = async () => {
    const bearerToken = await getToken();
    if (!bearerToken) return;

    try {
      // Create a new passkey (triggers biometric prompt)
      const newEncryptKey = await setupPasskey();

      // Re-encrypt the private key client-side with the new key.
      // Keep plaintext key material in-memory only — never log or persist it.
      const newEncryptedPrivateKey = encrypt(
        wallet.privateKey,
        newEncryptKey
      );

      await updateWalletEncryptionAsync({
        externalUserId: userId,
        newEncryptedPrivateKey,
        publicKey: wallet.publicKey,
        bearerToken,
      });

      alert("Passkey rotated successfully!");
    } catch (err) {
      console.error("Failed to rotate passkey:", err);
    }
  };

  return (
    <div>
      <button onClick={handleRotate} disabled={isLoading}>
        {isLoading ? "Updating..." : "Rotate Passkey"}
      </button>
      {isSuccess && <p>Encryption updated.</p>}
      {error && <p>Error: {error.message}</p>}
    </div>
  );
}