> ## Documentation Index
> Fetch the complete documentation index at: https://bkey.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Wallet provisioning

> Create, read, and delete an on-device Ethereum wallet.

<div className="bmoni-spine">
  <span>Lifecycle</span>
  <a data-stage="1" href="/lifecycle#1-create-the-user">User</a>
  <a data-stage="2" href="/lifecycle#2-provision-the-smart-wallet">Wallet</a>
  <a data-stage="3" href="/lifecycle#3-verify-identity-kyc">KYC</a>
  <a data-stage="4" href="/lifecycle#4-activate-the-rail">Rail</a>
  <a data-stage="5" href="/lifecycle#5-fund-the-wallet">Fund</a>
  <a data-stage="6" href="/lifecycle#6-move-money">Move money</a>
</div>

## Overview

A wallet is a secp256k1 keypair generated inside the device's secure hardware. The SDK stores the **encrypted** private key on-device and returns the EIP-55 checksummed address — the only piece of data you need to share with your backend.

<Info>
  The native BMONISigner layer only returns the address at the moment of provisioning. The TypeScript facade caches it in platform secure storage automatically, so you can read it back at any time.
</Info>

***

## Check whether a wallet exists

```ts theme={null}
const exists = await BmoniEmbeddedSdk.hasWallet();
```

***

## Provision a new wallet

```ts theme={null}
import {
  BmoniEmbeddedSdk,
  BmoniSignerError,
  BmoniSignerErrorCode,
} from '@bkey-inc/bmoni_embedded_sdk';

try {
  const address = await BmoniEmbeddedSdk.initWallet();
  console.log('Wallet address:', address);
  // address is EIP-55 checksummed, e.g. 0xAbC...123
} catch (error) {
  if (
    error instanceof BmoniSignerError &&
    error.errorCode === BmoniSignerErrorCode.walletAlreadyExists
  ) {
    // A wallet is already on disk — see "Re-provisioning" below.
  } else {
    throw error;
  }
}
```

`initWallet` throws `walletAlreadyExists` if the native layer already holds an encrypted key. You must delete it first before provisioning again.

***

## Read the cached address

```ts theme={null}
const address = await BmoniEmbeddedSdk.walletAddress();
if (address !== null) {
  // Wallet is provisioned.
}
```

The typical startup pattern:

```ts theme={null}
const address =
  (await BmoniEmbeddedSdk.walletAddress()) ??
  (await BmoniEmbeddedSdk.initWallet());
```

***

## Delete a wallet

`deleteWallet` removes the encrypted private key from device storage. It is idempotent at the native layer.

```ts theme={null}
await BmoniEmbeddedSdk.deleteWallet('123456');
// The address cache is also wiped automatically.
```

When `requirePin` is `false`, omit the argument:

```ts theme={null}
BmoniEmbeddedSdk.initialize({ requirePin: false });
await BmoniEmbeddedSdk.deleteWallet();
```

If the PIN check fails, the native delete never runs and the cached address is left untouched, so `walletAddress()` still reflects the live wallet.

<Warning>
  Deletion is **permanent and irreversible from this device**. The on-chain address is unrecoverable once the key is deleted.
</Warning>

***

## Re-provisioning (recovery flow)

If `initWallet` throws `walletAlreadyExists` but `walletAddress()` returns `null`, the native wallet exists but the TypeScript-side address cache is missing (for example, the app was reinstalled). The only recovery path is to delete the existing wallet and provision a new one:

```ts theme={null}
// This is destructive — the old address becomes unrecoverable.
try {
  // Temporarily disable the PIN gate so we can delete without a known PIN.
  BmoniEmbeddedSdk.initialize({ requirePin: false });
  await BmoniEmbeddedSdk.deleteWallet();
  BmoniEmbeddedSdk.initialize({ requirePin: true }); // restore

  const newAddress = await BmoniEmbeddedSdk.initWallet();
  console.log('Re-provisioned:', newAddress);
} catch (error) {
  console.error('Recovery failed:', error);
}
```

Always show a confirmation dialog before executing this flow — the old address is gone after deletion.
