Skip to main content

Recover Account using Candide Guardian

Learn how to recover your Safe account using Candide Guardian when you've lost access to your owner keys. This guide walks through the complete recovery process using email and SMS verification.

If you haven't set up Candide Guardian yet, check out the Add Candide Guardian guide first.

What You'll Need

Before starting the recovery process, ensure you have:

  • Access to registered recovery methods (email or SMS)
  • Safe account address you want to recover
  • New private key to replace the lost one
  • Recovery service access (Candide Guardian must be enabled)

Recovery Overview

The recovery process involves these key steps:

  1. Generate new owner key - Create replacement for lost key
  2. Request guardian signature - Initiate recovery through Guardian service
  3. Verify all channels - Confirm identity via ALL registered methods
  4. Execute recovery - Submit recovery transaction
  5. Finalize recovery - Complete ownership transfer after grace period

Quickstart

You can also fork the complete code and follow along.

Installation

npm i abstractionkit safe-recovery-service-sdk viem

Configure Environment

# Network Configuration
CHAIN_ID=11155111
BUNDLER_URL=https://api.candide.dev/public/v3/11155111
NODE_URL=https://ethereum-sepolia-rpc.publicnode.com

# Recovery Service URL
# Get access here: https://app.formbricks.com/s/brdzlw0t897cz3mxl3ausfb5
RECOVERY_SERVICE_URL=

Step 1: Initialize Recovery Service

import { RecoveryByCustodialGuardian } from "safe-recovery-service-sdk";
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';

const chainId = BigInt(process.env.CHAIN_ID as string);
const serviceUrl = process.env.RECOVERY_SERVICE_URL as string;

// Initialize recovery service
const custodialGuardianService = new RecoveryByCustodialGuardian(serviceUrl, chainId);

// Generate new owner key to replace the lost one
const newOwnerPrivateKey = generatePrivateKey();
const newOwner = privateKeyToAccount(newOwnerPrivateKey);

Step 2: Request Guardian Signature Challenge

Request a recovery signature from Candide Guardian:

// Request Candide Guardian signature for recovery
const signatureRequest = await custodialGuardianService.requestCustodialGuardianSignatureChallenge(
safeAccountAddress,
[newOwner.address], // New owner array
1 // New threshold
);

Step 3: Verify All Recovery Channels

You must verify ALL registered channels to complete recovery. Submit the OTP codes received:

// Find the email authentication challenge
const emailAuth = signatureRequest.auths.find(auth => auth.channel === 'email');

// Enter OTP from email
const emailOtp = "123456"; // Replace with actual OTP

const verificationResult = await custodialGuardianService.submitCustodialGuardianSignatureChallenge(
signatureRequest.requestId,
emailAuth.challengeId,
emailOtp
);

Step 4: Execute Recovery Transaction

After verifying all channels, execute the recovery with the obtained guardian signature:

// Execute recovery using the service
const recoveryRequest = await custodialGuardianService.createAndExecuteRecoveryRequest(
safeAccountAddress,
[newOwner.address], // New owner array
1, // New threshold
verificationResult.custodianGuardianAddress as string,
verificationResult.custodianGuardianSignature as string
);

Step 5: Finalize Recovery After Grace Period

Wait for the grace period to expire, then finalize the recovery:

import { SocialRecoveryModuleGracePeriodSelector } from "abstractionkit";
import { RecoveryByGuardian } from "safe-recovery-service-sdk";

// Wait for grace period (3 minutes)
await new Promise(resolve => setTimeout(resolve, 3 * 60 * 1000));

// Initialize recovery service for finalization
const recoveryService = new RecoveryByGuardian(
serviceUrl,
chainId,
SocialRecoveryModuleGracePeriodSelector.After3Minutes
);

// Finalize the recovery
const finalizationResult = await recoveryService.finalizeRecoveryRequest(recoveryRequest.id);