@solana/connector 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +460 -1082
- package/dist/{chunk-RIBOPAOD.js → chunk-CLXM6UEE.js} +149 -121
- package/dist/chunk-CLXM6UEE.js.map +1 -0
- package/dist/{chunk-JS4KJ2KK.js → chunk-D6PZY5G6.js} +71 -93
- package/dist/chunk-D6PZY5G6.js.map +1 -0
- package/dist/chunk-LUZWUZ5N.js +2012 -0
- package/dist/chunk-LUZWUZ5N.js.map +1 -0
- package/dist/{chunk-WXYUUCSD.mjs → chunk-N3Q2J2FG.mjs} +53 -71
- package/dist/chunk-N3Q2J2FG.mjs.map +1 -0
- package/dist/chunk-P5MWBDFG.mjs +298 -0
- package/dist/chunk-P5MWBDFG.mjs.map +1 -0
- package/dist/chunk-RIQH5W7D.js +311 -0
- package/dist/chunk-RIQH5W7D.js.map +1 -0
- package/dist/chunk-U64YZRJL.mjs +1984 -0
- package/dist/chunk-U64YZRJL.mjs.map +1 -0
- package/dist/{chunk-4K6QY4HR.mjs → chunk-YTCSTE3Q.mjs} +64 -37
- package/dist/chunk-YTCSTE3Q.mjs.map +1 -0
- package/dist/compat.d.mts +4 -2
- package/dist/compat.d.ts +4 -2
- package/dist/compat.js +3 -3
- package/dist/compat.mjs +1 -1
- package/dist/headless.d.mts +146 -18
- package/dist/headless.d.ts +146 -18
- package/dist/headless.js +144 -111
- package/dist/headless.mjs +3 -2
- package/dist/index.d.mts +6 -5
- package/dist/index.d.ts +6 -5
- package/dist/index.js +207 -126
- package/dist/index.mjs +4 -3
- package/dist/react.d.mts +707 -67
- package/dist/react.d.ts +707 -67
- package/dist/react.js +64 -16
- package/dist/react.mjs +2 -2
- package/dist/{transaction-signer-D3csM_Mf.d.ts → transaction-signer-D9d8nxwb.d.mts} +3 -1
- package/dist/{transaction-signer-D3csM_Mf.d.mts → transaction-signer-D9d8nxwb.d.ts} +3 -1
- package/dist/{wallet-standard-shim-Cg0GVGwu.d.mts → wallet-standard-shim-Cp4vF4oo.d.mts} +133 -6
- package/dist/{wallet-standard-shim-C1tisl9S.d.ts → wallet-standard-shim-DC_Z7DS-.d.ts} +133 -6
- package/package.json +16 -12
- package/dist/chunk-4K6QY4HR.mjs.map +0 -1
- package/dist/chunk-5ZUVZZWU.mjs +0 -180
- package/dist/chunk-5ZUVZZWU.mjs.map +0 -1
- package/dist/chunk-F2QJH5ED.mjs +0 -298
- package/dist/chunk-F2QJH5ED.mjs.map +0 -1
- package/dist/chunk-JS4KJ2KK.js.map +0 -1
- package/dist/chunk-RIBOPAOD.js.map +0 -1
- package/dist/chunk-SJEZHNYF.js +0 -314
- package/dist/chunk-SJEZHNYF.js.map +0 -1
- package/dist/chunk-SMUUAKC3.js +0 -186
- package/dist/chunk-SMUUAKC3.js.map +0 -1
- package/dist/chunk-WXYUUCSD.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -3,255 +3,139 @@ title: @solana/connector
|
|
|
3
3
|
description: Production-ready wallet connector for Solana applications
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
**ConnectorKit is your Solana wallet infrastructure.** A headless, framework-agnostic wallet connector built on Wallet Standard
|
|
6
|
+
**ConnectorKit is your Solana wallet infrastructure.** A headless, framework-agnostic wallet connector built on Wallet Standard that just work.
|
|
7
7
|
|
|
8
8
|

|
|
9
|
-

|
|
10
10
|

|
|
11
|
-

|
|
12
11
|
|
|
13
12
|
### Why ConnectorKit?
|
|
14
13
|
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
|
|
21
|
-
### Architecture
|
|
22
|
-
|
|
23
|
-
- **Language**: TypeScript with full type safety
|
|
24
|
-
- **Standard**: Built on Wallet Standard protocol
|
|
25
|
-
- **Frameworks**: React hooks + headless core for any framework
|
|
26
|
-
- **Mobile**: Solana Mobile Wallet Adapter integration
|
|
27
|
-
- **Storage**: Enhanced persistence with SSR support
|
|
28
|
-
|
|
29
|
-
### Features
|
|
30
|
-
|
|
31
|
-
- Wallet Standard compliance with multi-wallet support
|
|
32
|
-
- Clean transaction signer abstraction
|
|
33
|
-
- Comprehensive event system for analytics
|
|
34
|
-
- Connection pooling for better performance
|
|
35
|
-
- Health checks and diagnostics
|
|
36
|
-
- Auto-connect and account management
|
|
37
|
-
- Network switching (mainnet, devnet, testnet, custom)
|
|
38
|
-
- Browser polyfills for universal compatibility
|
|
39
|
-
- Debug panel for development
|
|
40
|
-
- Wallet Adapter compatibility bridge
|
|
41
|
-
- 80%+ test coverage
|
|
14
|
+
- **Wallet Standard First**: Built on the official Wallet Standard protocol for universal wallet compatibility
|
|
15
|
+
- **Modern & Legacy Support**: Works with both `@solana/kit` (web3.js 2.0) and `@solana/web3.js` (legacy)
|
|
16
|
+
- **Framework Agnostic**: React hooks + headless core for Vue, Svelte, or vanilla JavaScript
|
|
17
|
+
- **Production Ready**: Event system for analytics, health checks for diagnostics, error boundaries for React apps
|
|
18
|
+
- **Enhanced Storage**: Automatic validation, SSR fallback, and error handling out of the box
|
|
19
|
+
- **Mobile Support**: Built-in Solana Mobile Wallet Adapter integration
|
|
42
20
|
|
|
43
21
|
---
|
|
44
22
|
|
|
45
23
|
## Quick Start
|
|
46
24
|
|
|
47
|
-
Install
|
|
25
|
+
### 1. Install
|
|
48
26
|
|
|
49
27
|
```bash
|
|
50
|
-
pnpm add @solana/connector
|
|
51
|
-
# or
|
|
52
28
|
npm install @solana/connector
|
|
53
29
|
# or
|
|
30
|
+
pnpm add @solana/connector
|
|
31
|
+
# or
|
|
54
32
|
yarn add @solana/connector
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
} from '@solana/connector';
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
function SendTransaction() {
|
|
100
|
-
const { signer, ready } = useTransactionSigner();
|
|
101
|
-
|
|
102
|
-
const handleSend = async () => {
|
|
103
|
-
const signature = await signer.signAndSendTransaction(transaction);
|
|
104
|
-
};
|
|
33
|
+
# or
|
|
34
|
+
bun add @solana/connector
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Setup Provider (once in your app root)
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
'use client';
|
|
41
|
+
|
|
42
|
+
import { useMemo } from 'react';
|
|
43
|
+
import { AppProvider } from '@solana/connector/react';
|
|
44
|
+
import { getDefaultConfig, getDefaultMobileConfig } from '@solana/connector/headless';
|
|
45
|
+
|
|
46
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
47
|
+
const connectorConfig = useMemo(() => {
|
|
48
|
+
// Optional: Get custom RPC URL from environment variable
|
|
49
|
+
const customRpcUrl = process.env.SOLANA_RPC_URL;
|
|
50
|
+
|
|
51
|
+
// Optional: Create custom cluster configuration
|
|
52
|
+
const clusters = customRpcUrl
|
|
53
|
+
? [
|
|
54
|
+
{
|
|
55
|
+
id: 'solana:mainnet' as const,
|
|
56
|
+
label: 'Mainnet (Custom RPC)',
|
|
57
|
+
name: 'mainnet-beta' as const,
|
|
58
|
+
url: customRpcUrl,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'solana:devnet' as const,
|
|
62
|
+
label: 'Devnet',
|
|
63
|
+
name: 'devnet' as const,
|
|
64
|
+
url: 'https://api.devnet.solana.com',
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
: undefined;
|
|
68
|
+
|
|
69
|
+
return getDefaultConfig({
|
|
70
|
+
appName: 'My App',
|
|
71
|
+
appUrl: 'https://myapp.com',
|
|
72
|
+
autoConnect: true,
|
|
73
|
+
enableMobile: true,
|
|
74
|
+
clusters,
|
|
75
|
+
});
|
|
76
|
+
}, []);
|
|
105
77
|
|
|
106
|
-
|
|
78
|
+
const mobile = useMemo(
|
|
79
|
+
() =>
|
|
80
|
+
getDefaultMobileConfig({
|
|
81
|
+
appName: 'My App',
|
|
82
|
+
appUrl: 'https://myapp.com',
|
|
83
|
+
}),
|
|
84
|
+
[],
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<AppProvider connectorConfig={connectorConfig} mobile={mobile}>
|
|
89
|
+
{children}
|
|
90
|
+
</AppProvider>
|
|
91
|
+
);
|
|
107
92
|
}
|
|
108
93
|
```
|
|
109
94
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
**[→ Transaction Signer](#transaction-signer)** - Sign and send transactions
|
|
113
|
-
|
|
114
|
-
**[→ Event System](#event-system)** - Track wallet events for analytics
|
|
115
|
-
|
|
116
|
-
**[→ Framework Guides](#headless-client-vue-svelte-vanilla-js)** - Use with Vue, Svelte, or vanilla JS
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## Documentation
|
|
121
|
-
|
|
122
|
-
### Getting Started
|
|
123
|
-
|
|
124
|
-
- [Installation](#quick-start)
|
|
125
|
-
- [Quick Start Guide](#quick-start)
|
|
126
|
-
- [TypeScript SDK](#typescript-sdk)
|
|
127
|
-
- [Core Hooks](#core-hooks)
|
|
128
|
-
- [Local Development](#local-development)
|
|
129
|
-
|
|
130
|
-
### Production Features
|
|
131
|
-
|
|
132
|
-
- [Transaction Signer](#transaction-signer) - Clean signing API
|
|
133
|
-
- [Event System](#event-system) - Analytics and monitoring
|
|
134
|
-
- [Debug Panel](#debug-panel) - Development tools
|
|
135
|
-
- [Connection Pooling](#connection-pooling) - Performance optimization
|
|
136
|
-
- [Health Checks](#health-checks) - Diagnostics
|
|
137
|
-
- [Wallet Adapter Compatibility](#wallet-adapter-compatibility) - Drop-in replacement
|
|
138
|
-
|
|
139
|
-
### Configuration & Usage
|
|
140
|
-
|
|
141
|
-
- [Configuration](#configuration) - Setup options
|
|
142
|
-
- [Network Selection](#network-selection) - Cluster management
|
|
143
|
-
- [Custom Storage](#custom-storage) - Persistence options
|
|
144
|
-
- [Mobile Wallet Adapter](#mobile-wallet-adapter) - Mobile support
|
|
145
|
-
- [Advanced Usage](#advanced-usage) - Framework-specific guides
|
|
146
|
-
|
|
147
|
-
### Reference
|
|
148
|
-
|
|
149
|
-
- [Complete API Reference](#complete-api-reference)
|
|
150
|
-
- [Configuration Functions](#configuration-functions)
|
|
151
|
-
- [Transaction Signing API](#transaction-signing-api-new)
|
|
152
|
-
- [Event System API](#event-system-api-new)
|
|
153
|
-
- [Health Check API](#health-check-api-new)
|
|
154
|
-
- [Connection Pool API](#connection-pool-api-new)
|
|
155
|
-
- [Utility Functions](#utility-functions)
|
|
156
|
-
- [TypeScript Types](#types)
|
|
157
|
-
|
|
158
|
-
### Testing & Performance
|
|
159
|
-
|
|
160
|
-
- [Testing](#testing) - Test suite and utilities
|
|
161
|
-
- [Performance](#performance) - Bundle size and optimization
|
|
162
|
-
- [Browser Compatibility](#browser-compatibility)
|
|
163
|
-
|
|
164
|
-
### Migration & Examples
|
|
165
|
-
|
|
166
|
-
- [Migration from wallet-adapter](#migration-from-solanawallet-adapter)
|
|
167
|
-
- [Examples](#examples)
|
|
168
|
-
- [Supported Wallets](#supported-wallets)
|
|
169
|
-
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
## TypeScript SDK
|
|
173
|
-
|
|
174
|
-
ConnectorKit provides React hooks and a headless core for any framework:
|
|
95
|
+
### 3. Use Hooks (in any component)
|
|
175
96
|
|
|
176
97
|
```typescript
|
|
177
|
-
|
|
178
|
-
import { useConnector, useTransactionSigner, useAccount } from '@solana/connector';
|
|
179
|
-
|
|
180
|
-
// Headless (Vue, Svelte, vanilla JS)
|
|
181
|
-
import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
|
|
182
|
-
|
|
183
|
-
const client = new ConnectorClient(getDefaultConfig({ appName: 'My App' }));
|
|
184
|
-
await client.select('Phantom');
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**[→ API Reference](#complete-api-reference)** - Full TypeScript API documentation
|
|
188
|
-
|
|
189
|
-
**[→ Core Hooks](#core-hooks)** - React hooks reference
|
|
190
|
-
|
|
191
|
-
**[→ Headless Guide](#headless-client-vue-svelte-vanilla-js)** - Use without React
|
|
98
|
+
'use client';
|
|
192
99
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
## Local Development
|
|
196
|
-
|
|
197
|
-
### Prerequisites
|
|
198
|
-
|
|
199
|
-
- Node.js 20+ (or 18+)
|
|
200
|
-
- pnpm, npm, or yarn
|
|
201
|
-
- TypeScript 5.0+
|
|
202
|
-
|
|
203
|
-
### Installation
|
|
204
|
-
|
|
205
|
-
```bash
|
|
206
|
-
git clone https://github.com/your-org/connectorkit.git
|
|
207
|
-
cd connectorkit
|
|
208
|
-
pnpm install
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### Build
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
pnpm build
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### Running Examples
|
|
218
|
-
|
|
219
|
-
```bash
|
|
220
|
-
cd examples/react
|
|
221
|
-
pnpm dev
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Or run the Vite example:
|
|
225
|
-
|
|
226
|
-
```bash
|
|
227
|
-
cd examples/vite
|
|
228
|
-
pnpm dev
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Local Testing
|
|
100
|
+
import { useConnector, useAccount } from '@solana/connector';
|
|
232
101
|
|
|
233
|
-
|
|
102
|
+
export function ConnectButton() {
|
|
103
|
+
const { wallets, select, disconnect, connected, connecting, selectedWallet, selectedAccount } = useConnector();
|
|
104
|
+
const { address, formatted, copy } = useAccount();
|
|
234
105
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
106
|
+
if (connecting) {
|
|
107
|
+
return <button disabled>Connecting...</button>;
|
|
108
|
+
}
|
|
238
109
|
|
|
239
|
-
|
|
110
|
+
if (!connected) {
|
|
111
|
+
return (
|
|
112
|
+
<div>
|
|
113
|
+
{wallets.map(w => (
|
|
114
|
+
<button key={w.wallet.name} onClick={() => select(w.wallet.name)}>
|
|
115
|
+
Connect {w.wallet.name}
|
|
116
|
+
</button>
|
|
117
|
+
))}
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
240
121
|
|
|
241
|
-
|
|
242
|
-
|
|
122
|
+
return (
|
|
123
|
+
<div>
|
|
124
|
+
<button onClick={copy}>{formatted}</button>
|
|
125
|
+
<button onClick={disconnect}>Disconnect</button>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
243
129
|
```
|
|
244
130
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
```bash
|
|
248
|
-
pnpm test:coverage
|
|
249
|
-
```
|
|
131
|
+
**That's it!** You're ready to go. Everything else below is optional.
|
|
250
132
|
|
|
251
133
|
---
|
|
252
134
|
|
|
253
135
|
## Core Hooks
|
|
254
136
|
|
|
137
|
+
These are the main hooks you'll use in your components.
|
|
138
|
+
|
|
255
139
|
### `useConnector()`
|
|
256
140
|
|
|
257
141
|
Main hook for wallet connection and state.
|
|
@@ -264,6 +148,7 @@ function Component() {
|
|
|
264
148
|
// State
|
|
265
149
|
wallets, // WalletInfo[] - All available wallets
|
|
266
150
|
selectedWallet, // Wallet | null - Currently connected wallet
|
|
151
|
+
selectedAccount, // string | null - Currently selected account address
|
|
267
152
|
accounts, // AccountInfo[] - Connected accounts
|
|
268
153
|
connected, // boolean - Connection status
|
|
269
154
|
connecting, // boolean - Connecting in progress
|
|
@@ -275,6 +160,41 @@ function Component() {
|
|
|
275
160
|
}
|
|
276
161
|
```
|
|
277
162
|
|
|
163
|
+
**Real Example** - Connect Button with wallet selection:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
'use client';
|
|
167
|
+
|
|
168
|
+
import { useConnector } from '@solana/connector';
|
|
169
|
+
import { useState } from 'react';
|
|
170
|
+
|
|
171
|
+
export function ConnectButton() {
|
|
172
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
173
|
+
const { connected, connecting, selectedWallet, selectedAccount, wallets, select } = useConnector();
|
|
174
|
+
|
|
175
|
+
if (connecting) {
|
|
176
|
+
return <button disabled>Connecting...</button>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (connected && selectedAccount && selectedWallet) {
|
|
180
|
+
const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;
|
|
181
|
+
return (
|
|
182
|
+
<div>
|
|
183
|
+
<span>{shortAddress}</span>
|
|
184
|
+
<button onClick={() => select(selectedWallet.name)}>Switch Wallet</button>
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<>
|
|
191
|
+
<button onClick={() => setIsModalOpen(true)}>Connect Wallet</button>
|
|
192
|
+
{/* Wallet selection modal */}
|
|
193
|
+
</>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
278
198
|
### `useAccount()`
|
|
279
199
|
|
|
280
200
|
Hook for working with the connected account.
|
|
@@ -295,6 +215,35 @@ function Component() {
|
|
|
295
215
|
}
|
|
296
216
|
```
|
|
297
217
|
|
|
218
|
+
**Real Example** - Account Switcher for multi-account wallets:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
'use client';
|
|
222
|
+
|
|
223
|
+
import { useAccount } from '@solana/connector';
|
|
224
|
+
|
|
225
|
+
export function AccountSwitcher() {
|
|
226
|
+
const { accounts, address, selectAccount, connected } = useAccount();
|
|
227
|
+
|
|
228
|
+
if (!connected || accounts.length <= 1) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<select
|
|
234
|
+
value={address || ''}
|
|
235
|
+
onChange={e => selectAccount(e.target.value)}
|
|
236
|
+
>
|
|
237
|
+
{accounts.map(account => (
|
|
238
|
+
<option key={account.address} value={account.address}>
|
|
239
|
+
{account.address.slice(0, 6)}...{account.address.slice(-6)}
|
|
240
|
+
</option>
|
|
241
|
+
))}
|
|
242
|
+
</select>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
298
247
|
### `useCluster()`
|
|
299
248
|
|
|
300
249
|
Hook for managing Solana network/cluster.
|
|
@@ -315,291 +264,280 @@ function Component() {
|
|
|
315
264
|
}
|
|
316
265
|
```
|
|
317
266
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
## Production Features
|
|
321
|
-
|
|
322
|
-
### Transaction Signer
|
|
323
|
-
|
|
324
|
-
Clean, unified interface for transaction signing operations.
|
|
267
|
+
**Real Example** - Network Selector:
|
|
325
268
|
|
|
326
269
|
```typescript
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
function SendTx() {
|
|
330
|
-
const { signer, ready, capabilities } = useTransactionSigner();
|
|
331
|
-
|
|
332
|
-
// Check capabilities
|
|
333
|
-
console.log('Can sign:', capabilities.canSign);
|
|
334
|
-
console.log('Can send:', capabilities.canSend);
|
|
335
|
-
console.log('Can sign messages:', capabilities.canSignMessage);
|
|
336
|
-
console.log('Batch support:', capabilities.supportsBatchSigning);
|
|
337
|
-
|
|
338
|
-
const handleSend = async () => {
|
|
339
|
-
if (!signer) return;
|
|
340
|
-
|
|
341
|
-
try {
|
|
342
|
-
// Sign and send a transaction
|
|
343
|
-
const signature = await signer.signAndSendTransaction(transaction);
|
|
344
|
-
console.log('Success:', signature);
|
|
345
|
-
|
|
346
|
-
// Or just sign without sending
|
|
347
|
-
const signed = await signer.signTransaction(transaction);
|
|
348
|
-
|
|
349
|
-
// Or sign multiple transactions
|
|
350
|
-
const signedBatch = await signer.signAllTransactions([tx1, tx2, tx3]);
|
|
351
|
-
|
|
352
|
-
// Or sign and send multiple
|
|
353
|
-
const signatures = await signer.signAndSendTransactions([tx1, tx2]);
|
|
270
|
+
'use client';
|
|
354
271
|
|
|
355
|
-
|
|
356
|
-
if (error instanceof TransactionSignerError) {
|
|
357
|
-
console.error('Signing error:', error.code, error.message);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
};
|
|
272
|
+
import { useCluster } from '@solana/connector';
|
|
361
273
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
274
|
+
export function ClusterSelector() {
|
|
275
|
+
const { cluster, clusters, setCluster } = useCluster();
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<select
|
|
279
|
+
value={cluster?.id || ''}
|
|
280
|
+
onChange={e => setCluster(e.target.value as SolanaClusterId)}
|
|
281
|
+
>
|
|
282
|
+
{clusters.map(c => (
|
|
283
|
+
<option key={c.id} value={c.id}>
|
|
284
|
+
{c.label}
|
|
285
|
+
</option>
|
|
286
|
+
))}
|
|
287
|
+
</select>
|
|
288
|
+
);
|
|
367
289
|
}
|
|
368
290
|
```
|
|
369
291
|
|
|
370
|
-
|
|
292
|
+
### `useWalletInfo()`
|
|
371
293
|
|
|
372
|
-
|
|
373
|
-
import { isTransactionSignerError, TransactionSignerError } from '@solana/connector';
|
|
374
|
-
|
|
375
|
-
try {
|
|
376
|
-
await signer.signAndSendTransaction(tx);
|
|
377
|
-
} catch (error) {
|
|
378
|
-
if (isTransactionSignerError(error)) {
|
|
379
|
-
switch (error.code) {
|
|
380
|
-
case 'WALLET_NOT_CONNECTED':
|
|
381
|
-
// Show connect prompt
|
|
382
|
-
break;
|
|
383
|
-
case 'FEATURE_NOT_SUPPORTED':
|
|
384
|
-
// Show unsupported feature message
|
|
385
|
-
break;
|
|
386
|
-
case 'SIGNING_FAILED':
|
|
387
|
-
// User rejected or signing failed
|
|
388
|
-
break;
|
|
389
|
-
case 'SEND_FAILED':
|
|
390
|
-
// Transaction broadcast failed
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
### Event System
|
|
398
|
-
|
|
399
|
-
Track all connector lifecycle events for analytics and monitoring.
|
|
294
|
+
Hook for accessing current wallet metadata.
|
|
400
295
|
|
|
401
296
|
```typescript
|
|
402
|
-
import {
|
|
403
|
-
|
|
404
|
-
function AnalyticsTracker() {
|
|
405
|
-
const client = useConnectorClient();
|
|
406
|
-
|
|
407
|
-
useEffect(() => {
|
|
408
|
-
if (!client) return;
|
|
409
|
-
|
|
410
|
-
// Subscribe to events
|
|
411
|
-
const unsubscribe = client.on(event => {
|
|
412
|
-
switch (event.type) {
|
|
413
|
-
case 'wallet:connected':
|
|
414
|
-
analytics.track('Wallet Connected', {
|
|
415
|
-
wallet: event.wallet,
|
|
416
|
-
account: event.account,
|
|
417
|
-
timestamp: event.timestamp,
|
|
418
|
-
});
|
|
419
|
-
break;
|
|
420
|
-
|
|
421
|
-
case 'wallet:disconnected':
|
|
422
|
-
analytics.track('Wallet Disconnected');
|
|
423
|
-
break;
|
|
424
|
-
|
|
425
|
-
case 'cluster:changed':
|
|
426
|
-
analytics.track('Network Changed', {
|
|
427
|
-
from: event.previousCluster,
|
|
428
|
-
to: event.cluster,
|
|
429
|
-
});
|
|
430
|
-
break;
|
|
431
|
-
|
|
432
|
-
case 'error':
|
|
433
|
-
errorTracker.captureException(event.error, {
|
|
434
|
-
context: event.context,
|
|
435
|
-
});
|
|
436
|
-
break;
|
|
437
|
-
}
|
|
438
|
-
});
|
|
297
|
+
import { useWalletInfo } from '@solana/connector';
|
|
439
298
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
299
|
+
function Component() {
|
|
300
|
+
const {
|
|
301
|
+
name, // string | null - Wallet name
|
|
302
|
+
icon, // string | undefined - Wallet icon URL
|
|
303
|
+
wallet, // WalletInfo | null - Full wallet info
|
|
304
|
+
connecting, // boolean - Connection in progress
|
|
305
|
+
} = useWalletInfo();
|
|
444
306
|
}
|
|
445
307
|
```
|
|
446
308
|
|
|
447
|
-
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Transaction Signing
|
|
448
312
|
|
|
449
|
-
|
|
450
|
-
- `wallet:disconnected` - Wallet disconnected
|
|
451
|
-
- `wallet:changed` - Selected wallet changed
|
|
452
|
-
- `account:changed` - Selected account changed
|
|
453
|
-
- `cluster:changed` - Network/cluster changed
|
|
454
|
-
- `wallets:detected` - New wallets detected
|
|
455
|
-
- `connecting` - Connection attempt started
|
|
456
|
-
- `connection:failed` - Connection attempt failed
|
|
457
|
-
- `error` - Error occurred
|
|
313
|
+
ConnectorKit provides powerful transaction signing capabilities with support for both legacy `@solana/web3.js` and modern `@solana/kit` APIs.
|
|
458
314
|
|
|
459
|
-
###
|
|
315
|
+
### Modern API (`@solana/kit`)
|
|
460
316
|
|
|
461
|
-
|
|
317
|
+
Use `useKitTransactionSigner()` for modern, type-safe transaction building:
|
|
462
318
|
|
|
463
319
|
```typescript
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
function App() {
|
|
467
|
-
return (
|
|
468
|
-
<ConnectorProvider config={config}>
|
|
469
|
-
{/* Only visible in development mode */}
|
|
470
|
-
{process.env.NODE_ENV === 'development' && <ConnectorDebugPanel />}
|
|
471
|
-
<YourApp />
|
|
472
|
-
</ConnectorProvider>
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
```
|
|
320
|
+
'use client';
|
|
476
321
|
|
|
477
|
-
|
|
322
|
+
import { useState } from 'react';
|
|
323
|
+
import {
|
|
324
|
+
address,
|
|
325
|
+
createSolanaRpc,
|
|
326
|
+
pipe,
|
|
327
|
+
createTransactionMessage,
|
|
328
|
+
setTransactionMessageFeePayerSigner,
|
|
329
|
+
setTransactionMessageLifetimeUsingBlockhash,
|
|
330
|
+
appendTransactionMessageInstructions,
|
|
331
|
+
sendAndConfirmTransactionFactory,
|
|
332
|
+
getSignatureFromTransaction,
|
|
333
|
+
signTransactionMessageWithSigners,
|
|
334
|
+
createSolanaRpcSubscriptions,
|
|
335
|
+
lamports,
|
|
336
|
+
assertIsTransactionWithBlockhashLifetime,
|
|
337
|
+
} from '@solana/kit';
|
|
338
|
+
import { getTransferSolInstruction } from '@solana-program/system';
|
|
339
|
+
import { useKitTransactionSigner, useCluster, useConnectorClient, LAMPORTS_PER_SOL } from '@solana/connector';
|
|
340
|
+
|
|
341
|
+
export function ModernSolTransfer() {
|
|
342
|
+
const { signer, ready } = useKitTransactionSigner();
|
|
343
|
+
const { cluster } = useCluster();
|
|
344
|
+
const client = useConnectorClient();
|
|
345
|
+
const [signature, setSignature] = useState<string | null>(null);
|
|
478
346
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
- Health check information
|
|
484
|
-
- Click to expand/collapse
|
|
485
|
-
- Automatically excluded in production builds
|
|
347
|
+
async function handleTransfer(recipientAddress: string, amount: number) {
|
|
348
|
+
if (!signer || !client) {
|
|
349
|
+
throw new Error('Wallet not connected');
|
|
350
|
+
}
|
|
486
351
|
|
|
487
|
-
|
|
352
|
+
// Get RPC URL from connector client
|
|
353
|
+
const rpcUrl = client.getRpcUrl();
|
|
354
|
+
if (!rpcUrl) {
|
|
355
|
+
throw new Error('No RPC endpoint configured');
|
|
356
|
+
}
|
|
488
357
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
defaultOpen={true}
|
|
493
|
-
zIndex={10000}
|
|
494
|
-
/>
|
|
495
|
-
```
|
|
358
|
+
// Create RPC client using web3.js 2.0
|
|
359
|
+
const rpc = createSolanaRpc(rpcUrl);
|
|
360
|
+
const rpcSubscriptions = createSolanaRpcSubscriptions(rpcUrl.replace('http', 'ws'));
|
|
496
361
|
|
|
497
|
-
|
|
362
|
+
// Get recent blockhash
|
|
363
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
498
364
|
|
|
499
|
-
|
|
365
|
+
// Convert SOL to lamports
|
|
366
|
+
const amountInLamports = lamports(BigInt(Math.floor(amount * Number(LAMPORTS_PER_SOL))));
|
|
500
367
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
const pool = createConnectionPool({
|
|
507
|
-
maxSize: 10,
|
|
508
|
-
createConnection: cluster => {
|
|
509
|
-
return new Connection(cluster.endpoint, {
|
|
510
|
-
commitment: 'confirmed',
|
|
368
|
+
// Create transfer instruction
|
|
369
|
+
const transferInstruction = getTransferSolInstruction({
|
|
370
|
+
source: signer,
|
|
371
|
+
destination: address(recipientAddress),
|
|
372
|
+
amount: amountInLamports,
|
|
511
373
|
});
|
|
512
|
-
},
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
// Get or create connection for a cluster
|
|
516
|
-
const connection = pool.get(currentCluster);
|
|
517
|
-
const balance = await connection.getBalance(publicKey);
|
|
518
374
|
|
|
519
|
-
//
|
|
520
|
-
|
|
375
|
+
// Build transaction message
|
|
376
|
+
const transactionMessage = pipe(
|
|
377
|
+
createTransactionMessage({ version: 0 }),
|
|
378
|
+
tx => setTransactionMessageFeePayerSigner(signer, tx),
|
|
379
|
+
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
|
|
380
|
+
tx => appendTransactionMessageInstructions([transferInstruction], tx),
|
|
381
|
+
);
|
|
521
382
|
|
|
522
|
-
//
|
|
523
|
-
const
|
|
524
|
-
console.log(`Pool: ${stats.size}/${stats.maxSize}`);
|
|
525
|
-
console.log(`Hit rate: ${(stats.hits / (stats.hits + stats.misses)) * 100}%`);
|
|
526
|
-
```
|
|
383
|
+
// Sign transaction
|
|
384
|
+
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
|
|
527
385
|
|
|
528
|
-
|
|
386
|
+
// Send and confirm
|
|
387
|
+
assertIsTransactionWithBlockhashLifetime(signedTransaction);
|
|
388
|
+
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
|
|
389
|
+
commitment: 'confirmed',
|
|
390
|
+
});
|
|
529
391
|
|
|
530
|
-
|
|
531
|
-
|
|
392
|
+
const transactionSignature = getSignatureFromTransaction(signedTransaction);
|
|
393
|
+
setSignature(transactionSignature);
|
|
394
|
+
}
|
|
532
395
|
|
|
533
|
-
|
|
534
|
-
|
|
396
|
+
return (
|
|
397
|
+
<div>
|
|
398
|
+
{/* Your form UI */}
|
|
399
|
+
<button onClick={() => handleTransfer('...', 0.1)} disabled={!ready}>
|
|
400
|
+
Send SOL
|
|
401
|
+
</button>
|
|
402
|
+
{signature && <div>Transaction: {signature}</div>}
|
|
403
|
+
</div>
|
|
404
|
+
);
|
|
405
|
+
}
|
|
535
406
|
```
|
|
536
407
|
|
|
537
|
-
###
|
|
408
|
+
### Legacy API (`@solana/web3.js`)
|
|
538
409
|
|
|
539
|
-
|
|
410
|
+
Use `useTransactionSigner()` for legacy web3.js compatibility:
|
|
540
411
|
|
|
541
412
|
```typescript
|
|
542
|
-
import {
|
|
413
|
+
import { useTransactionSigner } from '@solana/connector';
|
|
414
|
+
import { Transaction, SystemProgram } from '@solana/web3.js';
|
|
543
415
|
|
|
544
|
-
function
|
|
545
|
-
|
|
416
|
+
function SendTransaction() {
|
|
417
|
+
const { signer, ready } = useTransactionSigner();
|
|
546
418
|
|
|
547
|
-
|
|
419
|
+
const handleSend = async () => {
|
|
420
|
+
if (!signer) return;
|
|
548
421
|
|
|
549
|
-
|
|
422
|
+
const transaction = new Transaction().add(
|
|
423
|
+
SystemProgram.transfer({
|
|
424
|
+
fromPubkey: signer.address,
|
|
425
|
+
toPubkey: recipientPubkey,
|
|
426
|
+
lamports: 1000000,
|
|
427
|
+
})
|
|
428
|
+
);
|
|
550
429
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
<div>Initialized: {health.initialized ? '✓' : '✗'}</div>
|
|
555
|
-
<div>Wallet Standard: {health.walletStandardAvailable ? '✓' : '✗'}</div>
|
|
556
|
-
<div>Storage: {health.storageAvailable ? '✓' : '✗'}</div>
|
|
557
|
-
<div>Wallets Detected: {health.walletsDetected}</div>
|
|
430
|
+
const signature = await signer.signAndSendTransaction(transaction);
|
|
431
|
+
console.log('Transaction sent:', signature);
|
|
432
|
+
};
|
|
558
433
|
|
|
559
|
-
|
|
560
|
-
<div className="errors">
|
|
561
|
-
{health.errors.map(err => <div key={err}>{err}</div>)}
|
|
562
|
-
</div>
|
|
563
|
-
)}
|
|
564
|
-
</div>
|
|
565
|
-
);
|
|
434
|
+
return <button onClick={handleSend} disabled={!ready}>Send</button>;
|
|
566
435
|
}
|
|
567
436
|
```
|
|
568
437
|
|
|
569
|
-
|
|
438
|
+
---
|
|
570
439
|
|
|
571
|
-
|
|
440
|
+
## UI Elements
|
|
572
441
|
|
|
573
|
-
|
|
574
|
-
import { useTransactionSigner, useConnector } from '@solana/connector';
|
|
575
|
-
import { createWalletAdapterCompat } from '@solana/connector/compat';
|
|
442
|
+
ConnectorKit provides composable UI elements that handle data fetching and state management for you. Use the render prop pattern to customize the UI.
|
|
576
443
|
|
|
577
|
-
|
|
578
|
-
const { signer } = useTransactionSigner();
|
|
579
|
-
const { disconnect } = useConnector();
|
|
444
|
+
### Available Elements
|
|
580
445
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
}
|
|
589
|
-
});
|
|
446
|
+
- `BalanceElement` - Display SOL balance with refresh
|
|
447
|
+
- `ClusterElement` - Network/cluster selector
|
|
448
|
+
- `TokenListElement` - List of SPL tokens
|
|
449
|
+
- `TransactionHistoryElement` - Recent transaction history
|
|
450
|
+
- `DisconnectElement` - Disconnect button
|
|
451
|
+
- `AccountElement` - Account display and switcher
|
|
452
|
+
- `WalletListElement` - List of available wallets
|
|
590
453
|
|
|
591
|
-
|
|
592
|
-
return <JupiterTerminal wallet={walletAdapter} />;
|
|
593
|
-
}
|
|
594
|
-
```
|
|
454
|
+
### Example: Wallet Dropdown
|
|
595
455
|
|
|
596
|
-
|
|
456
|
+
```typescript
|
|
457
|
+
'use client';
|
|
597
458
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
459
|
+
import {
|
|
460
|
+
BalanceElement,
|
|
461
|
+
ClusterElement,
|
|
462
|
+
TokenListElement,
|
|
463
|
+
TransactionHistoryElement,
|
|
464
|
+
DisconnectElement,
|
|
465
|
+
} from '@solana/connector/react';
|
|
466
|
+
|
|
467
|
+
export function WalletDropdown() {
|
|
468
|
+
return (
|
|
469
|
+
<div className="wallet-dropdown">
|
|
470
|
+
{/* Balance */}
|
|
471
|
+
<BalanceElement
|
|
472
|
+
render={({ solBalance, isLoading, refetch }) => (
|
|
473
|
+
<div>
|
|
474
|
+
<div>Balance: {isLoading ? '...' : `${solBalance?.toFixed(4)} SOL`}</div>
|
|
475
|
+
<button onClick={refetch}>Refresh</button>
|
|
476
|
+
</div>
|
|
477
|
+
)}
|
|
478
|
+
/>
|
|
479
|
+
|
|
480
|
+
{/* Network Selector */}
|
|
481
|
+
<ClusterElement
|
|
482
|
+
render={({ cluster, clusters, setCluster }) => (
|
|
483
|
+
<select value={cluster?.id} onChange={e => setCluster(e.target.value)}>
|
|
484
|
+
{clusters.map(c => (
|
|
485
|
+
<option key={c.id} value={c.id}>
|
|
486
|
+
{c.label}
|
|
487
|
+
</option>
|
|
488
|
+
))}
|
|
489
|
+
</select>
|
|
490
|
+
)}
|
|
491
|
+
/>
|
|
492
|
+
|
|
493
|
+
{/* Tokens */}
|
|
494
|
+
<TokenListElement
|
|
495
|
+
limit={5}
|
|
496
|
+
render={({ tokens, isLoading }) => (
|
|
497
|
+
<div>
|
|
498
|
+
{isLoading ? (
|
|
499
|
+
<div>Loading tokens...</div>
|
|
500
|
+
) : (
|
|
501
|
+
tokens.map(token => (
|
|
502
|
+
<div key={token.mint}>
|
|
503
|
+
{token.symbol}: {token.formatted}
|
|
504
|
+
</div>
|
|
505
|
+
))
|
|
506
|
+
)}
|
|
507
|
+
</div>
|
|
508
|
+
)}
|
|
509
|
+
/>
|
|
510
|
+
|
|
511
|
+
{/* Transaction History */}
|
|
512
|
+
<TransactionHistoryElement
|
|
513
|
+
limit={5}
|
|
514
|
+
render={({ transactions, isLoading }) => (
|
|
515
|
+
<div>
|
|
516
|
+
{isLoading ? (
|
|
517
|
+
<div>Loading transactions...</div>
|
|
518
|
+
) : (
|
|
519
|
+
transactions.map(tx => (
|
|
520
|
+
<a key={tx.signature} href={tx.explorerUrl} target="_blank">
|
|
521
|
+
{tx.type} - {tx.formattedTime}
|
|
522
|
+
</a>
|
|
523
|
+
))
|
|
524
|
+
)}
|
|
525
|
+
</div>
|
|
526
|
+
)}
|
|
527
|
+
/>
|
|
528
|
+
|
|
529
|
+
{/* Disconnect */}
|
|
530
|
+
<DisconnectElement
|
|
531
|
+
render={({ disconnect, disconnecting }) => (
|
|
532
|
+
<button onClick={disconnect} disabled={disconnecting}>
|
|
533
|
+
{disconnecting ? 'Disconnecting...' : 'Disconnect'}
|
|
534
|
+
</button>
|
|
535
|
+
)}
|
|
536
|
+
/>
|
|
537
|
+
</div>
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
```
|
|
603
541
|
|
|
604
542
|
---
|
|
605
543
|
|
|
@@ -612,16 +550,11 @@ import { getDefaultConfig } from '@solana/connector';
|
|
|
612
550
|
|
|
613
551
|
const config = getDefaultConfig({
|
|
614
552
|
appName: 'My App', // Required
|
|
553
|
+
appUrl: 'https://myapp.com', // Optional: for mobile wallet adapter
|
|
615
554
|
autoConnect: true, // Auto-reconnect (default: true)
|
|
616
|
-
network: 'mainnet-beta', // Initial network
|
|
555
|
+
network: 'mainnet-beta', // Initial network (default: 'mainnet-beta')
|
|
617
556
|
enableMobile: true, // Mobile Wallet Adapter (default: true)
|
|
618
557
|
debug: false, // Debug logging
|
|
619
|
-
|
|
620
|
-
// NEW: Custom error handler
|
|
621
|
-
onError: (error, errorInfo) => {
|
|
622
|
-
console.error('Connector error:', error);
|
|
623
|
-
errorTracker.captureException(error, errorInfo);
|
|
624
|
-
},
|
|
625
558
|
});
|
|
626
559
|
```
|
|
627
560
|
|
|
@@ -634,20 +567,26 @@ const config = getDefaultConfig({
|
|
|
634
567
|
});
|
|
635
568
|
```
|
|
636
569
|
|
|
637
|
-
### Custom
|
|
570
|
+
### Custom RPC Endpoints
|
|
638
571
|
|
|
639
572
|
```typescript
|
|
640
|
-
import { getDefaultConfig
|
|
573
|
+
import { getDefaultConfig } from '@solana/connector';
|
|
641
574
|
|
|
642
575
|
const config = getDefaultConfig({
|
|
643
576
|
appName: 'My App',
|
|
644
577
|
clusters: [
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
578
|
+
{
|
|
579
|
+
id: 'solana:mainnet' as const,
|
|
580
|
+
label: 'Mainnet (Custom RPC)',
|
|
581
|
+
name: 'mainnet-beta' as const,
|
|
582
|
+
url: 'https://my-custom-rpc.com',
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
id: 'solana:devnet' as const,
|
|
586
|
+
label: 'Devnet',
|
|
587
|
+
name: 'devnet' as const,
|
|
588
|
+
url: 'https://api.devnet.solana.com',
|
|
589
|
+
},
|
|
651
590
|
],
|
|
652
591
|
});
|
|
653
592
|
```
|
|
@@ -655,18 +594,16 @@ const config = getDefaultConfig({
|
|
|
655
594
|
### Mobile Wallet Adapter
|
|
656
595
|
|
|
657
596
|
```typescript
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
>
|
|
668
|
-
<App />
|
|
669
|
-
</ConnectorProvider>
|
|
597
|
+
import { getDefaultMobileConfig } from '@solana/connector/headless';
|
|
598
|
+
|
|
599
|
+
const mobile = getDefaultMobileConfig({
|
|
600
|
+
appName: 'My App',
|
|
601
|
+
appUrl: 'https://myapp.com',
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
<AppProvider connectorConfig={config} mobile={mobile}>
|
|
605
|
+
{children}
|
|
606
|
+
</AppProvider>
|
|
670
607
|
```
|
|
671
608
|
|
|
672
609
|
---
|
|
@@ -675,7 +612,7 @@ const config = getDefaultConfig({
|
|
|
675
612
|
|
|
676
613
|
### Headless Client (Vue, Svelte, Vanilla JS)
|
|
677
614
|
|
|
678
|
-
Use `ConnectorClient` for non-React frameworks
|
|
615
|
+
Use `ConnectorClient` for non-React frameworks:
|
|
679
616
|
|
|
680
617
|
```typescript
|
|
681
618
|
import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
|
|
@@ -695,15 +632,6 @@ const unsubscribe = client.subscribe(state => {
|
|
|
695
632
|
console.log('State updated:', state);
|
|
696
633
|
});
|
|
697
634
|
|
|
698
|
-
// Subscribe to events (NEW!)
|
|
699
|
-
const unsubEvents = client.on(event => {
|
|
700
|
-
console.log('Event:', event.type, event);
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
// Check health (NEW!)
|
|
704
|
-
const health = client.getHealth();
|
|
705
|
-
console.log('Health:', health);
|
|
706
|
-
|
|
707
635
|
// Disconnect
|
|
708
636
|
await client.disconnect();
|
|
709
637
|
|
|
@@ -711,44 +639,15 @@ await client.disconnect();
|
|
|
711
639
|
client.destroy();
|
|
712
640
|
```
|
|
713
641
|
|
|
714
|
-
###
|
|
715
|
-
|
|
716
|
-
If you're using both ConnectorKit and Armadura:
|
|
717
|
-
|
|
718
|
-
```typescript
|
|
719
|
-
import { createConfig, AppProvider } from '@solana/connector';
|
|
720
|
-
import { ArmaProvider } from '@armadura/sdk';
|
|
721
|
-
|
|
722
|
-
const config = createConfig({
|
|
723
|
-
appName: 'My App',
|
|
724
|
-
network: 'mainnet',
|
|
725
|
-
rpcUrl: 'https://my-custom-rpc.com',
|
|
726
|
-
autoConnect: true
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
function App() {
|
|
730
|
-
return (
|
|
731
|
-
<AppProvider config={config.connectorConfig}>
|
|
732
|
-
<ArmaProvider
|
|
733
|
-
config={{
|
|
734
|
-
network: config.network,
|
|
735
|
-
rpcUrl: config.rpcUrl,
|
|
736
|
-
providers: [/* ... */]
|
|
737
|
-
}}
|
|
738
|
-
useConnector="auto"
|
|
739
|
-
>
|
|
740
|
-
{children}
|
|
741
|
-
</ArmaProvider>
|
|
742
|
-
</AppProvider>
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
```
|
|
642
|
+
### Custom Storage (React Native, SSR)
|
|
746
643
|
|
|
747
|
-
|
|
644
|
+
Storage uses nanostores with built-in enhancements that are **automatically applied**:
|
|
748
645
|
|
|
749
|
-
|
|
646
|
+
- Validation (Solana address format checking)
|
|
647
|
+
- Error handling (catches localStorage quota errors, private browsing)
|
|
648
|
+
- SSR fallback (uses memory storage when localStorage unavailable)
|
|
750
649
|
|
|
751
|
-
Only customize for:
|
|
650
|
+
**Most users don't need to configure storage.** Only customize for:
|
|
752
651
|
|
|
753
652
|
- React Native (custom storage backend)
|
|
754
653
|
- Additional validation rules
|
|
@@ -759,7 +658,6 @@ import { getDefaultConfig, createEnhancedStorageWallet, EnhancedStorageAdapter }
|
|
|
759
658
|
|
|
760
659
|
const config = getDefaultConfig({
|
|
761
660
|
appName: 'My App',
|
|
762
|
-
|
|
763
661
|
storage: {
|
|
764
662
|
wallet: new EnhancedStorageAdapter(
|
|
765
663
|
createEnhancedStorageWallet({
|
|
@@ -768,11 +666,11 @@ const config = getDefaultConfig({
|
|
|
768
666
|
return walletName !== null && walletName.length > 0;
|
|
769
667
|
},
|
|
770
668
|
onError: error => {
|
|
669
|
+
// Custom error tracking
|
|
771
670
|
Sentry.captureException(error);
|
|
772
671
|
},
|
|
773
672
|
}),
|
|
774
673
|
),
|
|
775
|
-
// account and cluster use defaults if not specified
|
|
776
674
|
},
|
|
777
675
|
});
|
|
778
676
|
```
|
|
@@ -785,7 +683,7 @@ const config = getDefaultConfig({
|
|
|
785
683
|
|
|
786
684
|
```typescript
|
|
787
685
|
// Full library - includes React and headless
|
|
788
|
-
import { ConnectorProvider, useConnector } from '@solana/connector';
|
|
686
|
+
import { ConnectorProvider, useConnector, useAccount } from '@solana/connector';
|
|
789
687
|
```
|
|
790
688
|
|
|
791
689
|
### Headless Export (Framework Agnostic)
|
|
@@ -802,427 +700,58 @@ import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
|
|
|
802
700
|
import { useConnector, useAccount } from '@solana/connector/react';
|
|
803
701
|
```
|
|
804
702
|
|
|
805
|
-
### Compatibility Layer (NEW!)
|
|
806
|
-
|
|
807
|
-
```typescript
|
|
808
|
-
// Wallet adapter compatibility bridge
|
|
809
|
-
import { createWalletAdapterCompat } from '@solana/connector/compat';
|
|
810
|
-
```
|
|
811
|
-
|
|
812
703
|
---
|
|
813
704
|
|
|
814
|
-
##
|
|
815
|
-
|
|
816
|
-
The connector package includes a comprehensive test suite built with Vitest. All tests are located in `src/__tests__/` and co-located with source files.
|
|
817
|
-
|
|
818
|
-
### Running Tests
|
|
819
|
-
|
|
820
|
-
```bash
|
|
821
|
-
# Run all tests
|
|
822
|
-
pnpm test
|
|
823
|
-
|
|
824
|
-
# Run tests in watch mode
|
|
825
|
-
pnpm test:watch
|
|
826
|
-
|
|
827
|
-
# Run tests with UI
|
|
828
|
-
pnpm test:ui
|
|
829
|
-
|
|
830
|
-
# Generate coverage report
|
|
831
|
-
pnpm test:coverage
|
|
832
|
-
```
|
|
833
|
-
|
|
834
|
-
### Test Coverage
|
|
835
|
-
|
|
836
|
-
The package maintains high test coverage:
|
|
837
|
-
|
|
838
|
-
- **Lines**: 80%+
|
|
839
|
-
- **Functions**: 80%+
|
|
840
|
-
- **Branches**: 75%+
|
|
841
|
-
- **Statements**: 80%+
|
|
842
|
-
|
|
843
|
-
### Test Structure
|
|
844
|
-
|
|
845
|
-
```
|
|
846
|
-
src/
|
|
847
|
-
├── lib/
|
|
848
|
-
│ ├── core/
|
|
849
|
-
│ │ ├── state-manager.ts
|
|
850
|
-
│ │ └── state-manager.test.ts # Unit tests
|
|
851
|
-
│ └── connection/
|
|
852
|
-
│ ├── connection-manager.ts
|
|
853
|
-
│ └── connection-manager.test.ts # Unit tests
|
|
854
|
-
├── hooks/
|
|
855
|
-
│ ├── use-account.ts
|
|
856
|
-
│ └── use-account.test.tsx # React hook tests
|
|
857
|
-
└── __tests__/
|
|
858
|
-
├── setup.ts # Global test setup
|
|
859
|
-
├── mocks/ # Mock implementations
|
|
860
|
-
│ ├── wallet-standard-mock.ts # Mock wallets
|
|
861
|
-
│ ├── storage-mock.ts # Mock storage
|
|
862
|
-
│ └── window-mock.ts # Mock browser APIs
|
|
863
|
-
├── fixtures/ # Test data
|
|
864
|
-
│ ├── wallets.ts # Wallet fixtures
|
|
865
|
-
│ ├── accounts.ts # Account fixtures
|
|
866
|
-
│ └── transactions.ts # Transaction fixtures
|
|
867
|
-
├── utils/ # Test helpers
|
|
868
|
-
│ ├── test-helpers.ts # Common utilities
|
|
869
|
-
│ ├── react-helpers.tsx # React test utils
|
|
870
|
-
│ └── wait-for-state.ts # State helpers
|
|
871
|
-
└── integration/ # Integration tests
|
|
872
|
-
└── connector-flow.test.ts # Full workflows
|
|
873
|
-
```
|
|
874
|
-
|
|
875
|
-
### Writing Tests
|
|
876
|
-
|
|
877
|
-
Example unit test:
|
|
878
|
-
|
|
879
|
-
```typescript
|
|
880
|
-
import { describe, it, expect } from 'vitest';
|
|
881
|
-
import { StateManager } from './state-manager';
|
|
882
|
-
|
|
883
|
-
describe('StateManager', () => {
|
|
884
|
-
it('should update state correctly', () => {
|
|
885
|
-
const manager = new StateManager(initialState);
|
|
886
|
-
manager.updateState({ connected: true });
|
|
887
|
-
|
|
888
|
-
expect(manager.getSnapshot().connected).toBe(true);
|
|
889
|
-
});
|
|
890
|
-
});
|
|
891
|
-
```
|
|
892
|
-
|
|
893
|
-
Example React hook test:
|
|
894
|
-
|
|
895
|
-
```typescript
|
|
896
|
-
import { renderHook } from '@testing-library/react';
|
|
897
|
-
import { useAccount } from './use-account';
|
|
898
|
-
import { createHookWrapper } from '../__tests__/utils/react-helpers';
|
|
899
|
-
|
|
900
|
-
describe('useAccount', () => {
|
|
901
|
-
it('should return account information', () => {
|
|
902
|
-
const { result } = renderHook(() => useAccount(), {
|
|
903
|
-
wrapper: createHookWrapper(),
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
expect(result.current.address).toBeDefined();
|
|
907
|
-
});
|
|
908
|
-
});
|
|
909
|
-
```
|
|
910
|
-
|
|
911
|
-
### Test Utilities
|
|
912
|
-
|
|
913
|
-
The package provides comprehensive test utilities:
|
|
914
|
-
|
|
915
|
-
**Mock Wallets:**
|
|
916
|
-
|
|
917
|
-
```typescript
|
|
918
|
-
import { createMockPhantomWallet, createMockSolflareWallet } from '../mocks/wallet-standard-mock';
|
|
919
|
-
|
|
920
|
-
const wallet = createMockPhantomWallet({
|
|
921
|
-
connectBehavior: 'success', // or 'error', 'timeout'
|
|
922
|
-
});
|
|
923
|
-
```
|
|
924
|
-
|
|
925
|
-
**Test Fixtures:**
|
|
926
|
-
|
|
927
|
-
```typescript
|
|
928
|
-
import { createTestAccounts, TEST_ADDRESSES } from '../fixtures/accounts';
|
|
929
|
-
import { createTestWallets } from '../fixtures/wallets';
|
|
930
|
-
|
|
931
|
-
const accounts = createTestAccounts(3);
|
|
932
|
-
const wallets = createTestWallets();
|
|
933
|
-
```
|
|
934
|
-
|
|
935
|
-
**Test Helpers:**
|
|
936
|
-
|
|
937
|
-
```typescript
|
|
938
|
-
import { waitForCondition, createEventCollector } from '../utils/test-helpers';
|
|
939
|
-
|
|
940
|
-
// Wait for a condition
|
|
941
|
-
await waitForCondition(() => state.connected, { timeout: 5000 });
|
|
942
|
-
|
|
943
|
-
// Collect events
|
|
944
|
-
const collector = createEventCollector();
|
|
945
|
-
client.on(collector.collect);
|
|
946
|
-
collector.assertEventEmitted('connected');
|
|
947
|
-
```
|
|
705
|
+
## API Reference
|
|
948
706
|
|
|
949
|
-
###
|
|
707
|
+
### Hooks
|
|
950
708
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
## Complete API Reference
|
|
709
|
+
| Hook | Description | Returns |
|
|
710
|
+
|------|-------------|---------|
|
|
711
|
+
| `useConnector()` | Main wallet connection hook | `{ wallets, selectedWallet, accounts, connected, connecting, select, disconnect }` |
|
|
712
|
+
| `useAccount()` | Account management hook | `{ address, formatted, copy, copied, accounts, selectAccount }` |
|
|
713
|
+
| `useCluster()` | Network/cluster management hook | `{ cluster, clusters, setCluster, isMainnet, isDevnet, rpcUrl }` |
|
|
714
|
+
| `useWalletInfo()` | Wallet metadata hook | `{ name, icon, wallet, connecting }` |
|
|
715
|
+
| `useTransactionSigner()` | Legacy transaction signer (web3.js) | `{ signer, ready, address, capabilities }` |
|
|
716
|
+
| `useKitTransactionSigner()` | Modern transaction signer (@solana/kit) | `{ signer, ready, address }` |
|
|
717
|
+
| `useBalance()` | SOL balance hook | `{ solBalance, isLoading, refetch }` |
|
|
718
|
+
| `useTokens()` | SPL tokens hook | `{ tokens, isLoading, refetch }` |
|
|
719
|
+
| `useTransactions()` | Transaction history hook | `{ transactions, isLoading, refetch }` |
|
|
963
720
|
|
|
964
721
|
### Configuration Functions
|
|
965
722
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
appUrl?: string, // App URL for metadata
|
|
972
|
-
autoConnect?: boolean, // Auto-reconnect (default: true)
|
|
973
|
-
debug?: boolean, // Debug logging
|
|
974
|
-
network?: 'mainnet' | 'mainnet-beta' // Initial network (default: mainnet-beta)
|
|
975
|
-
| 'devnet' | 'testnet' | 'localnet',
|
|
976
|
-
enableMobile?: boolean, // Mobile Wallet Adapter (default: true)
|
|
977
|
-
storage?: ConnectorConfig['storage'], // Custom storage adapters
|
|
978
|
-
clusters?: SolanaCluster[], // Override default clusters
|
|
979
|
-
customClusters?: SolanaCluster[], // Add custom clusters
|
|
980
|
-
persistClusterSelection?: boolean, // Persist cluster (default: true)
|
|
981
|
-
enableErrorBoundary?: boolean, // Error boundaries (default: true)
|
|
982
|
-
maxRetries?: number, // Retry attempts (default: 3)
|
|
983
|
-
onError?: (error, errorInfo) => void // Error handler (NEW!)
|
|
984
|
-
});
|
|
985
|
-
```
|
|
986
|
-
|
|
987
|
-
### Transaction Signing API (NEW!)
|
|
988
|
-
|
|
989
|
-
#### `useTransactionSigner()`
|
|
990
|
-
|
|
991
|
-
React hook for transaction operations.
|
|
992
|
-
|
|
993
|
-
```typescript
|
|
994
|
-
interface UseTransactionSignerReturn {
|
|
995
|
-
signer: TransactionSigner | null; // Signer instance
|
|
996
|
-
ready: boolean; // Whether signer is ready
|
|
997
|
-
address: string | null; // Current address
|
|
998
|
-
capabilities: TransactionSignerCapabilities; // What signer can do
|
|
999
|
-
}
|
|
1000
|
-
```
|
|
1001
|
-
|
|
1002
|
-
#### `createTransactionSigner(config)`
|
|
1003
|
-
|
|
1004
|
-
Create a transaction signer (headless).
|
|
1005
|
-
|
|
1006
|
-
```typescript
|
|
1007
|
-
import { createTransactionSigner } from '@solana/connector/headless';
|
|
1008
|
-
|
|
1009
|
-
const signer = createTransactionSigner({
|
|
1010
|
-
wallet: connectedWallet,
|
|
1011
|
-
account: selectedAccount,
|
|
1012
|
-
cluster: currentCluster, // Optional
|
|
1013
|
-
});
|
|
1014
|
-
```
|
|
1015
|
-
|
|
1016
|
-
#### `TransactionSigner` Interface
|
|
1017
|
-
|
|
1018
|
-
```typescript
|
|
1019
|
-
interface TransactionSigner {
|
|
1020
|
-
readonly address: string;
|
|
1021
|
-
|
|
1022
|
-
signTransaction(tx: any): Promise<any>;
|
|
1023
|
-
signAllTransactions(txs: any[]): Promise<any[]>;
|
|
1024
|
-
signAndSendTransaction(tx: any, options?: SendOptions): Promise<string>;
|
|
1025
|
-
signAndSendTransactions(txs: any[], options?: SendOptions): Promise<string[]>;
|
|
1026
|
-
signMessage?(message: Uint8Array): Promise<Uint8Array>;
|
|
1027
|
-
|
|
1028
|
-
getCapabilities(): TransactionSignerCapabilities;
|
|
1029
|
-
}
|
|
1030
|
-
```
|
|
1031
|
-
|
|
1032
|
-
### Event System API (NEW!)
|
|
1033
|
-
|
|
1034
|
-
#### Event Types
|
|
1035
|
-
|
|
1036
|
-
```typescript
|
|
1037
|
-
type ConnectorEvent =
|
|
1038
|
-
| { type: 'wallet:connected'; wallet: string; account: string; timestamp: string }
|
|
1039
|
-
| { type: 'wallet:disconnected'; timestamp: string }
|
|
1040
|
-
| { type: 'cluster:changed'; cluster: string; previousCluster: string | null; timestamp: string }
|
|
1041
|
-
| { type: 'wallets:detected'; count: number; timestamp: string }
|
|
1042
|
-
| { type: 'connecting'; wallet: string; timestamp: string }
|
|
1043
|
-
| { type: 'connection:failed'; wallet: string; error: string; timestamp: string }
|
|
1044
|
-
| { type: 'error'; error: Error; context: string; timestamp: string };
|
|
1045
|
-
```
|
|
1046
|
-
|
|
1047
|
-
#### Methods
|
|
1048
|
-
|
|
1049
|
-
```typescript
|
|
1050
|
-
// Subscribe to events
|
|
1051
|
-
const unsubscribe = client.on(event => {
|
|
1052
|
-
console.log('Event:', event.type, event);
|
|
1053
|
-
});
|
|
1054
|
-
|
|
1055
|
-
// Unsubscribe
|
|
1056
|
-
client.off(listener);
|
|
1057
|
-
|
|
1058
|
-
// Unsubscribe all
|
|
1059
|
-
client.offAll();
|
|
1060
|
-
```
|
|
1061
|
-
|
|
1062
|
-
### Health Check API (NEW!)
|
|
1063
|
-
|
|
1064
|
-
```typescript
|
|
1065
|
-
interface ConnectorHealth {
|
|
1066
|
-
initialized: boolean;
|
|
1067
|
-
walletStandardAvailable: boolean;
|
|
1068
|
-
storageAvailable: boolean;
|
|
1069
|
-
walletsDetected: number;
|
|
1070
|
-
errors: string[];
|
|
1071
|
-
connectionState: {
|
|
1072
|
-
connected: boolean;
|
|
1073
|
-
connecting: boolean;
|
|
1074
|
-
hasSelectedWallet: boolean;
|
|
1075
|
-
hasSelectedAccount: boolean;
|
|
1076
|
-
};
|
|
1077
|
-
timestamp: string;
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
// Get health status
|
|
1081
|
-
const health = client.getHealth();
|
|
1082
|
-
```
|
|
1083
|
-
|
|
1084
|
-
### Connection Pool API (NEW!)
|
|
1085
|
-
|
|
1086
|
-
```typescript
|
|
1087
|
-
class ConnectionPool {
|
|
1088
|
-
get(cluster: SolanaCluster): ConnectionLike;
|
|
1089
|
-
has(clusterId: string): boolean;
|
|
1090
|
-
clear(clusterId: string): void;
|
|
1091
|
-
clearAll(): void;
|
|
1092
|
-
getStats(): ConnectionPoolStats;
|
|
1093
|
-
resetStats(): void;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
// Create pool
|
|
1097
|
-
const pool = createConnectionPool(options);
|
|
1098
|
-
|
|
1099
|
-
// Get global pool
|
|
1100
|
-
const pool = getConnectionPool();
|
|
1101
|
-
```
|
|
1102
|
-
|
|
1103
|
-
### Wallet Adapter Compat API (NEW!)
|
|
1104
|
-
|
|
1105
|
-
```typescript
|
|
1106
|
-
// Create wallet-adapter compatible interface
|
|
1107
|
-
createWalletAdapterCompat(
|
|
1108
|
-
signer: TransactionSigner | null,
|
|
1109
|
-
options: {
|
|
1110
|
-
disconnect: () => Promise<void>;
|
|
1111
|
-
transformTransaction?: (tx: any) => any;
|
|
1112
|
-
onError?: (error: Error, operation: string) => void;
|
|
1113
|
-
}
|
|
1114
|
-
): WalletAdapterCompatible
|
|
1115
|
-
|
|
1116
|
-
// React hook version
|
|
1117
|
-
useWalletAdapterCompat(
|
|
1118
|
-
signer: TransactionSigner | null,
|
|
1119
|
-
disconnect: () => Promise<void>,
|
|
1120
|
-
options?: Omit<WalletAdapterCompatOptions, 'disconnect'>
|
|
1121
|
-
): WalletAdapterCompatible
|
|
1122
|
-
|
|
1123
|
-
// Type guard
|
|
1124
|
-
isWalletAdapterCompatible(obj: any): obj is WalletAdapterCompatible
|
|
1125
|
-
```
|
|
1126
|
-
|
|
1127
|
-
### Polyfill API (NEW!)
|
|
1128
|
-
|
|
1129
|
-
```typescript
|
|
1130
|
-
import {
|
|
1131
|
-
installPolyfills,
|
|
1132
|
-
isPolyfillInstalled,
|
|
1133
|
-
isCryptoAvailable,
|
|
1134
|
-
getPolyfillStatus,
|
|
1135
|
-
} from '@solana/connector/headless';
|
|
1136
|
-
|
|
1137
|
-
// Install browser polyfills (automatic in React provider)
|
|
1138
|
-
installPolyfills();
|
|
1139
|
-
|
|
1140
|
-
// Check status
|
|
1141
|
-
const installed = isPolyfillInstalled();
|
|
1142
|
-
const cryptoAvailable = isCryptoAvailable();
|
|
1143
|
-
const status = getPolyfillStatus();
|
|
1144
|
-
```
|
|
723
|
+
| Function | Description |
|
|
724
|
+
|----------|-------------|
|
|
725
|
+
| `getDefaultConfig(options)` | Create default connector configuration |
|
|
726
|
+
| `getDefaultMobileConfig(options)` | Create mobile wallet adapter configuration |
|
|
727
|
+
| `createConfig(options)` | Create unified config for ConnectorKit + Armadura |
|
|
1145
728
|
|
|
1146
729
|
### Utility Functions
|
|
1147
730
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
// Format addresses
|
|
1157
|
-
formatAddress(address, { length: 6 }); // "5Gv8yU...8x3kF"
|
|
1158
|
-
|
|
1159
|
-
// Lightweight versions (smaller bundle, no Intl)
|
|
1160
|
-
import { formatSOLSimple, formatAddressSimple } from '@solana/connector';
|
|
1161
|
-
```
|
|
1162
|
-
|
|
1163
|
-
#### Clipboard
|
|
1164
|
-
|
|
1165
|
-
```typescript
|
|
1166
|
-
import { copyAddressToClipboard, copyToClipboard } from '@solana/connector';
|
|
1167
|
-
|
|
1168
|
-
await copyAddressToClipboard(address);
|
|
1169
|
-
await copyToClipboard(text);
|
|
1170
|
-
```
|
|
1171
|
-
|
|
1172
|
-
#### Cluster Utilities
|
|
731
|
+
| Function | Description |
|
|
732
|
+
|----------|-------------|
|
|
733
|
+
| `formatAddress(address, options?)` | Format Solana address |
|
|
734
|
+
| `formatSOL(lamports, options?)` | Format SOL amount |
|
|
735
|
+
| `copyAddressToClipboard(address)` | Copy address to clipboard |
|
|
736
|
+
| `getTransactionUrl(cluster, signature)` | Get Solana Explorer transaction URL |
|
|
737
|
+
| `getAddressUrl(cluster, address)` | Get Solana Explorer address URL |
|
|
1173
738
|
|
|
1174
|
-
|
|
1175
|
-
import {
|
|
1176
|
-
getClusterRpcUrl,
|
|
1177
|
-
getClusterExplorerUrl,
|
|
1178
|
-
getTransactionUrl,
|
|
1179
|
-
getAddressUrl,
|
|
1180
|
-
isMainnetCluster,
|
|
1181
|
-
isDevnetCluster,
|
|
1182
|
-
} from '@solana/connector';
|
|
1183
|
-
|
|
1184
|
-
const rpcUrl = getClusterRpcUrl(cluster);
|
|
1185
|
-
const explorerUrl = getClusterExplorerUrl(cluster);
|
|
1186
|
-
const txUrl = getTransactionUrl(cluster, signature);
|
|
1187
|
-
const addrUrl = getAddressUrl(cluster, address);
|
|
1188
|
-
```
|
|
739
|
+
---
|
|
1189
740
|
|
|
1190
|
-
|
|
741
|
+
## Types
|
|
1191
742
|
|
|
1192
743
|
```typescript
|
|
1193
744
|
import type {
|
|
1194
745
|
// Configuration
|
|
1195
746
|
ConnectorConfig,
|
|
1196
747
|
DefaultConfigOptions,
|
|
1197
|
-
ExtendedConnectorConfig,
|
|
1198
748
|
UnifiedConfig,
|
|
1199
|
-
MobileWalletAdapterConfig,
|
|
1200
749
|
|
|
1201
750
|
// State & Info
|
|
1202
751
|
ConnectorState,
|
|
1203
752
|
ConnectorSnapshot,
|
|
1204
753
|
WalletInfo,
|
|
1205
754
|
AccountInfo,
|
|
1206
|
-
ConnectorHealth, // NEW!
|
|
1207
|
-
|
|
1208
|
-
// Events
|
|
1209
|
-
ConnectorEvent, // NEW!
|
|
1210
|
-
ConnectorEventListener, // NEW!
|
|
1211
|
-
|
|
1212
|
-
// Transaction Signing
|
|
1213
|
-
TransactionSigner, // NEW!
|
|
1214
|
-
TransactionSignerConfig, // NEW!
|
|
1215
|
-
TransactionSignerCapabilities, // NEW!
|
|
1216
|
-
SignedTransaction, // NEW!
|
|
1217
|
-
|
|
1218
|
-
// Connection Pooling
|
|
1219
|
-
ConnectionLike, // NEW!
|
|
1220
|
-
ConnectionPoolOptions, // NEW!
|
|
1221
|
-
ConnectionPoolStats, // NEW!
|
|
1222
|
-
|
|
1223
|
-
// Wallet Adapter Compat
|
|
1224
|
-
WalletAdapterCompatible, // NEW!
|
|
1225
|
-
WalletAdapterCompatOptions, // NEW!
|
|
1226
755
|
|
|
1227
756
|
// Wallet Standard
|
|
1228
757
|
Wallet,
|
|
@@ -1232,101 +761,17 @@ import type {
|
|
|
1232
761
|
SolanaCluster,
|
|
1233
762
|
SolanaClusterId,
|
|
1234
763
|
|
|
1235
|
-
// Storage
|
|
1236
|
-
StorageAdapter,
|
|
1237
|
-
|
|
1238
764
|
// Hook Returns
|
|
1239
765
|
UseClusterReturn,
|
|
1240
766
|
UseAccountReturn,
|
|
1241
767
|
UseWalletInfoReturn,
|
|
1242
|
-
UseTransactionSignerReturn,
|
|
1243
|
-
|
|
1244
|
-
// Errors
|
|
1245
|
-
WalletError,
|
|
768
|
+
UseTransactionSignerReturn,
|
|
769
|
+
UseKitTransactionSignerReturn,
|
|
1246
770
|
} from '@solana/connector';
|
|
1247
771
|
```
|
|
1248
772
|
|
|
1249
773
|
---
|
|
1250
774
|
|
|
1251
|
-
## Performance
|
|
1252
|
-
|
|
1253
|
-
### Bundle Size
|
|
1254
|
-
|
|
1255
|
-
| Component | Size (gzipped) | Tree-Shakeable |
|
|
1256
|
-
| -------------------- | -------------- | ------------------ |
|
|
1257
|
-
| **Base Connector** | ~45KB | ✅ |
|
|
1258
|
-
| + Polyfills | +2KB | ❌ (auto-included) |
|
|
1259
|
-
| + Transaction Signer | +3KB | ✅ |
|
|
1260
|
-
| + Connection Pool | +1.5KB | ✅ |
|
|
1261
|
-
| + Debug Panel | +2KB | ✅ (dev-only) |
|
|
1262
|
-
| + Event System | +0.5KB | ✅ |
|
|
1263
|
-
| + Compat Layer | +2KB | ✅ |
|
|
1264
|
-
|
|
1265
|
-
**Total**: ~48-53KB for typical production usage
|
|
1266
|
-
|
|
1267
|
-
### Runtime Performance
|
|
1268
|
-
|
|
1269
|
-
- **40-60% fewer re-renders** via optimized state updates
|
|
1270
|
-
- **Connection pooling** reduces memory usage and initialization overhead
|
|
1271
|
-
- **Automatic tree-shaking** excludes unused features
|
|
1272
|
-
- **Debug panel** automatically excluded in production builds
|
|
1273
|
-
|
|
1274
|
-
---
|
|
1275
|
-
|
|
1276
|
-
## Browser Compatibility
|
|
1277
|
-
|
|
1278
|
-
Enhanced support for:
|
|
1279
|
-
|
|
1280
|
-
- ✅ Chrome/Edge 90+
|
|
1281
|
-
- ✅ Firefox 88+
|
|
1282
|
-
- ✅ Safari 14+
|
|
1283
|
-
- ✅ iOS Safari 14+
|
|
1284
|
-
- ✅ Chrome Mobile 90+
|
|
1285
|
-
- ✅ Samsung Internet 15+
|
|
1286
|
-
|
|
1287
|
-
Automatic polyfills ensure compatibility across all environments.
|
|
1288
|
-
|
|
1289
|
-
---
|
|
1290
|
-
|
|
1291
|
-
## Migration from @solana/wallet-adapter
|
|
1292
|
-
|
|
1293
|
-
Using the wallet-adapter compatibility bridge for gradual migration:
|
|
1294
|
-
|
|
1295
|
-
```typescript
|
|
1296
|
-
// Before (wallet-adapter)
|
|
1297
|
-
import { useWallet } from '@solana/wallet-adapter-react';
|
|
1298
|
-
|
|
1299
|
-
const { publicKey, sendTransaction } = useWallet();
|
|
1300
|
-
await sendTransaction(tx, connection);
|
|
1301
|
-
|
|
1302
|
-
// After (connector-kit)
|
|
1303
|
-
import { useTransactionSigner } from '@solana/connector';
|
|
1304
|
-
|
|
1305
|
-
const { signer } = useTransactionSigner();
|
|
1306
|
-
await signer.signAndSendTransaction(tx);
|
|
1307
|
-
|
|
1308
|
-
// Or use compatibility bridge for existing integrations
|
|
1309
|
-
import { createWalletAdapterCompat } from '@solana/connector/compat';
|
|
1310
|
-
|
|
1311
|
-
const walletAdapter = createWalletAdapterCompat(signer, { disconnect });
|
|
1312
|
-
// Pass walletAdapter to existing wallet-adapter code
|
|
1313
|
-
```
|
|
1314
|
-
|
|
1315
|
-
---
|
|
1316
|
-
|
|
1317
|
-
## Examples
|
|
1318
|
-
|
|
1319
|
-
Check out the [examples directory](../../examples/react) for:
|
|
1320
|
-
|
|
1321
|
-
- **React Example** - Complete wallet connection UI with shadcn/ui
|
|
1322
|
-
- **Vite Example** - Lightweight setup with Vite
|
|
1323
|
-
- **Transaction Signing** - Full transaction demos
|
|
1324
|
-
- **Network Switching** - Cluster/network management
|
|
1325
|
-
- **Account Management** - Multi-account support
|
|
1326
|
-
- **Mobile Support** - Solana Mobile Wallet Adapter
|
|
1327
|
-
|
|
1328
|
-
---
|
|
1329
|
-
|
|
1330
775
|
## Development
|
|
1331
776
|
|
|
1332
777
|
### Commands
|
|
@@ -1353,9 +798,6 @@ pnpm test
|
|
|
1353
798
|
# Test in watch mode
|
|
1354
799
|
pnpm test:watch
|
|
1355
800
|
|
|
1356
|
-
# Test with UI
|
|
1357
|
-
pnpm test:ui
|
|
1358
|
-
|
|
1359
801
|
# Coverage report
|
|
1360
802
|
pnpm test:coverage
|
|
1361
803
|
|
|
@@ -1363,65 +805,17 @@ pnpm test:coverage
|
|
|
1363
805
|
pnpm size
|
|
1364
806
|
```
|
|
1365
807
|
|
|
1366
|
-
### Project Structure
|
|
1367
|
-
|
|
1368
|
-
```
|
|
1369
|
-
packages/connector/
|
|
1370
|
-
├── src/
|
|
1371
|
-
│ ├── lib/
|
|
1372
|
-
│ │ ├── core/ # Core functionality
|
|
1373
|
-
│ │ │ ├── state-manager.ts
|
|
1374
|
-
│ │ │ ├── event-emitter.ts
|
|
1375
|
-
│ │ │ └── debug-metrics.ts
|
|
1376
|
-
│ │ ├── connection/ # Connection management
|
|
1377
|
-
│ │ │ ├── connection-manager.ts
|
|
1378
|
-
│ │ │ └── connection-pool.ts
|
|
1379
|
-
│ │ ├── transaction/ # Transaction signing
|
|
1380
|
-
│ │ │ ├── transaction-signer.ts
|
|
1381
|
-
│ │ │ └── signer-factory.ts
|
|
1382
|
-
│ │ └── storage/ # Persistence layer
|
|
1383
|
-
│ │ └── enhanced-storage.ts
|
|
1384
|
-
│ ├── hooks/ # React hooks
|
|
1385
|
-
│ │ ├── use-connector.ts
|
|
1386
|
-
│ │ ├── use-account.ts
|
|
1387
|
-
│ │ ├── use-cluster.ts
|
|
1388
|
-
│ │ └── use-transaction-signer.ts
|
|
1389
|
-
│ ├── components/ # React components
|
|
1390
|
-
│ │ └── debug-panel.tsx
|
|
1391
|
-
│ ├── compat/ # Wallet adapter compatibility
|
|
1392
|
-
│ │ └── wallet-adapter-compat.ts
|
|
1393
|
-
│ ├── __tests__/ # Test utilities
|
|
1394
|
-
│ │ ├── mocks/
|
|
1395
|
-
│ │ ├── fixtures/
|
|
1396
|
-
│ │ └── utils/
|
|
1397
|
-
│ └── index.ts # Main exports
|
|
1398
|
-
├── tsconfig.json
|
|
1399
|
-
├── tsup.config.ts
|
|
1400
|
-
├── vitest.config.ts
|
|
1401
|
-
└── package.json
|
|
1402
|
-
```
|
|
1403
|
-
|
|
1404
|
-
### Contributing
|
|
1405
|
-
|
|
1406
|
-
Contributions are welcome! Please:
|
|
1407
|
-
|
|
1408
|
-
1. Fork the repository
|
|
1409
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
1410
|
-
3. Make your changes
|
|
1411
|
-
4. Add tests for new functionality
|
|
1412
|
-
5. Ensure tests pass (`pnpm test`)
|
|
1413
|
-
6. Commit with conventional commits (`feat:`, `fix:`, `docs:`, etc.)
|
|
1414
|
-
7. Push to your fork and submit a pull request
|
|
1415
|
-
|
|
1416
|
-
For detailed testing guidelines, see [Testing Guide](src/__tests__/README.md).
|
|
1417
|
-
|
|
1418
808
|
---
|
|
1419
809
|
|
|
1420
|
-
##
|
|
810
|
+
## Examples
|
|
811
|
+
|
|
812
|
+
Check out the [examples directory](../../examples/next-js) for complete working examples:
|
|
1421
813
|
|
|
1422
|
-
- **
|
|
1423
|
-
- **
|
|
1424
|
-
- **
|
|
814
|
+
- **Next.js Example** - Full-featured wallet connection UI with shadcn/ui
|
|
815
|
+
- **Transaction Signing** - Modern and legacy transaction examples
|
|
816
|
+
- **Network Switching** - Cluster/network management
|
|
817
|
+
- **Account Management** - Multi-account support
|
|
818
|
+
- **Mobile Support** - Solana Mobile Wallet Adapter
|
|
1425
819
|
|
|
1426
820
|
---
|
|
1427
821
|
|
|
@@ -1439,22 +833,6 @@ Compatible with all [Wallet Standard](https://github.com/wallet-standard/wallet-
|
|
|
1439
833
|
|
|
1440
834
|
---
|
|
1441
835
|
|
|
1442
|
-
##
|
|
1443
|
-
|
|
1444
|
-
- [ConnectorKit Documentation](https://connectorkit.dev) - Full documentation site
|
|
1445
|
-
- [API Reference](#complete-api-reference) - Complete TypeScript API
|
|
1446
|
-
- [Examples](../../examples/react) - Working examples
|
|
1447
|
-
- [Wallet Standard Spec](https://github.com/wallet-standard/wallet-standard) - Protocol specification
|
|
1448
|
-
- [@solana/connector on NPM](https://www.npmjs.com/package/@solana/connector) - Package page
|
|
1449
|
-
|
|
1450
|
-
---
|
|
1451
|
-
|
|
1452
|
-
## Source
|
|
1453
|
-
|
|
1454
|
-
- [GitHub Repository](https://github.com/your-org/connectorkit)
|
|
1455
|
-
- [Examples Directory](../../examples)
|
|
1456
|
-
- [Package Directory](../../packages/connector)
|
|
1457
|
-
|
|
1458
|
-
Built with ❤️ for the Solana ecosystem.
|
|
836
|
+
## License
|
|
1459
837
|
|
|
1460
|
-
|
|
838
|
+
MIT
|