Social recovery

How to recover a wallet using recovery

What is a recovery

Users of Cometh Connect will generate and use a Safe as their wallet, with exclusive ownership and access to the funds it contains. Nonetheless, in the event of a lost key (such as misplacing their device or any other unforeseen circumstance), we aim to facilitate user's recovery of wallet access without compromising their security or self-custody. To achieve this, we have implemented a default feature in any Safe deployed to allow a guardian to initiate a recovery request. Upon the completion of a recovery request, the ownership structure of the Safe will be modified.

Our decentralized recovery model implementation is based on Safe{RecoveryHub}.

For now, the recovery process works with Cometh as guardian.

We have a default settings of 24h for recovery cooldown period and 7 days for recovery expiration.

Prerequesites

Before initiating a recovery request, the following conditions are assumed to be met:

  • The application using Cometh SDK should have identified their users before starting any recovery procedure.

Recovery flow

A recovery request consists of three phases:

  1. Activate the recovery module: User need to activate the recovery module on his smart wallet (This has to be done only once per wallet)

  2. Creating a new passkey owner: end user must create a signer that will be the new owner of his lost wallet.

  3. User identification and submitting the recovery request: after identification of the user by the application, the recovery request can be created and sent to the guardian for signature.

  4. Finalizing the recovery request: after Cometh's verification, provided the cooldown period is over (24h by default), the request can be processed. This action effectively modifies the ownership structure of the user's Safe.

1. User activates the social recovery module

The wallet created by cometh connect does not have the module right away, the user need to activate it by signing a transaction. Here is the transaction:

import { ENTRYPOINT_ADDRESS_V07, createSafeSmartAccount, 
  createSmartAccountClient, 
  createComethPaymasterClient 
  } from "@cometh/connect-sdk-4337";
import { http } from "viem"
import { arbitrumSepolia } from "viem/chains";

const apiKey = process.env.COMETH_API_KEY;
const bundlerUrl = process.env.4337_BUNDLER_URL;
const rpcUrl = process.env.RPC_URL;
const chain = arbitrumSepolia


const smartAccount = await createSafeSmartAccount({
    apiKey,
    rpcUrl,
    entryPoint: ENTRYPOINT_ADDRESS_V07,
 });
 
const paymasterClient = await createComethPaymasterClient({
    transport: http(paymasterUrl),
    chain,
    rpcUrl,
    entryPoint: ENTRYPOINT_ADDRESS_V07
})
    
const smartAccountClient = createSmartAccountClient({
    account: smartAccount,
    entryPoint: ENTRYPOINT_ADDRESS_V07,
    chain,
    bundlerTransport: http(bundlerUrl),
    middleware: {
      sponsorUserOperation: paymasterClient.sponsorUserOperation,
      gasPrice: paymasterClient.gasPrice,
    }
})
        

await smartAccountClient.setUpRecoveryModule();

2. User creates a new owner for their wallet

In the case of lost access to the wallet, you can start a recovery procedure by calling the createNewSignerWithAccountAddress function from the SDK. It will return an object that contains the new signer that will be the new owner of your wallet.

const signer = await createNewSignerWithAccountAddress({
    apiKey: API_KEY_CONNECT,
    smartAccountAddress: smartAccount.account.address,
});

/*
In the case of passkeys, the signer object should look like:
{ 
    signerAddress: "0x...",
    deviceData: {
        browser: "Firefox",
        os: "macOS",
        platform: "desktop",
    };
    publicKeyId: "0x...";
    publicKeyX: "0x...";
    publicKeyY: "0x...";
}
*/

2. Submit the recovery request

Following the creation of the new owner, they can then initiate a recovery request. This process is similar to a "Forgot password" feature, requiring the user to specify the new addresses they wish to designate as the new owners of their Safe.

From a technical standpoint, after identification of the user at the application level, this is done by calling Cometh Connect API.

Recovery endpoints are protected with an apisecret, indicating that requests should be done from your backend for privacy concerns.

export const api = axios.create({
    baseURL:"https://api.4337.cometh.io"
});

api.defaults.headers.common["apisecret"] = process.env.COMETH_API_SECRET;

const body = {
    chainId: arbitrumSepolia.id
    walletAddress: smartAccount.account.address,
    newOwner: signer.signerAddress,
    publicKeyId: signer.publicKeyId,
    publicKeyX: signer.publicKeyX,
    publicKeyY: signer.publicKeyY,
    deviceData: signer.deviceData
};

await api.post("/recovery/start", body);

3. Finalize the recovery request

Once the 24h recovery period is over without the owner of the Safe canceling the recovery, the request can be finalized. This step does not require any signature and can be executed by any party. Either Cometh, the project or the user can finalize the request.

An easy way to finalize the recovery request is by calling Cometh Connect API:

export const api = axios.create({
    baseURL:"https://api.4337.cometh.io"
});

api.defaults.headers.common["apisecret"] = process.env.COMETH_API_SECRET;

const body = {
  chainId: arbitrumSepolia.id,
  walletAddress: WALLET_ADDRESS,
};
            
await api.post(`/recovery/finalize`, body);

Check if social recovery module is active

You can get the current recovery request using the isRecoveryActive method of the SDK.

Here is the method to call from the SDK:

// optional rpc url
const rpcUrl = YOUR_RPC_URL

await smartAccountClient.isRecoveryActive(rpcUrl);

/* returned params:
{
    isDelayModuleDeployed = true,
    guardianAddress = "0x..."
}
*/

Get a recovery Request

You can get the current recovery request using the getRecoveryRequest method of the SDK. You'll get the creation date of the request and the hash of the transaction.

Here is the method to call from the SDK:

// optional rpc url
const rpcUrl = YOUR_RPC_URL

await smartAccountClient.getRecoveryRequest(rpcUrl);

/* returned params:
{
    txCreatedAt = UNIX_TIMESTAMP,
    txHash = "0x..."
}
*/

Cancel a recovery request

If a recovery request is still in the cooldown period, the user can cancel it if he has access to a device with a valid signer. This is done using the SDK method cancelRecoveryRequest, triggering an onchain transaction that will cancel the recovery request.

// optional rpc url
const rpcUrl = YOUR_RPC_URL

await smartAccountClient.cancelRecoveryRequest(rpcUrl);

Last updated