> For the complete documentation index, see [llms.txt](https://docs.t-rex.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.t-rex.network/reference/identity-suite/recoverymodule.md).

# RecoveryModule

`RecoveryModule` lets the Guardians of an identity give it a new `MANAGEMENT` key when its owner lost every key. Guardians sign a recovery, the module schedules it, and anyone executes it once a delay has elapsed. The contract is OpenZeppelin's `ERC7579SocialRecoveryExecutor`, deployed unchanged: a delayed executor with a weighted multisignature. The concept is in [Account abstraction and recovery](/identity-onchainid/account-abstraction-and-recovery.md).

### At a glance

|                           |                                                                                                                               |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **Source**                | `contracts/modules/executors/RecoveryModule.sol`, which inherits `ERC7579SocialRecoveryExecutor`                              |
| **Module type**           | Executor (ERC-7579, type 2)                                                                                                   |
| **Deployed as**           | One contract per network. It stores the Guardians, weights, threshold, delay and expiration of each identity that installs it |
| **Needs on the identity** | To be installed as an executor, and to hold a key of type `MODULE` with the purpose `MANAGEMENT`                              |
| **Defaults**              | Expiration of 60 days (`defaultExpiration()`). A change of delay is spread over at most 5 days (`delayChangeWindow()`)        |

### Installation

The module is installed with `Identity.installModule(2, recoveryModule, initData)`. `initData` is the two-byte length of the executor arguments, the executor arguments `abi.encodePacked(uint32 delay, uint32 expiration)`, the two-byte length of the guardian arguments, and the guardian arguments `abi.encode(bytes[] guardians, uint64 threshold, uint64[] weights)`.

| Check at installation                                        | Reverts with                                                                |
| ------------------------------------------------------------ | --------------------------------------------------------------------------- |
| The identity has no settings in the module                   | `ERC7579DelayedExecutorAlreadyInstalled`, `ERC7579MultisigAlreadyInstalled` |
| The guardian arguments decode and list at least one Guardian | `ERC7579MultisigInvalidInitData`, `ERC7579MultisigEmptySigners`             |
| Each Guardian is at least 20 bytes long and listed once      | `ERC7579MultisigInvalidSigner`, `ERC7579MultisigAlreadyExists`              |
| One weight per Guardian, none of them zero                   | `ERC7579MultisigMismatchedLength`, `ERC7579MultisigInvalidWeight`           |
| The threshold is above zero and within the total weight      | `ERC7579MultisigZeroThreshold`, `ERC7579MultisigUnreachableThreshold`       |

Uninstalling the module clears the Guardians, the weights, the threshold and the scheduling settings of the identity. Guide: [28 Install the recovery module and manage guardians](/guides/identity/28.-install-the-recovery-module-and-manage-guardians.md).

### Recovery

| Function                                                             | Access                                                                | Reverts with                                                                                                                                                                                                                                                                 |
| -------------------------------------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `startRecovery(identity, salt, mode, recoveryData, multisignature)`  | Anyone carrying signatures of Guardians that reach the threshold      | `ERC7579SocialRecoveryExecutorInvalidSchedule` for an invalid bundle or weights below the threshold, `ERC7579ExecutorModuleNotInstalled`, `ERC7579ExecutorUnexpectedOperationState` when the same operation was already scheduled. Emits `ERC7579ExecutorOperationScheduled` |
| `cancelRecovery(identity, salt, mode, recoveryData)`                 | The identity                                                          | `ERC7579SocialRecoveryExecutorInvalidCancel`. Emits `ERC7579ExecutorOperationCanceled`                                                                                                                                                                                       |
| `cancelRecovery(identity, salt, mode, recoveryData, multisignature)` | Anyone carrying signatures of Guardians over the cancellation message | The same                                                                                                                                                                                                                                                                     |
| `executeRecovery(identity, salt, mode, recoveryData)`                | Anyone                                                                | `ERC7579ExecutorUnexpectedOperationState` unless the operation is `Ready`. `ExecutorPurposeNotAuthorized`, from the identity, when the module lacks the purpose the target requires                                                                                          |

* **Signatures are scoped.** Guardians sign in the ERC-712 domain of the identity they recover. A signature made to schedule cannot cancel, and the reverse.
* **An operation is used once.** A cancelled or executed operation cannot be scheduled again with the same salt.

Guide: [21 Recover access to an ONCHAINID](/guides/identity/21.-recover-access-to-an-onchainid.md).

#### State of an operation

`state(account, salt, mode, executionCalldata)` and `state(operationId)` return one of six values.

| State       | Meaning                                                                 |
| ----------- | ----------------------------------------------------------------------- |
| `Unknown`   | Never scheduled                                                         |
| `Scheduled` | Scheduled, the delay has not elapsed                                    |
| `Ready`     | The delay has elapsed and the expiration has not passed: it can execute |
| `Expired`   | The expiration has passed                                               |
| `Executed`  | Executed                                                                |
| `Canceled`  | Cancelled                                                               |

`hashOperation(account, salt, mode, executionCalldata)` gives the `operationId`. `getSchedule` returns `scheduledAt`, `executableAt` and `expiresAt`, by parameters or by `operationId`.

### Settings

Each function changes the settings of its caller, so the identity makes the call: see step 5 of guide 28.

| Function                               | Reverts with                                                                                                                                 | Effect                                                                                                                                                                                                           |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `addGuardians(guardians)`              | `ERC7579MultisigInvalidSigner`, `ERC7579MultisigAlreadyExists`                                                                               | At once. Emits `ERC7913SignerAdded`. A new Guardian has the weight 1                                                                                                                                             |
| `removeGuardians(guardians)`           | `ERC7579MultisigNonexistentSigner`, `ERC7579MultisigUnreachableThreshold`                                                                    | At once. Emits `ERC7913SignerRemoved`                                                                                                                                                                            |
| `setSignerWeights(guardians, weights)` | `ERC7579MultisigMismatchedLength`, `ERC7579MultisigNonexistentSigner`, `ERC7579MultisigInvalidWeight`, `ERC7579MultisigUnreachableThreshold` | At once. Emits `ERC7579MultisigWeightChanged`                                                                                                                                                                    |
| `setThreshold(threshold)`              | `ERC7579MultisigZeroThreshold`, `ERC7579MultisigUnreachableThreshold`                                                                        | At once. Emits `ERC7913ThresholdSet`                                                                                                                                                                             |
| `setExpiration(expiration)`            |                                                                                                                                              | At once. Emits `ERC7579ExecutorExpirationUpdated`                                                                                                                                                                |
| `setDelay(delay)`                      |                                                                                                                                              | Not at once. A longer delay takes effect after the new delay, capped at 5 days. A shorter delay takes effect after the difference between the current delay and the new one. Emits `ERC7579ExecutorDelayUpdated` |

### Reads

| View                                                               | Returns                                                                 |
| ------------------------------------------------------------------ | ----------------------------------------------------------------------- |
| `getGuardians(identity, start, end)`, `getGuardianCount(identity)` | The Guardians of an identity                                            |
| `signerWeight(identity, guardian)`, `totalWeight(identity)`        | The weight of a Guardian (0 when it is not one), the sum of the weights |
| `threshold(identity)`                                              | The weight a bundle of signatures must reach                            |
| `getDelay(identity)`                                               | The current delay, the pending one and the time it takes effect         |
| `getExpiration(identity)`                                          | How long a scheduled operation stays executable after its delay         |

### Events

| Event                                                                                              | Emitted when                                                              |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `ERC7579ExecutorOperationScheduled(account, operationId, salt, mode, executionCalldata, schedule)` | A recovery is scheduled. `schedule` is the time from which it can execute |
| `ERC7579ExecutorOperationCanceled(account, operationId)`                                           | A recovery is cancelled                                                   |
| `ERC7579ExecutorDelayUpdated`, `ERC7579ExecutorExpirationUpdated`                                  | A scheduling setting changes                                              |
| `ERC7913SignerAdded`, `ERC7913SignerRemoved`                                                       | A Guardian is added, removed                                              |
| `ERC7913ThresholdSet`                                                                              | The threshold changes                                                     |
| `ERC7579MultisigWeightChanged(address indexed account, bytes indexed signer, uint64 weight)`       | A weight changes. Not emitted for the default weight of a new Guardian    |

> **Trust statement.** Guardians whose weights reach the threshold can take control of the identity after the delay. The delay is the owner's protection: an owner who still holds a `MANAGEMENT` key cancels a recovery it did not ask for.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.t-rex.network/reference/identity-suite/recoverymodule.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
