# Complete Recovery Flow Guide

Learn how to implement a complete account recovery flow using guardians and the Safe Recovery Service. This guide assumes you have a Safe account with the recovery module enabled and guardians configured.

> To set up the recovery module, see [Enable Recovery Module and Add Guardians](https://docs.candide.dev/wallet/plugins/how-to-add-a-guardian.md).

## Overview[​](#overview "Direct link to Overview")

The recovery flow consists of four key steps:

1. **Recovery Request**: Create and submit a recovery request
2. **Guardian Approval**: Collect required guardian signatures
3. **Execution**: Execute recovery after collecting all signatures
4. **Finalization**: Complete ownership transfer after the grace period expires

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

### Installation[​](#installation "Direct link to Installation")

* npm
* yarn

```
npm i abstractionkit safe-recovery-service-sdk viem
```

```
yarn add abstractionkit safe-recovery-service-sdk
```

1. `abstractionkit` provides the core functionality for interacting with social recovery module smart contracts and constructing calldata.
2. `safe-recovery-service-sdk` adds optional API services including alerts, recovery via email/SMS, and additional recovery features.
3. `viem` provides the ethereum library utils to generate private keys and sign transactions. You can also use `ethers`.

### Environment Setup[​](#environment-setup "Direct link to Environment Setup")

.env

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

GUARDIAN_1_PRIVATE_KEY=
GUARDIAN_2_PRIVATE_KEY=
```

## Recovery Steps[​](#recovery-steps "Direct link to Recovery Steps")

> Fork the [recovery example](https://github.com/candidelabs/safe-recovery-service-sdk/tree/main/examples/03-recovery-flow) to follow along.

### Step 1: Initialize Services[​](#step-1-initialize-services "Direct link to Step 1: Initialize Services")

Initialize the recovery service and guardian references.

About the Recovery Service

The [Candide Recovery Service](https://docs.candide.dev/wallet/recovery/overview.md) is an optional hosted service that streamlines recovery by automatically executing recovery after collecting required guardian signatures and finalizing it after the grace period expires. Request access to the recovery service [here](https://app.formbricks.com/s/brdzlw0t897cz3mxl3ausfb5).

**Alternative**: Anyone can [execute](https://docs.candide.dev/blog/making-accounts-recoverable#multi-confirm-recovery) and [finalize](https://docs.candide.dev/blog/making-accounts-recoverable#finalize-recovery) recovery transactions directly using Social Recovery Module methods, which are public and callable once guardian signatures are collected and grace period requirements are met.

initialize-services.ts

```
import {
  SafeAccountV0_3_0 as SafeAccount,
  SocialRecoveryModule,
  SocialRecoveryModuleGracePeriodSelector,
} from "abstractionkit";
import { RecoveryByGuardian } from "safe-recovery-service-sdk";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";

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

const smartAccountAddress = "0x...";
const newOwnerAddress = "0x...";

const guardian1PrivateKey = process.env.GUARDIAN_1_PRIVATE_KEY as `0x${string}`;
const guardian1Account = privateKeyToAccount(guardian1PrivateKey);
const guardian2PrivateKey = process.env.GUARDIAN_2_PRIVATE_KEY as `0x${string}`;
const guardian2Account = privateKeyToAccount(guardian2PrivateKey);

const srm = new SocialRecoveryModule(SocialRecoveryModuleGracePeriodSelector.After3Minutes);

const recoveryService = new RecoveryByGuardian(
  recoveryServiceURL,
  chainId,
  SocialRecoveryModuleGracePeriodSelector.After3Minutes
);
```

### Step 2: Create Recovery Request[​](#step-2-create-recovery-request "Direct link to Step 2: Create Recovery Request")

* First guardian signs EIP-712 recovery data
* Guardian 1 submits the recovery request with their signature (on-chain or through the service)
* Service generates a unique emoji sequence for this recovery request

recovery-request.ts

```
import { TypedDataDomain } from 'viem';
import { EXECUTE_RECOVERY_PRIMARY_TYPE } from "abstractionkit"

const nodeUrl = process.env.NODE_URL as string;

const recoveryRequestEip712Data = await srm.getRecoveryRequestEip712Data(
    nodeUrl,
    chainId,
    smartAccountAddress,
    [newOwnerAddress],
    1n
);

const guardian1Signature = await guardian1Account.signTypedData({
    primaryType: EXECUTE_RECOVERY_PRIMARY_TYPE,
    domain: recoveryRequestEip712Data.domain as TypedDataDomain,
    types: recoveryRequestEip712Data.types,
    message: recoveryRequestEip712Data.messageValue
});

const recoveryRequest = await recoveryService.createRecoveryRequest(
    smartAccountAddress,
    [newOwnerAddress],
    1n,
    guardian1Account.address,
    guardian1Signature
);
```

### Step 3: Second Guardian Signature[​](#step-3-second-guardian-signature "Direct link to Step 3: Second Guardian Signature")

The second guardian and each consecutive guardian must sign the recovery request using EIP-712 signatures:

guardian-signatures.ts

```
const guardian2Signature = await guardian2Account.signTypedData({
    primaryType: EXECUTE_RECOVERY_PRIMARY_TYPE,
    domain: recoveryRequestEip712Data.domain as TypedDataDomain,
    types: recoveryRequestEip712Data.types,
    message: recoveryRequestEip712Data.messageValue
});

await recoveryService.submitGuardianSignatureForRecoveryRequest(
    recoveryRequest.id,
    guardian2Account.address,
    guardian2Signature
);
```

### Step 4: Execute Recovery[​](#step-4-execute-recovery "Direct link to Step 4: Execute Recovery")

Once all guardian signatures are collected or the threshold is met, the service executes the recovery to initiate the grace period:

recovery-execution.ts

```
await recoveryService.executeRecoveryRequest(recoveryRequest.id);

await new Promise(resolve => setTimeout(resolve, 1 * 30 * 1000)); // wait for tx to be included

const executedRequest = await recoveryService.getExecutedRecoveryRequestForLatestNonce(
    nodeUrl,
    smartAccountAddress
);

if (executedRequest && executedRequest.status === "EXECUTED") {
    console.log("Transaction hash:", executedRequest.executeData.transactionHash);
}
```

### Step 5: Finalize Recovery[​](#step-5-finalize-recovery "Direct link to Step 5: Finalize Recovery")

After the grace period has elapsed, anyone can finalize the recovery. Here's how to use the recovery service:

recovery-finalization.ts

```
const finalizationResult = await recoveryService.finalizeRecoveryRequest(
  recoveryRequest.id
);

const pendingRequests = await recoveryService.getPendingRecoveryRequestsForLatestNonce(
    nodeUrl,
    smartAccountAddress
);
```

## Complete Working Example[​](#complete-working-example "Direct link to Complete Working Example")

Full Recovery Flow Example

examples/03-recovery-flow/index.ts

```
loading...
```

[See full example on GitHub](https://github.com/candidelabs/safe-recovery-service-sdk/blob/main/examples/03-recovery-flow/index.ts)

## What's Next[​](#whats-next "Direct link to What's Next")

* [Recovery Alerts Guide](https://docs.candide.dev/wallet/plugins/recovery-alerts-guide.md): set up email and SMS notifications so account owners are alerted if a recovery is ever initiated
* [Enable Email / SMS Recovery](https://docs.candide.dev/wallet/plugins/add-candide-guardian.md): use Candide's managed guardian service instead of self-managed guardian keys

## Security Considerations[​](#security-considerations "Direct link to Security Considerations")

### Emoji Verification[​](#emoji-verification "Direct link to Emoji Verification")

Candide Recovery Service provides an emoji-based communication system enabling guardians to verify and approve legitimate recovery requests.

* **Unique Verification**: Each recovery request generates a unique emoji sequence
* **Anti-Phishing**: Prevents malicious recovery attempts through social engineering
* **Guardian Verification**: Guardians must verify the emoji with the account owner before signing
* **Secure Communication**: Share emojis only through trusted, encrypted channels

### Signatures[​](#signatures "Direct link to Signatures")

* **EIP-712**: All signatures use typed data for replay protection
* **Domain Separation**: Signatures are chain-specific
* **Nonce Protection**: Each recovery request includes a unique nonce

### Grace Period[​](#grace-period "Direct link to Grace Period")

* **Sufficient Duration**: Allow adequate time for legitimate owners to cancel unauthorized recovery attempts
* **Monitoring**: Implement notification systems to alert owners of recovery attempts, such as [Candide's Alert System](https://docs.candide.dev/wallet/recovery/ux-api/.md#alerts)

## Utility Methods[​](#utility-methods "Direct link to Utility Methods")

Common utilities you might find helpful:

```
// Check guardian status
const isGuardian = await srm.isGuardian(
  nodeUrl,
  smartAccountAddress,
  guardianAddress
);

if (!isGuardian) {
  throw new Error("Address is not a configured guardian");
}

// Verify threshold
const threshold = await srm.threshold(
  nodeUrl,
  smartAccountAddress
);

console.log(`Required guardian signatures: ${threshold}`);
```
