@liberfi.io/wallet-connector
v0.1.89
Published
Base Wallet Connector for Liberfi React SDK
Readme
@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
WalletAdapterinterface and React contexts; the package never imports a concrete wallet SDK. Implementation packages inject behavior viaWalletConnectorProviderandAuthProvider. - Inversion of control —
connect,disconnect,signIn,signOut, andrefreshAccessTokenare 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
pnpm add @liberfi.io/wallet-connectorPeer Dependencies
| Package | Version |
| ----------- | ------- |
| react | >=18 |
| react-dom | >=18 |
API Reference
Types
WalletAdapter
The core wallet abstraction. All wallet implementations must conform to this interface.
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.
interface EvmWalletAdapter extends WalletAdapter {
getEip1193Provider(): Promise<Eip1193Provider | undefined>;
switchChain(chain: Chain): Promise<void>;
}Eip1193Provider
Standard EIP-1193 provider interface.
interface Eip1193Provider {
request(request: {
method: string;
params?: Array<unknown> | Record<string, unknown>;
}): Promise<unknown>;
}AuthenticatedUser
Represents the currently authenticated user.
interface AuthenticatedUser {
id: string;
wallets: Array<WalletAdapter>;
accessToken: string;
}WalletConnectorContextValue
Shape of the wallet connector context.
interface WalletConnectorContextValue {
status:
| "detecting"
| "connecting"
| "connected"
| "disconnecting"
| "disconnected";
wallets: Array<WalletAdapter>;
connect: () => Promise<void>;
disconnect: () => Promise<void>;
}AuthContextValue
Shape of the auth context.
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.
function useWalletConnector(): WalletConnectorContextValue;useWallets()
Convenience hook that returns only the wallets array from the wallet connector context.
function useWallets(): Array<WalletAdapter>;useAuth()
Returns the full AuthContextValue. Throws if used outside AuthProvider.
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.
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.
function useSwitchChain(): (chain: Chain) => Promise<void>;Constants
version
The current package version string.
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:
import {
PrivyWalletConnectorProvider,
PrivyAuthProvider,
} from "@liberfi.io/wallet-connector-privy";
function App() {
return (
<PrivyWalletConnectorProvider privyAppId="your-app-id">
<PrivyAuthProvider>
<MyApp />
</PrivyAuthProvider>
</PrivyWalletConnectorProvider>
);
}Consuming Wallet State
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
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
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:
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 ContextValuetonullwithContextValue | nulltype for type-safe "no provider" detection. - Expand test coverage — Add tests for status transitions (unauthenticated → authenticated) and error propagation when
switchChainrejects. - Typed EIP-1193 overloads — Provide method-specific typed overloads for common EIP-1193 methods (e.g.
eth_sendTransaction,personal_sign).
