# IWalletKeyManager

> Protocol Managed Wallet key generation, confirmation, and TEE routing.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

Source: https://dev.flare.network/fcc/reference/IWalletKeyManager

Public interface for `WalletKeyManagerFacet` on the [`FlareTeeManager`](/fcc/reference/IFlareTeeManager) diamond.

This facet manages the **keys** of a [Protocol Managed Wallet (PMW)](/fcc/overview#protocol-managed-wallets-pmw): which TEE machines hold each key, the wallet's multisig threshold, and how payment flows pick receiving machines. Create the project and wallet first with [`IWalletProjectManager`](/fcc/reference/IWalletProjectManager) and [`IWalletManager`](/fcc/reference/IWalletManager). Only setup mutations require wallet status `INITIALIZED`: `setMultisigThreshold`, `addKey`, and the first `confirmKey` for a new key. `deleteKey`, `cleanUpTeeIds`, restore confirmations, and receiving-TEE helpers do not gate on `INITIALIZED`.

Key material never appears onchain. `addKey` and `deleteKey` only emit instructions; the private key is generated and stored inside the TEE. Someone must later call `confirmKey` with a TEE-signed existence proof before the public key is recorded on the diamond.

Typical lifecycle:

1.  The wallet project owner calls `addKey` on a `PRODUCTION` TEE that belongs to the wallet's extension. The facet sends an `F_WALLET` / `KEY_GENERATE` instruction and emits `WalletKeyAdded`.
2.  The TEE generates the key and returns a signed `KeyExistence` proof (domain prefix `TEE_KEY_EXISTENCE`).
3.  The owner (or backup manager, for restores) calls `confirmKey`. On success the diamond stores the public key and TEE id and emits `WalletKeyConfirmed`.
4.  Payment and reissue paths call `receivingTeesAndKeys` (or its read-only twin `getReceivingTeeIds`) to pick PRODUCTION machines that currently hold enough keys to meet `multisigThreshold`.

Nothing here is automatic: each step is an explicit call, and instructions still need data-provider weight (and any wallet cosigners) before the TEE executes them. See [Data providers and cosigners](/fcc/data-providers).

Inherits shared [`ITeeCommonErrors`](/fcc/reference/ITeeCommonErrors).

info

FCC and Protocol Managed Wallets are in the final stages of development. Prefer **Coston2** for examples and treat interfaces as subject to change.

## Constants[​](#constants "Direct link to Constants")

### `TEE_KEY_EXISTENCE`[​](#tee_key_existence "Direct link to tee_key_existence")

Domain prefix for the TEE-attested wallet-key-existence signed payload. The TEE identity key signs `ethSignedHash(TEE_KEY_EXISTENCE, keccak256(abi.encode(KeyExistence)))`. `confirmKey` recovers the signer and requires it equal `KeyExistence.teeId`.

```
bytes32 constant TEE_KEY_EXISTENCE = bytes32("TEE_KEY_EXISTENCE");
```

## Types[​](#types "Direct link to Types")

### `KeyConfigConstants`[​](#keyconfigconstants "Direct link to keyconfigconstants")

Admin public keys and cosigner set copied into generate/existence payloads so the TEE and onchain config stay aligned.

```
struct KeyConfigConstants {        PublicKey[] adminsPublicKeys;        uint64 adminsThreshold;        address[] cosigners;        uint64 cosignersThreshold;    }
```

### `KeyGenerate`[​](#keygenerate "Direct link to keygenerate")

ABI-encoded body of the `KEY_GENERATE` instruction sent by `addKey`.

```
struct KeyGenerate {        address teeId;        bytes32 walletId;        uint64 keyId;        bytes32 keyType;        bytes32 signingAlgo;        KeyConfigConstants configConstants;    }
```

### `KeyExistence`[​](#keyexistence "Direct link to keyexistence")

TEE-signed proof that a machine holds (or restored) a wallet key. Passed to `confirmKey`.

```
struct KeyExistence {        address teeId;        bytes32 walletId;        uint64 keyId;        bytes32 keyType;        bytes32 signingAlgo;        bytes publicKey;        uint256 nonce;        bool restored;        KeyConfigConstants configConstants;        bytes32 settingsVersion;        bytes settings;    }
```

### `KeyDelete`[​](#keydelete "Direct link to keydelete")

ABI-encoded body of the `KEY_DELETE` instruction sent by `deleteKey`.

```
struct KeyDelete {        address teeId;        bytes32 walletId;        uint64 keyId;        uint256 nonce;    }
```

### `TeeIdKeyIdPair`[​](#teeidkeyidpair "Direct link to teeidkeyidpair")

Pair returned by `receivingTeesAndKeys` for each PRODUCTION machine that currently holds a wallet key.

```
struct TeeIdKeyIdPair {        address teeId;        uint64 keyId;    }
```

### `PublicKey` / `Signature`[​](#publickey--signature "Direct link to publickey--signature")

Shared FCC structs (not facet-specific):

```
struct PublicKey {        bytes32 x;        bytes32 y;    }struct Signature {        uint8 v;        bytes32 r;        bytes32 s;    }
```

## Functions[​](#functions "Direct link to Functions")

### `setMultisigThreshold`[​](#setmultisigthreshold "Direct link to setmultisigthreshold")

Sets the multisig threshold for the wallet. Emits `WalletMultisigThresholdSet` event. Can only be called by the wallet project owner. The wallet must be `INITIALIZED`; `_multisigThreshold` must be greater than zero.

```
function setMultisigThreshold(        bytes32 _walletId,        uint64 _multisigThreshold    )        external
```

**Parameters**

-   `_walletId`: The wallet id.
-   `_multisigThreshold`: The multisig threshold (number of available keys required by `receivingTeesAndKeys`).

### `addKey`[​](#addkey "Direct link to addkey")

Adds a key to the wallet and triggers key generation on the target TEE. Emits `WalletKeyAdded`, then sends an `F_WALLET` / `KEY_GENERATE` instruction (payable; fee follows [`IOperationFees`](/fcc/reference/IOperationFees)). Can only be called by the wallet project owner. The wallet must be `INITIALIZED`, `_teeId` must be `PRODUCTION`, and the TEE's extension must match the wallet project's extension.

```
function addKey(        address _teeId,        bytes32 _walletId,        address _claimBackAddress    )        external payable        returns (uint64 _keyId)
```

**Parameters**

-   `_teeId`: The TEE machine that should generate and hold the key.
-   `_walletId`: The wallet id.
-   `_claimBackAddress`: An address that can claim back the fee if the instructions are not executed (optional).

**Returns**

-   `_keyId`: The newly assigned key id (from the wallet's `addKey` counter).

### `confirmKey`[​](#confirmkey "Direct link to confirmkey")

Confirms key generation (or restore) with a TEE-signed `KeyExistence` proof. Emits `WalletKeyConfirmed` event. Callable by the wallet project owner, or by the project backup manager on restore confirmations.

First confirmation (`nonce == 0`, `restored == false`) stores the public key and TEE id and requires wallet status `INITIALIZED`. Later re-introduction of the same key on another TEE requires `restored == true`, a matching public key, and a nonce greater than zero; that restore path does **not** require `INITIALIZED`.

```
function confirmKey(        KeyExistence calldata _proof,        Signature calldata _teeSignature    )        external
```

**Parameters**

-   `_proof`: The key existence proof.
-   `_teeSignature`: The TEE machine signature of the key existence proof (`TEE_KEY_EXISTENCE` domain).

### `deleteKey`[​](#deletekey "Direct link to deletekey")

Deletes a key from a TEE machine and triggers a key deletion instruction. Emits `WalletKeyDeleted`, then sends an `F_WALLET` / `KEY_DELETE` instruction (payable). Can only be called by the wallet project owner. Does **not** require wallet status `INITIALIZED` (unlike `addKey`), so it remains available after `enableWallet`. Removes `_teeId` from the key's holder list if present, increments that TEE's per-key nonce, and instructs the enclave to delete the material.

```
function deleteKey(        address _teeId,        bytes32 _walletId,        uint64 _keyId,        address _claimBackAddress    )        external payable
```

**Parameters**

-   `_teeId`: The TEE machine that should delete the key.
-   `_walletId`: The wallet id.
-   `_keyId`: The key id.
-   `_claimBackAddress`: An address that can claim back the fee if the instructions are not executed (optional).

### `cleanUpTeeIds`[​](#cleanupteeids "Direct link to cleanupteeids")

For a given wallet id and key id, removes every holder TEE that is **not** in `PRODUCTION`. Note: the key nonce is not incremented, so the key can be re-added to the same TEE later. Emits `WalletKeyDeleted` for each removed TEE id. Callable by the wallet project owner or backup manager.

```
function cleanUpTeeIds(        bytes32 _walletId,        uint64 _keyId    )        external
```

**Parameters**

-   `_walletId`: The wallet id.
-   `_keyId`: The key id.

### `receivingTeesAndKeys`[​](#receivingteesandkeys "Direct link to receivingteesandkeys")

Returns the wallet's receiving TEE and key pairs for dispatch (used by payment / reissue paths). Reverts with `ThresholdNotMet` if fewer than `multisigThreshold` keys have at least one `PRODUCTION` holder. If some keys have no PRODUCTION holder, emits `WalletKeysNotAvailable` for those key ids (the call still succeeds when the threshold is met).

```
function receivingTeesAndKeys(        bytes32 _walletId    )        external        returns (TeeIdKeyIdPair[] memory _teeIdKeyIdPairs)
```

**Parameters**

-   `_walletId`: The wallet id.

**Returns**

-   `_teeIdKeyIdPairs`: The `(teeId, keyId)` pairs for PRODUCTION holders.

### `getReceivingTeeIds`[​](#getreceivingteeids "Direct link to getreceivingteeids")

Read-only twin of `receivingTeesAndKeys`: the deduplicated list of TEE ids that would receive instructions for the wallet. Matches the TEE ids the dispatch path feeds into fee calculation, so [`IOperationFees.calculateFeeByTeeIds`](/fcc/reference/IOperationFees) (or `calculateFeeByWalletId`) applied to it yields the same fee a real `pay` / `reissue` charges. Reverts with `ThresholdNotMet` if not enough receiving TEEs are available, and emits no event (safe to call via `eth_call`).

```
function getReceivingTeeIds(        bytes32 _walletId    )        external view        returns (address[] memory _teeIds)
```

**Parameters**

-   `_walletId`: The wallet id.

**Returns**

-   `_teeIds`: The deduplicated list of receiving TEE ids.

### `getWalletKeyTeeIds`[​](#getwalletkeyteeids "Direct link to getwalletkeyteeids")

Returns the list of TEE ids that currently hold the wallet key.

```
function getWalletKeyTeeIds(        bytes32 _walletId,        uint64 _keyId    )        external view        returns (address[] memory _teeIds)
```

**Parameters**

-   `_walletId`: The wallet id.
-   `_keyId`: The key id.

**Returns**

-   `_teeIds`: The list of TEE ids.

### `getWalletKeyPublicKey`[​](#getwalletkeypublickey "Direct link to getwalletkeypublickey")

Returns the public key of the wallet key (empty until the first successful `confirmKey`).

```
function getWalletKeyPublicKey(        bytes32 _walletId,        uint64 _keyId    )        external view        returns (bytes memory _publicKey)
```

**Parameters**

-   `_walletId`: The wallet id.
-   `_keyId`: The key id.

**Returns**

-   `_publicKey`: The public key.

### `getKeyNonce`[​](#getkeynonce "Direct link to getkeynonce")

Returns the current per-`(teeId, walletId, keyId)` nonce and whether the TEE currently holds the key. Reverts with `InvalidKeyId` if the wallet has no such key. Reverts with `TeeNotFound` if `_teeId` is not a registered TEE machine. Reverts with `ExtensionIdMismatch` if `_teeId` belongs to a different extension than the wallet.

Interpretation of the return tuple:

Return

Meaning

`(N, true)`

TEE currently holds the key; the next delete/restore operation will use nonce `N+1`.

`(0, false)`

TEE in the wallet's extension that has never held this key.

`(N, false)`

TEE previously held the key (nonce `N`) but it was deleted from this TEE; a future re-introduction continues from `N+1`.

Callers must use `_teeHoldsKey` rather than treating nonce `0` as "key present" — nonce `0` alone is ambiguous.

```
function getKeyNonce(        address _teeId,        bytes32 _walletId,        uint64 _keyId    )        external view        returns (            uint256 _nonce,            bool _teeHoldsKey        )
```

**Parameters**

-   `_teeId`: The TEE id.
-   `_walletId`: The wallet id.
-   `_keyId`: The key id.

**Returns**

-   `_nonce`: The current per-TEE nonce for this key.
-   `_teeHoldsKey`: True if the TEE is currently registered as holding this key.

### `getWalletKeysInfo`[​](#getwalletkeysinfo "Direct link to getwalletkeysinfo")

Returns information about the wallet keys.

```
function getWalletKeysInfo(        bytes32 _walletId    )        external view        returns (            uint64 _multisigThreshold,            uint64[] memory _keyIds,            uint64 _counter        )
```

**Parameters**

-   `_walletId`: The wallet id.

**Returns**

-   `_multisigThreshold`: The multisig threshold.
-   `_keyIds`: The confirmed key ids.
-   `_counter`: The number of `addKey` calls (next key id).

### `getWalletPublicKeys`[​](#getwalletpublickeys "Direct link to getwalletpublickeys")

Returns the wallet's multisig threshold and public keys (ordered by key id) in a single call.

```
function getWalletPublicKeys(        bytes32 _walletId    )        external view        returns (            uint64 _multisigThreshold,            bytes[] memory _publicKeys        )
```

**Parameters**

-   `_walletId`: The wallet id.

**Returns**

-   `_multisigThreshold`: The multisig threshold.
-   `_publicKeys`: The public keys, ordered by key id.

## Events[​](#events "Direct link to Events")

### `WalletMultisigThresholdSet`[​](#walletmultisigthresholdset "Direct link to walletmultisigthresholdset")

```
event WalletMultisigThresholdSet(        bytes32 indexed walletId,        uint64 multisigThreshold    )
```

**Parameters**

-   `walletId` (`bytes32 indexed walletId`)
-   `multisigThreshold` (`uint64 multisigThreshold`)

### `WalletKeyAdded`[​](#walletkeyadded "Direct link to walletkeyadded")

Emitted when `addKey` assigns a key id and queues `KEY_GENERATE` (before confirmation).

```
event WalletKeyAdded(        address indexed teeId,        bytes32 indexed walletId,        uint64 indexed keyId    )
```

**Parameters**

-   `teeId` (`address indexed teeId`)
-   `walletId` (`bytes32 indexed walletId`)
-   `keyId` (`uint64 indexed keyId`)

### `WalletKeyConfirmed`[​](#walletkeyconfirmed "Direct link to walletkeyconfirmed")

Emitted when `confirmKey` accepts a TEE-signed existence proof and records the public key / holder.

```
event WalletKeyConfirmed(        address indexed teeId,        bytes32 indexed walletId,        uint64 indexed keyId,        bytes publicKey    )
```

**Parameters**

-   `teeId` (`address indexed teeId`)
-   `walletId` (`bytes32 indexed walletId`)
-   `keyId` (`uint64 indexed keyId`)
-   `publicKey` (`bytes publicKey`)

### `WalletKeyDeleted`[​](#walletkeydeleted "Direct link to walletkeydeleted")

Emitted by `deleteKey` (before the `KEY_DELETE` instruction) and by `cleanUpTeeIds` for each removed non-PRODUCTION holder.

```
event WalletKeyDeleted(        address indexed teeId,        bytes32 indexed walletId,        uint64 indexed keyId    )
```

**Parameters**

-   `teeId` (`address indexed teeId`)
-   `walletId` (`bytes32 indexed walletId`)
-   `keyId` (`uint64 indexed keyId`)

### `WalletKeysNotAvailable`[​](#walletkeysnotavailable "Direct link to walletkeysnotavailable")

Emitted by `receivingTeesAndKeys` when some key ids have no PRODUCTION holder, while the multisig threshold is still met.

```
event WalletKeysNotAvailable(        bytes32 indexed walletId,        uint64[] keyIds    )
```

**Parameters**

-   `walletId` (`bytes32 indexed walletId`)
-   `keyIds` (`uint64[] keyIds`)

## Errors[​](#errors "Direct link to Errors")

Facet-specific errors are listed here. The interface also inherits shared [`ITeeCommonErrors`](/fcc/reference/ITeeCommonErrors). This facet uses those for ownership, extension matching, wallet status, key type / signing algo checks, and config-constant validation, including `OnlyOwner`, `OnlyOwnerOrBackupManager`, `ExtensionIdMismatch`, `InvalidWalletStatus`, `InvalidKeyType`, `InvalidSigningAlgo`, `InvalidPublicKey`, `InvalidNonce`, `InvalidThreshold`, `LengthsMismatch`, and `InvalidAddress`.

### `InvalidKeyId`[​](#invalidkeyid "Direct link to invalidkeyid")

The wallet has no confirmed key at `_keyId`, or `confirmKey` references a key id that was never assigned by `addKey`.

```
error InvalidKeyId()
```

### `InvalidSettings`[​](#invalidsettings "Direct link to invalidsettings")

`KeyExistence.settingsVersion` is not zero or `settings` is non-empty. Current `confirmKey` requires both empty / zero.

```
error InvalidSettings()
```

### `InvalidTeeSignature`[​](#invalidteesignature "Direct link to invalidteesignature")

The recovered signer of the `TEE_KEY_EXISTENCE` payload is not `KeyExistence.teeId`.

```
error InvalidTeeSignature()
```

### `KeyNotRestoredOnTeeMachine`[​](#keynotrestoredonteemachine "Direct link to keynotrestoredonteemachine")

A re-introduction `confirmKey` (public key already stored) did not set `restored == true` with a nonce greater than zero.

```
error KeyNotRestoredOnTeeMachine()
```

### `TeeIdAlreadyAdded`[​](#teeidalreadyadded "Direct link to teeidalreadyadded")

`confirmKey` tried to add a TEE that is already listed as holding this key.

```
error TeeIdAlreadyAdded()
```

### `KeyNotGeneratedOnTeeMachine`[​](#keynotgeneratedonteemachine "Direct link to keynotgeneratedonteemachine")

A first-time `confirmKey` (`nonce == 0`) set `restored == true`. First generation must use `restored == false`.

```
error KeyNotGeneratedOnTeeMachine()
```

### `ThresholdNotMet`[​](#thresholdnotmet "Direct link to thresholdnotmet")

`receivingTeesAndKeys` / `getReceivingTeeIds` found fewer available keys (keys with at least one PRODUCTION holder) than the wallet's `multisigThreshold`.

```
error ThresholdNotMet()
```
