npm package: @liberfi.io/wallet-connector
Description: Base Wallet Connector for Liberfi React SDK
Author: liberfi.io
Latest version: 0.1.142

# @liberfi.io/wallet-connector

Base wallet connector abstraction for the Liberfi React SDK. This package defines the **interfaces**, **React context/providers**, and **hooks** for wallet connection and authentication — without binding to any specific wallet provider or identity service. Concrete implementations (e.g. Privy) live in separate packages like `@liberfi.io/wallet-connector-privy`.

## Design Philosophy

- **Provider-agnostic abstraction** — Defines a `WalletAdapter` interface and React contexts; the package never imports a concrete wallet SDK. Implementation packages inject behavior via `WalletConnectorProvider` and `AuthProvider`.
- **Inversion of control** — `connect`, `disconnect`, `signIn`, `signOut`, and `refreshAccessToken` are supplied by the consumer, not hardcoded. This allows swapping wallet providers without changing downstream code.
- **Layered architecture** — Three clean layers: `types/` (interfaces and domain types) → `providers/` (React context and passthrough providers) → `hooks/` (consumer-facing hooks). No circular dependencies.
- **Minimal surface area** — Only exports what consumers need: 2 providers, 5 hooks, and a handful of types. No UI, no side effects, no heavy dependencies.

## Installation

```bash
pnpm add @liberfi.io/wallet-connector
```

### Peer Dependencies

| Package     | Version |
| ----------- | ------- |
| `react`     | >=18    |
| `react-dom` | >=18    |

## API Reference

### Types

#### `WalletAdapter`

The core wallet abstraction. All wallet implementations must conform to this interface.

```typescript
interface WalletAdapter {
  get chainNamespace(): ChainNamespace;
  get chain(): Chain | undefined;
  get address(): string;
  get isConnected(): boolean;
  get isCustodial(): boolean;
  get connector(): string;

  signMessage(message: string): Promise<string>;
  signTransaction(serializedTx: Uint8Array): Promise<Uint8Array>;
  sendTransaction(serializedTx: Uint8Array): Promise<string>;
}
```

#### `EvmWalletAdapter`

Extends `WalletAdapter` with EVM-specific capabilities.

```typescript
interface EvmWalletAdapter extends WalletAdapter {
  getEip1193Provider(): Promise<Eip1193Provider | undefined>;
  switchChain(chain: Chain): Promise<void>;
}
```

#### `Eip1193Provider`

Standard [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) provider interface.

```typescript
interface Eip1193Provider {
  request(request: {
    method: string;
    params?: Array<unknown> | Record<string, unknown>;
  }): Promise<unknown>;
}
```

#### `AuthenticatedUser`

Represents the currently authenticated user.

```typescript
interface AuthenticatedUser {
  id: string;
  wallets: Array<WalletAdapter>;
  accessToken: string;
}
```

#### `WalletConnectorContextValue`

Shape of the wallet connector context.

```typescript
interface WalletConnectorContextValue {
  status:
    | "detecting"
    | "connecting"
    | "connected"
    | "disconnecting"
    | "disconnected";
  wallets: Array<WalletAdapter>;
  connect: () => Promise<void>;
  disconnect: () => Promise<void>;
}
```

#### `AuthContextValue`

Shape of the auth context.

```typescript
interface AuthContextValue {
  user: AuthenticatedUser | null;
  status: "unauthenticated" | "authenticating" | "authenticated";
  signIn: () => void | Promise<void>;
  signOut: () => void | Promise<void>;
  refreshAccessToken: () => void | Promise<void>;
}
```

### Components

#### `WalletConnectorProvider`

Provides wallet connection state to the component tree. Typically wrapped by an implementation provider (e.g. `PrivyWalletConnectorProvider`).

| Prop         | Type                                    | Description                |
| ------------ | --------------------------------------- | -------------------------- |
| `status`     | `WalletConnectorContextValue["status"]` | Current connection status  |
| `wallets`    | `Array<WalletAdapter>`                  | Connected wallet adapters  |
| `connect`    | `() => Promise<void>`                   | Triggers wallet connection |
| `disconnect` | `() => Promise<void>`                   | Disconnects all wallets    |
| `children`   | `ReactNode`                             | Child components           |

#### `AuthProvider`

Provides authentication state to the component tree. Typically wrapped by an implementation provider (e.g. `PrivyAuthProvider`).

| Prop                 | Type                          | Description                |
| -------------------- | ----------------------------- | -------------------------- |
| `user`               | `AuthenticatedUser \| null`   | Current authenticated user |
| `status`             | `AuthContextValue["status"]`  | Current auth status        |
| `signIn`             | `() => void \| Promise<void>` | Triggers sign-in flow      |
| `signOut`            | `() => void \| Promise<void>` | Triggers sign-out flow     |
| `refreshAccessToken` | `() => void \| Promise<void>` | Refreshes the access token |
| `children`           | `ReactNode`                   | Child components           |

### Hooks

#### `useWalletConnector()`

Returns the full `WalletConnectorContextValue`. Throws if used outside `WalletConnectorProvider`.

```typescript
function useWalletConnector(): WalletConnectorContextValue;
```

#### `useWallets()`

Convenience hook that returns only the `wallets` array from the wallet connector context.

```typescript
function useWallets(): Array<WalletAdapter>;
```

#### `useAuth()`

Returns the full `AuthContextValue`. Throws if used outside `AuthProvider`.

```typescript
function useAuth(): AuthContextValue;
```

#### `useAuthCallback<T>(callback, deps?)`

Wraps a callback so it only executes when the user is authenticated. If unauthenticated, it triggers `signIn()` and returns `undefined`. If currently authenticating, it silently returns `undefined` without re-triggering sign-in.

```typescript
type AuthGuardedCallback<T extends (...args: any[]) => any> = (
  ...args: Parameters<T>
) => Promise<Awaited<ReturnType<T>> | undefined>;

function useAuthCallback<T extends (...args: any[]) => any>(
  callback: T,
  deps?: DependencyList,
): AuthGuardedCallback<T>;
```

The return type `AuthGuardedCallback<T>` makes it explicit that the wrapped function may resolve to `undefined` when the user is not authenticated.

#### `useSwitchChain()`

Returns a function that switches all connected EVM wallets to a given chain. Solana chains are automatically skipped.

```typescript
function useSwitchChain(): (chain: Chain) => Promise<void>;
```

### Constants

#### `version`

The current package version string.

```typescript
const version: string; // e.g. "0.1.18"
```

## Usage Examples

### Basic Setup with an Implementation Provider

This package is designed to be used with an implementation provider. Here's an example using `@liberfi.io/wallet-connector-privy`:

```tsx
import {
  PrivyWalletConnectorProvider,
  PrivyAuthProvider,
} from "@liberfi.io/wallet-connector-privy";

function App() {
  return (
    <PrivyWalletConnectorProvider privyAppId="your-app-id">
      <PrivyAuthProvider>
        <MyApp />
      </PrivyAuthProvider>
    </PrivyWalletConnectorProvider>
  );
}
```

### Consuming Wallet State

```tsx
import { useWalletConnector, useWallets } from "@liberfi.io/wallet-connector";

function WalletStatus() {
  const { status, connect, disconnect } = useWalletConnector();
  const wallets = useWallets();

  if (status === "disconnected") {
    return <button onClick={connect}>Connect Wallet</button>;
  }

  return (
    <div>
      <p>Status: {status}</p>
      <ul>
        {wallets.map((w) => (
          <li key={w.address}>
            {w.connector}: {w.address}
          </li>
        ))}
      </ul>
      <button onClick={disconnect}>Disconnect</button>
    </div>
  );
}
```

### Auth-Gated Actions

```tsx
import { useAuthCallback } from "@liberfi.io/wallet-connector";

function TradeButton() {
  const handleTrade = useAuthCallback(async () => {
    // This only runs when the user is authenticated.
    // If not authenticated, signIn() is triggered automatically.
    await executeTrade();
  }, []);

  return <button onClick={handleTrade}>Trade</button>;
}
```

### Switching Chains

```tsx
import { Chain } from "@liberfi.io/types";
import { useSwitchChain } from "@liberfi.io/wallet-connector";

function ChainSwitcher() {
  const switchChain = useSwitchChain();

  return (
    <button onClick={() => switchChain(Chain.ETHEREUM)}>
      Switch to Ethereum
    </button>
  );
}
```

### Building a Custom Implementation

To create a new wallet connector implementation, implement `WalletAdapter` (and optionally `EvmWalletAdapter`) and wrap the providers:

```tsx
import {
  WalletConnectorProvider,
  AuthProvider,
  WalletAdapter,
} from "@liberfi.io/wallet-connector";

class MyWalletAdapter implements WalletAdapter {
  // Implement all WalletAdapter properties and methods...
}

function MyWalletConnectorProvider({ children }: PropsWithChildren) {
  const [wallets, setWallets] = useState<WalletAdapter[]>([]);
  const [status, setStatus] = useState<"disconnected" | "connected">(
    "disconnected",
  );

  const connect = async () => {
    /* your connect logic */
  };
  const disconnect = async () => {
    /* your disconnect logic */
  };

  return (
    <WalletConnectorProvider
      status={status}
      wallets={wallets}
      connect={connect}
      disconnect={disconnect}
    >
      {children}
    </WalletConnectorProvider>
  );
}
```

## Future Improvements

- **Context default safety** — Switch context defaults from `{} as ContextValue` to `null` with `ContextValue | null` type for type-safe "no provider" detection.
- **Expand test coverage** — Add tests for status transitions (unauthenticated → authenticated) and error propagation when `switchChain` rejects.
- **Typed EIP-1193 overloads** — Provide method-specific typed overloads for common EIP-1193 methods (e.g. `eth_sendTransaction`, `personal_sign`).