IBExWalletAPI
Advanced

Wallet Recovery

๐Ÿ” Recovery Feature

๐Ÿ“‹ Overview

The recovery feature allows users to enable a wallet recovery mechanism for their Safe wallet in case of access loss. This feature includes:

  • Recovery activation: Configuration of a recovery address with a delay and collection of personal data
  • Recovery execution: Ownership transfer after delay expiration (administrative operation)
  • Recovery cancellation: Ability to cancel a recovery in progress

๐Ÿ—๏ธ Architecture

Smart Contract: RecoveryModule

The RecoveryModule contract manages all recovery logic:

contract RecoveryModule {
    struct RecoveryConfig {
        address recoveryAddress;
        uint256 delay;
        uint256 activationTime;
        bool isActive;
        string description;
    }
    
    mapping(address => RecoveryConfig) public recoveryConfigs;
    mapping(address => uint256) public pendingRecoveries;
}

๐Ÿ“ฆ Deployed Contracts

Original Contract (Deprecated)

  • Address: 0xa7480cc788b42dEF5F7dd979Bf9ce539CFB93DD9
  • Network: Arbitrum Sepolia
  • Status: Deprecated - do not use
  • Issue: Function signature with onlySafe(safe) that caused execution errors

Current Contract (Production)

  • Address: 0x13Ba85EC17A55BE3354bC540814D97e420b9f8C8
  • Network: Arbitrum Sepolia
  • Status: Active - used in production
  • Verified: โœ… Verified on Arbiscan
  • Improvement: Simplified signature using msg.sender instead of parameter

Differences Between Contracts

AspectOriginal ContractCurrent Contract
enableRecovery signatureenableRecovery(safe, recoveryAddress, delay, description)enableRecovery(recoveryAddress, delay, description)
cancelRecovery signaturecancelRecovery(safe)cancelRecovery()
disableRecovery signaturedisableRecovery(safe)disableRecovery()
ModifieronlySafe(safe)Uses msg.sender directly
CompatibilityโŒ Execution issuesโœ… Works correctly

Why Two Contracts?

  1. Initial problem: The first contract had a function signature that caused "Execution failed" errors when called from the Safe
  2. Solution: Simplified signature by using msg.sender instead of passing the Safe address as a parameter
  3. Migration: Deployment of a new contract with the corrected signature

๐Ÿ”ง Verification Scripts

Status Check Script

# Check the recovery status of a Safe
node scripts/check-recovery-status.js

Features:

  • Recovery configuration verification
  • Display of delay and recovery address
  • Verification if recovery can be executed
  • Automatic connection to Arbitrum Sepolia

Example output:

๐Ÿ” Checking recovery status...

๐Ÿ“ก Connected to Arbitrum Sepolia
๐Ÿ“‹ RecoveryModule contract: 0x13Ba85EC17A55BE3354bC540814D97e420b9f8C8
๐Ÿ  Safe to check: 0x261Af4c45335F15636A32e59F42ae5FcCc4351E3

โœ… Recovery can be executed: false

๐Ÿ“Š Recovery configuration:
   Recovery address: 0x303f215950f7B07Ae45FD98590d503E0242E7de3
   Delay: 86400 seconds (1 day)
   Activation time: 2025-06-18T15:32:18.000Z
   Active: true
   Description: Recovery wallet for emergency access

โœ… Recovery enabled for this Safe!
โณ Recovery enabled but not yet initiated

Deployment Script

# Deploy the RecoveryModule contract
npx hardhat run smartcontracts/scripts/deploy-recovery-module.js --network arbitrumSepolia

Arbiscan Verification Script

# Verify the contract on Arbiscan
npx hardhat verify --network arbitrumSepolia 0x13Ba85EC17A55BE3354bC540814D97e420b9f8C8

๐Ÿ” Arbiscan Verification

Verified Contract

Available Read Functions

  • getRecoveryConfig(address safe): Retrieve recovery configuration
  • canExecuteRecovery(address safe): Check if recovery can be executed
  • recoveryConfigs(address safe): Mapping of configurations
  • pendingRecoveries(address safe): Mapping of pending recoveries

Available Write Functions

  • enableRecovery(address recoveryAddress, uint256 delay, string description): Enable recovery
  • disableRecovery(): Disable recovery
  • initiateRecovery(address safe): Initiate the recovery process
  • cancelRecovery(): Cancel a recovery in progress
  • executeRecovery(address safe, address[] newOwners, uint256 threshold): Execute recovery

API Endpoints

1. Recovery Activation

POST /v1.2/safes/operations
{
  "safeAddress": "0x...",
  "operations": [
    {
      "type": "ENABLE_RECOVERY",
      "firstName": "John",
      "lastName": "Doe",
      "birthDate": "1990-01-01",
      "birthCity": "Paris",
      "birthCountry": "France"
    }
  ]
}

Response:

{
  "credentialRequestOptions": {
    "challenge": "base64url_encoded_userOpHash",
    "rpId": "ibex.fi.staging",
    "userVerification": "required"
  }
}

2. Recovery Cancellation

POST /v1.2/safes/operations
{
  "safeAddress": "0x...",
  "operations": [
    {
      "type": "CANCEL_RECOVERY"
    }
  ]
}

3. Recovery Execution (Administrative)

POST /system/recovery/execute
Headers: {
  "X-API-Key": "your-api-key"
}
{
  "safeAddress": "0x...",
  "newOwners": ["0x...", "0x..."],
  "threshold": 1
}

โš ๏ธ Internal administrative endpoint - Only the Ibex team can use this endpoint.

๐Ÿ”„ Workflow

1. Recovery Activation

  1. User configures their personal data via the ENABLE_RECOVERY operation
  2. API uses environment variables for recovery address and delay
  3. Message is signed with passkey
  4. Transaction is executed on the smart contract with the new signature
  5. Recovery is activated with the default delay (86400 seconds = 1 day)
  6. Personal data is saved to the database

2. Recovery Cancellation

  1. Current owners can cancel via the CANCEL_RECOVERY operation
  2. Message is signed with passkey
  3. Transaction is executed on the smart contract
  4. Recovery process is stopped
  5. Safe remains under control of current owners

3. Recovery Execution (Administrative)

  1. After delay expiration, the Ibex team can execute recovery
  2. New owners are defined
  3. Safe is transferred to new owners
  4. Operation is recorded in the database

๐Ÿ›ก๏ธ Security

Delay Constraints

  • Minimum: 1 day (86400 seconds)
  • Maximum: 30 days (2592000 seconds)
  • Default: 1 day (configured via RECOVERY_DEFAULT_DELAY)

Permissions

  • Activation: Only Safe owners
  • Execution: Only Ibex team (administrative endpoint)
  • Cancellation: Only current owners

Verifications

  • Ethereum address validation
  • Delay verification
  • Permission checks
  • Mandatory passkey signature
  • Personal data validation
  • API_KEY authentication for administrative execution

๐Ÿ“Š Database

Added Operation Types

-- New types in OperationType enum
ENABLE_RECOVERY
CANCEL_RECOVERY
EXECUTE_RECOVERY

Data Structure

Each recovery operation is recorded in the Operation table with:

  • Type: Recovery operation type
  • Parameters: Personal data (firstName, lastName, birthDate, etc.)
  • Encoded data: Blockchain transaction

๐Ÿš€ Deployment

1. Deploy Smart Contract

npx hardhat run smartcontracts/scripts/deploy-recovery-module.js --network arbitrumSepolia

2. Verify Contract on Arbiscan

npx hardhat verify --network arbitrumSepolia <CONTRACT_ADDRESS>

3. Update Contract Address

# In .env.staging
RECOVERY_CONTRACT=0x13Ba85EC17A55BE3354bC540814D97e420b9f8C8

4. Deploy API

# Quick API-only deployment
bash docker/scripts/deploy-api-staging.sh
 
# Or full deployment
bash docker/scripts/deploy-staging.sh

๐Ÿงช Testing

Unit Tests

npx hardhat test smartcontracts/test/recovery.test.js --config smartcontracts/hardhat.config.js

Integration Tests

npm run test:integration

Manual Verification

# Check Safe status
node smartcontracts/scripts/check-recovery-status.js
 
# Test recovery endpoints
node scripts/test-recovery-endpoints.js

๐Ÿ“ Usage

Complete Example

// 1. Enable recovery
const enableRecovery = await fetch('/v1.2/safes/operations', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${token}` },
  body: JSON.stringify({
    safeAddress: '0x261Af4c45335F15636A32e59F42ae5FcCc4351E3',
    operations: [{
      type: 'ENABLE_RECOVERY',
      firstName: 'John',
      lastName: 'Doe',
      birthDate: '1990-01-01',
      birthCity: 'Paris',
      birthCountry: 'France'
    }]
  })
});
 
// 2. Sign operation with passkey
const credential = await startAuthentication({
  optionsJSON: enableRecovery.credentialRequestOptions
});
 
const submitRecovery = await fetch('/v1.2/safes/operations', {
  method: 'PUT',
  headers: { 'Authorization': `Bearer ${token}` },
  body: JSON.stringify({
    credential: credential
  })
});
 
// 3. Check status
// Use check-recovery-status.js script or Arbiscan
 
// 4. Administrative execution (after delay expiration)
// This step is performed by the Ibex team via the /system/recovery/execute endpoint

๐Ÿ”ง Configuration

Environment Variables

# RecoveryModule contract address (PRODUCTION)
RECOVERY_CONTRACT=0x13Ba85EC17A55BE3354bC540814D97e420b9f8C8

# Default delay (in seconds) - 1 day
RECOVERY_DEFAULT_DELAY=86400

# Recovery wallet address
RECOVERY_ADDRESS=0x303f215950f7B07Ae45FD98590d503E0242E7de3

# Network configuration
ARBITRUM_SEPOLIA_RPC_URL=https://sepolia-rollup.arbitrum.io/rpc
ARBISCAN_API_KEY=your-arbiscan-api-key

Permissions

// Authorized operations for locked users
const LOCKED_AUTHORIZED_OPERATIONS = {
  [Lock.SOFT]: [
    OperationType.TRANSFER_EURe,
    OperationType.ENABLE_RECOVERY,
    OperationType.CANCEL_RECOVERY
  ]
}

๐ŸŽฏ Future Features

  • Multi-level recovery: Multiple recovery addresses
  • Notifications: Alerts on activation/initiation
  • Social recovery: Recovery via trusted contacts
  • Advanced timelock: Progressive delays
  • Conditional recovery: Based on specific events
  • User interface: Dashboard to manage recoveries
  • History: Complete traceability of recovery operations