---
title: Recover a Safe Account with Google using AbstractionKit (Guide 2/2)
description: Learn how to offer a recovery option for your users using AbstractinKit
image: /img/posters/abstractionkit-meta.png
keywords: [mpc,hosted-wallets,social-login, abstractionkit, recovery-module]
---
# Recover a Safe Account with Google using AbstractionKit (Guide 2/2)
This is the second of two guides on how to recovery a Safe Account using Google. In the first guide, we show the steps on how to add the recovery method. We recommend starting with the first guide here.
## What is AbstractionKit?
[AbstractionKit](https://docs.candide.dev/wallet/abstractionkit/introduction/) is a Typescript Library to easily build on Account Abstraction, with first class support for Safe Accounts. One of their usecases is to enable users to add recovery methods as a backup in case their use their main signer.
To leverage the full potential of Account Abstraction, you can combine Lit with AbstractionKit to enable email / social recovery experience, while using a Smart Account as the smart wallet to sponsor gas for users, batch transactions, and more.
## Relevant Links
For additional information during this guide:
- [How on-chain guardian recovery works](https://docs.candide.dev/wallet/plugins/recovery-with-guardians/)
- [Guardian Recovery SDK Reference](https://docs.candide.dev/blog/making-accounts-recoverable/)
- [Simple Recovery example on GitHub](https://github.com/candidelabs/abstractionkit/tree/experimental/examples/SafeAccountExamples/SocialRecovery)
- [Lit Documentation Website](https://developer.litprotocol.com/)
## Installation
### Install required dependencies
```bash
npm i abstractionkit@0.1.12 && @lit-protocol/lit-auth-client
```
### Configure .env file
Configure the values you created from Lit dashboard in an .env file
```ts
// Lit
LIT_API_KEY=Request Relay Server API Key from Lit at https://forms.gle/RNZYtGYTY9BcD9MEA
// Candide
BUNDLER_URL="https://sepolia.voltaire.candidewallet.com/rpc" // Other networks are found here: https://docs.candide.dev/wallet/bundler/rpc-endpoints
PAYMASTER_URL="Request an API key from Candide on Discord"
// Generate a Public/Private Key
OWNER_PUBLIC_ADDRESS=
OWNER_PRIVATE_KEY=
NEW_OWNER_PUBLIC_ADDRESS=
// Network Info
VITE_CHAIN_ID=
JSON_RPC_NODE_PROVIDER= // "Get an RPC from a Node provider"
```
## Sign in with Google using Lit
### Initialize the Lit client and provider
- Connect to the Lit Network using LitNodeClient.
- Set up the LitAuthClient for authentication.
- Initialize a GoogleProvider for Google sign-in.
```ts
import { LitNodeClient } from "@lit-protocol/lit-node-client";
import { LitAuthClient, GoogleProvider } from "@lit-protocol/lit-auth-client";
import { ProviderType } from "@lit-protocol/constants";
const initalizeClientsAndProvider = async () => {
const litNodeClient = new LitNodeClient({
litNetwork: "datil-dev",
debug: true,
});
await litNodeClient.connect();
const litAuthClient = new LitAuthClient({
litRelayConfig: {
relayApiKey: process.env.LIT_API_KEY,
},
litNodeClient,
});
console.log("Connected to Lit Node and Lit Auth Clients ✔️");
const provider = litAuthClient.initProvider<GoogleProvider>(
ProviderType.Google,
{
//redirectUri: VITE_REDIRECT_URI,
}
);
return { litNodeClient, litAuthClient, provider };
};
```
### Authentication with Gmail
- Generate Authentication Method
- Check if the user is already authenticated. If not, redirect to Google sign-in
```ts
import { AuthMethod } from "@lit-protocol/types";
const generateAuthMethod = async () => {
const url = new URL(window.location.href);
if (!url.searchParams.get("provider")) {
console.log("Signing in with Google...");
provider.signIn((url) => {
window.location.href = url;
});
} else if (url.searchParams.get("provider") === "google") {
const authMethod = await provider.authenticate();
return authMethod;
}
};
const authMethod = await generateAuthMethod();
if (!authMethod) {
return;
}
```
### Mint PKP (Programmable Key Pair)
```ts
import { LitAuthClient } from "@lit-protocol/lit-auth-client";
const mintWithGoogle = async (authMethod) => {
const pkp = await litAuthClient.mintPKPWithAuthMethods([authMethod], {
addPkpEthAddressAsPermittedAddress: true
});
console.log("Fetched PKP", pkp);
return pkp;
};
const pkp = await mintWithGoogle(authMethod);
console.log("Minted PKP ✔️");
```
### Get the Google Guardian Signer
```ts
import { PKPEthersWallet } from "@lit-protocol/pkp-ethers";
import { LitAbility, LitPKPResource } from "@lit-protocol/auth-helpers";
import { AuthCallbackParams } from "@lit-protocol/types";
const authNeededCallback = async (params: AuthCallbackParams) => {
console.log(`auth needed callback params`, JSON.stringify(params, null, 2));
const response = await litNodeClient.signSessionKey({
statement: params.statement,
authMethods: [authMethod],
resourceAbilityRequests: [
{
resource: new LitPKPResource("*"),
ability: LitAbility.PKPSigning,
},
],
expiration: params.expiration,
resources: params.resources,
chainId: 1,
pkpPublicKey: pkp.pkpPublicKey,
});
console.log("AUTHSIG", response);
return response.authSig;
};
const guardianSigner = new PKPEthersWallet({
litNodeClient,
authContext: {
getSessionSigsProps: {
chain: "ethereum",
expiration: new Date(Date.now() + 60_000 * 60).toISOString(),
resourceAbilityRequests: [
{
resource: new LitPKPResource("*"),
ability: LitAbility.PKPSigning,
},
],
authNeededCallback: authNeededCallback,
},
},
pkpPubKey: pkp.pkpPublicKey,
rpc: "https://yellowstone-rpc.litprotocol.com",
});
console.log("Created PKPEthersWallet using the PKP ✔️");
```
## Start the Recovery Process
### Initilize the Safe Account Class
```ts
import { SafeAccountV0_2_0 as SafeAccount } from "abstractionkit";
const smartAccount = SafeAccount.initializeNewAccount([ownerPublicAddress]);
console.log("Smart Account Address: ", smartAccount.accountAddress);
```
### Repare The Recovery Transaction
```ts
import { SocialRecoveryModule } from "abstractionkit";
const srm = new SocialRecoveryModule();
const initiateRecoveryMetaTx = srm.createConfirmRecoveryMetaTransaction(
smartAccount.accountAddress,
[newOwnerPublicAddress],
1, // new threshold
true // whether to auto-start execution of recovery
);
let userOperationRecovery = await guardianSmartAccount.createUserOperation(
[initiateRecoveryMetaTx],
process.env.JSON_RPC_NODE_PROVIDER,
process.env.BUNDLER_URL
);
```
### Sponsor the Gas
```ts
import { CandidePaymaster } from "abstractionkit";
import ethers from "ethers"
// Sponsor the recovery transaction using the paymaster
const paymasterUrl = process.env.PAYMASTER_URL;
const paymaster = new CandidePaymaster(paymasterUrl);
userOperationRecovery = await paymaster.createSponsorPaymasterUserOperation(
userOperationRecovery,
process.env.BUNDLER_URL
);
```
### Sign and Submit UserOperation
```ts
// Sign
const domain = {
chainId: process.env.CHAIN_ID,
verifyingContract: smartAccount.safe4337ModuleAddress,
};
const types = SafeAccount.EIP712_SAFE_OPERATION_TYPE;
// formate according to EIP712 Safe Operation Type
const { sender, ...userOp } = userOperation;
const safeUserOperation = {
...userOp,
safe: userOperation.sender,
validUntil: BigInt(0),
validAfter: BigInt(0),
entryPoint: smartAccount.entrypointAddress,
};
const signature = await guardianSigner.signTypedData(domain, types, safeUserOperation);
const formatedSig = SafeAccount.formatEip712SignaturesToUseroperationSignature([ownerPublicAddress], [signature]);
userOperationRecovery.signature = signature;
// Submit
const sendUserOpResponseRecovery =
await guardianSmartAccount.sendUserOperation(
userOperationRecovery,
process.env.BUNDLER_URL
);
```
### Monitor UserOp
```ts
// Wait for receipt
const userOpReceiptResultRecovery = await sendUserOpResponseRecovery.included();
console.log(userOpReceiptResultRecovery);
```
## Finalize the Recovery
After the grace period is over, you can finilize the recovery
### Prepare the Finilization UserOp
```ts
const finalizeRecoveryMetaTx = srm.createFinalizeRecoveryMetaTransaction(
smartAccount.accountAddress
);
let userOperationFinalizeRecovery = await guardianSmartAccount.createUserOperation(
[finalizeRecoveryMetaTx],
process.env.JSON_RPC_NODE_PROVIDER,
process.env.BUNDLER_URL
);
```
### Sponsor the Gas
```ts
// Add gas sponsorship info using paymaster
userOperationFinalizeRecovery = await paymaster.createSponsorPaymasterUserOperation(
userOperationRecovery,
process.env.BUNDLER_URL
);
```
### Sign and Submit
```ts
// Sign userOperation
const domain = {
chainId: process.env.CHAIN_ID,
verifyingContract: smartAccount.safe4337ModuleAddress,
};
const types = SafeAccount.EIP712_SAFE_OPERATION_TYPE;
// formate according to EIP712 Safe Operation Type
const { sender, ...userOp } = userOperation;
const safeUserOperation = {
...userOp,
safe: userOperation.sender,
validUntil: BigInt(0),
validAfter: BigInt(0),
entryPoint: smartAccount.entrypointAddress,
};
const signature = await guardianSigner.signTypedData(domain, types, safeUserOperation);
const formatedSig = SafeAccount.formatEip712SignaturesToUseroperationSignature([ownerPublicAddress], [signature]);
userOperationRecovery.signature = signature;
// Submit userOperation
const sendUserOperationResponseRecovery = await guardianSmartAccount.sendUserOperation(
userOperationRecovery,
process.env.BUNDLER_URL
);
```
### Monitor UserOperation
```ts
const userOperationReceiptResultRecovery = await sendUserOperationResponseRecovery.included();
console.log(userOperationReceiptResultRecovery);
```
---
That's it! You've successfully added a Guardian capable of recovering an account with a Google Account using Lit.
Find here the complete [doc page for Account Recovery](https://docs.candide.dev/wallet/plugins/recovery-with-guardians).
---