@solana/connector 0.1.9 → 0.1.10
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/README.md +97 -0
- package/dist/chunk-4JT24DIX.js +466 -0
- package/dist/chunk-4JT24DIX.js.map +1 -0
- package/dist/chunk-4KD6HQQG.js +69 -0
- package/dist/chunk-4KD6HQQG.js.map +1 -0
- package/dist/{chunk-DSUCH44G.js → chunk-64LV76OK.js} +2 -67
- package/dist/chunk-64LV76OK.js.map +1 -0
- package/dist/{chunk-5HRJKCIL.js → chunk-6AJJJG5B.js} +567 -133
- package/dist/chunk-6AJJJG5B.js.map +1 -0
- package/dist/chunk-7XHVZW2L.mjs +460 -0
- package/dist/chunk-7XHVZW2L.mjs.map +1 -0
- package/dist/{chunk-WDXEP4AJ.js → chunk-ATYK5OKR.js} +81 -33
- package/dist/chunk-ATYK5OKR.js.map +1 -0
- package/dist/{chunk-J7DHGLW6.mjs → chunk-DKCZA2QI.mjs} +3 -61
- package/dist/chunk-DKCZA2QI.mjs.map +1 -0
- package/dist/chunk-FVA4TUI4.mjs +178 -0
- package/dist/chunk-FVA4TUI4.mjs.map +1 -0
- package/dist/chunk-HO6QNKFM.mjs +61 -0
- package/dist/chunk-HO6QNKFM.mjs.map +1 -0
- package/dist/chunk-MN7XNCYI.js +230 -0
- package/dist/chunk-MN7XNCYI.js.map +1 -0
- package/dist/{chunk-MAXA3HEP.mjs → chunk-QOIQBWMP.mjs} +477 -51
- package/dist/chunk-QOIQBWMP.mjs.map +1 -0
- package/dist/{chunk-P5LXUDP6.mjs → chunk-WGZYKDXF.mjs} +57 -11
- package/dist/chunk-WGZYKDXF.mjs.map +1 -0
- package/dist/compat.js +10 -9
- package/dist/compat.js.map +1 -1
- package/dist/compat.mjs +2 -1
- package/dist/compat.mjs.map +1 -1
- package/dist/headless.d.mts +217 -100
- package/dist/headless.d.ts +217 -100
- package/dist/headless.js +190 -168
- package/dist/headless.mjs +5 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +233 -203
- package/dist/index.mjs +6 -4
- package/dist/react.d.mts +72 -4
- package/dist/react.d.ts +72 -4
- package/dist/react.js +52 -36
- package/dist/react.mjs +2 -2
- package/dist/{standard-shim-CT49DM5l.d.mts → standard-shim-BTUm7cur.d.mts} +280 -1
- package/dist/{standard-shim-D9guL5fz.d.ts → standard-shim-LsQ97i9T.d.ts} +280 -1
- package/dist/walletconnect-D4JN6H2O.js +28 -0
- package/dist/walletconnect-D4JN6H2O.js.map +1 -0
- package/dist/walletconnect-I3PZUBTA.mjs +3 -0
- package/dist/walletconnect-I3PZUBTA.mjs.map +1 -0
- package/package.json +6 -2
- package/dist/chunk-5HRJKCIL.js.map +0 -1
- package/dist/chunk-DSUCH44G.js.map +0 -1
- package/dist/chunk-I6TJLYNA.js +0 -535
- package/dist/chunk-I6TJLYNA.js.map +0 -1
- package/dist/chunk-J7DHGLW6.mjs.map +0 -1
- package/dist/chunk-JOBLG62A.mjs +0 -476
- package/dist/chunk-JOBLG62A.mjs.map +0 -1
- package/dist/chunk-MAXA3HEP.mjs.map +0 -1
- package/dist/chunk-P5LXUDP6.mjs.map +0 -1
- package/dist/chunk-WDXEP4AJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -606,6 +606,102 @@ const mobile = getDefaultMobileConfig({
|
|
|
606
606
|
</AppProvider>
|
|
607
607
|
```
|
|
608
608
|
|
|
609
|
+
### WalletConnect Integration
|
|
610
|
+
|
|
611
|
+
Connect mobile wallets via QR code or deep link using WalletConnect. This enables users to connect wallets like Trust Wallet, Exodus, and other WalletConnect-compatible Solana wallets.
|
|
612
|
+
|
|
613
|
+
**1. Install WalletConnect dependency:**
|
|
614
|
+
|
|
615
|
+
```bash
|
|
616
|
+
npm install @walletconnect/universal-provider
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
**2. Get a WalletConnect Cloud Project ID:**
|
|
620
|
+
|
|
621
|
+
Visit [cloud.walletconnect.com](https://cloud.walletconnect.com/) and create a project to get your `projectId`.
|
|
622
|
+
|
|
623
|
+
**3. Configure WalletConnect in your app:**
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
import { getDefaultConfig } from '@solana/connector/headless';
|
|
627
|
+
import { useState } from 'react';
|
|
628
|
+
|
|
629
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
630
|
+
const [walletConnectUri, setWalletConnectUri] = useState<string | null>(null);
|
|
631
|
+
|
|
632
|
+
const connectorConfig = useMemo(() => {
|
|
633
|
+
return getDefaultConfig({
|
|
634
|
+
appName: 'My App',
|
|
635
|
+
appUrl: 'https://myapp.com',
|
|
636
|
+
walletConnect: {
|
|
637
|
+
enabled: true,
|
|
638
|
+
projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID!,
|
|
639
|
+
metadata: {
|
|
640
|
+
name: 'My App',
|
|
641
|
+
description: 'My Solana Application',
|
|
642
|
+
url: 'https://myapp.com',
|
|
643
|
+
icons: ['https://myapp.com/icon.png'],
|
|
644
|
+
},
|
|
645
|
+
// Handle the WalletConnect URI for QR code display
|
|
646
|
+
onDisplayUri: (uri) => {
|
|
647
|
+
setWalletConnectUri(uri);
|
|
648
|
+
},
|
|
649
|
+
onSessionEstablished: () => {
|
|
650
|
+
setWalletConnectUri(null);
|
|
651
|
+
},
|
|
652
|
+
},
|
|
653
|
+
});
|
|
654
|
+
}, []);
|
|
655
|
+
|
|
656
|
+
return (
|
|
657
|
+
<AppProvider connectorConfig={connectorConfig}>
|
|
658
|
+
{children}
|
|
659
|
+
{/* Render QR code modal when URI is available */}
|
|
660
|
+
{walletConnectUri && (
|
|
661
|
+
<WalletConnectQRModal
|
|
662
|
+
uri={walletConnectUri}
|
|
663
|
+
onClose={() => setWalletConnectUri(null)}
|
|
664
|
+
/>
|
|
665
|
+
)}
|
|
666
|
+
</AppProvider>
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
**4. Create a QR code modal:**
|
|
672
|
+
|
|
673
|
+
```typescript
|
|
674
|
+
import QRCode from 'qrcode.react'; // npm install qrcode.react
|
|
675
|
+
|
|
676
|
+
function WalletConnectQRModal({ uri, onClose }: { uri: string; onClose: () => void }) {
|
|
677
|
+
return (
|
|
678
|
+
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
679
|
+
<div className="bg-white rounded-xl p-6 max-w-sm">
|
|
680
|
+
<h2 className="text-lg font-semibold mb-4">Scan with your wallet</h2>
|
|
681
|
+
<QRCode value={uri} size={256} />
|
|
682
|
+
<p className="text-sm text-gray-500 mt-4 text-center">
|
|
683
|
+
Open your WalletConnect-compatible wallet and scan this QR code
|
|
684
|
+
</p>
|
|
685
|
+
<button onClick={onClose} className="mt-4 w-full py-2 bg-gray-100 rounded">
|
|
686
|
+
Cancel
|
|
687
|
+
</button>
|
|
688
|
+
</div>
|
|
689
|
+
</div>
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Once enabled, "WalletConnect" appears as a wallet option in your wallet list. When selected, the `onDisplayUri` callback fires with a URI that should be displayed as a QR code for mobile wallet scanning.
|
|
695
|
+
|
|
696
|
+
**Supported WalletConnect Solana methods:**
|
|
697
|
+
- `solana_getAccounts` / `solana_requestAccounts` - Get connected accounts
|
|
698
|
+
- `solana_signMessage` - Sign arbitrary messages
|
|
699
|
+
- `solana_signTransaction` - Sign transactions
|
|
700
|
+
- `solana_signAllTransactions` - Sign multiple transactions
|
|
701
|
+
- `solana_signAndSendTransaction` - Sign and broadcast transactions
|
|
702
|
+
|
|
703
|
+
See the [WalletConnect Solana documentation](https://docs.walletconnect.network/wallet-sdk/chain-support/solana) for more details.
|
|
704
|
+
|
|
609
705
|
---
|
|
610
706
|
|
|
611
707
|
## Security Considerations
|
|
@@ -1208,6 +1304,7 @@ Compatible with all [Wallet Standard](https://github.com/wallet-standard/wallet-
|
|
|
1208
1304
|
- **Glow** - Browser extension
|
|
1209
1305
|
- **Brave Wallet** - Built-in browser wallet
|
|
1210
1306
|
- **Solana Mobile** - All mobile wallet adapter compatible wallets
|
|
1307
|
+
- **WalletConnect** - Connect any WalletConnect-compatible mobile wallet via QR code
|
|
1211
1308
|
- **Any Wallet Standard wallet** - Full compatibility
|
|
1212
1309
|
|
|
1213
1310
|
---
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk64LV76OK_js = require('./chunk-64LV76OK.js');
|
|
4
|
+
var codecs = require('@solana/codecs');
|
|
5
|
+
|
|
6
|
+
// src/lib/wallet/walletconnect/universal-provider.ts
|
|
7
|
+
chunk64LV76OK_js.createLogger("WalletConnectProvider"); var SOLANA_METHODS = [
|
|
8
|
+
"solana_getAccounts",
|
|
9
|
+
"solana_requestAccounts",
|
|
10
|
+
"solana_signMessage",
|
|
11
|
+
"solana_signTransaction",
|
|
12
|
+
"solana_signAllTransactions",
|
|
13
|
+
"solana_signAndSendTransaction"
|
|
14
|
+
], SOLANA_CAIP_CHAINS = {
|
|
15
|
+
"solana:mainnet": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
16
|
+
"solana:devnet": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
|
|
17
|
+
"solana:testnet": "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z"
|
|
18
|
+
}, ALL_SOLANA_CAIP_CHAINS = Object.values(SOLANA_CAIP_CHAINS);
|
|
19
|
+
async function createWalletConnectTransport(config) {
|
|
20
|
+
let state = {
|
|
21
|
+
provider: null,
|
|
22
|
+
initialized: false,
|
|
23
|
+
connecting: false,
|
|
24
|
+
connectPromise: null,
|
|
25
|
+
cancelConnect: null
|
|
26
|
+
};
|
|
27
|
+
function hasSolanaNamespace(session) {
|
|
28
|
+
let namespaces = session?.namespaces;
|
|
29
|
+
return namespaces ? "solana" in namespaces : false;
|
|
30
|
+
}
|
|
31
|
+
async function safeCleanupPendingPairings(provider, deletePairings = false) {
|
|
32
|
+
let cleanup = provider.cleanupPendingPairings;
|
|
33
|
+
if (cleanup)
|
|
34
|
+
try {
|
|
35
|
+
await cleanup.call(provider, { deletePairings });
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function safeAbortPairingAttempt(provider) {
|
|
40
|
+
let abort = provider.abortPairingAttempt;
|
|
41
|
+
if (abort)
|
|
42
|
+
try {
|
|
43
|
+
abort.call(provider);
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function safeDisconnectProvider(provider) {
|
|
48
|
+
try {
|
|
49
|
+
await provider.disconnect();
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function initProvider() {
|
|
54
|
+
if (state.provider)
|
|
55
|
+
return state.provider;
|
|
56
|
+
let UniversalProvider;
|
|
57
|
+
try {
|
|
58
|
+
UniversalProvider = (await import('@walletconnect/universal-provider')).default;
|
|
59
|
+
} catch {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"WalletConnect is enabled but @walletconnect/universal-provider is not installed. Please install it in your app (e.g. pnpm add @walletconnect/universal-provider)."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
let provider = await UniversalProvider.init({
|
|
65
|
+
projectId: config.projectId,
|
|
66
|
+
metadata: config.metadata,
|
|
67
|
+
relayUrl: config.relayUrl
|
|
68
|
+
});
|
|
69
|
+
return provider.on("display_uri", (uri) => {
|
|
70
|
+
config.onDisplayUri ? config.onDisplayUri(uri) : process.env.NODE_ENV;
|
|
71
|
+
}), provider.on("session_delete", () => {
|
|
72
|
+
config.onSessionDisconnected && config.onSessionDisconnected();
|
|
73
|
+
}), state.provider = provider, state.initialized = true, provider;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
async connect() {
|
|
77
|
+
if (state.connectPromise) {
|
|
78
|
+
await state.connectPromise;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
state.connectPromise = (async () => {
|
|
82
|
+
state.connecting = true;
|
|
83
|
+
try {
|
|
84
|
+
let CANCELLED = Symbol("WALLETCONNECT_CANCELLED"), cancelResolve = null, cancelPromise = new Promise((resolve) => {
|
|
85
|
+
cancelResolve = () => resolve(CANCELLED);
|
|
86
|
+
}), isCancelled = false;
|
|
87
|
+
state.cancelConnect = () => {
|
|
88
|
+
isCancelled || (isCancelled = true, cancelResolve?.());
|
|
89
|
+
};
|
|
90
|
+
async function raceWithCancel(promise) {
|
|
91
|
+
let result = await Promise.race([
|
|
92
|
+
promise,
|
|
93
|
+
cancelPromise
|
|
94
|
+
]);
|
|
95
|
+
if (result === CANCELLED)
|
|
96
|
+
throw new Error("Connection cancelled");
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
let provider = null, connectAttemptPromise = null;
|
|
100
|
+
if (provider = await raceWithCancel(initProvider()), provider.session) {
|
|
101
|
+
if (hasSolanaNamespace(provider.session)) {
|
|
102
|
+
config.onSessionEstablished && config.onSessionEstablished();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
await raceWithCancel(safeDisconnectProvider(provider)), await raceWithCancel(safeCleanupPendingPairings(provider, false));
|
|
106
|
+
}
|
|
107
|
+
connectAttemptPromise = provider.connect({
|
|
108
|
+
namespaces: {
|
|
109
|
+
solana: {
|
|
110
|
+
chains: [...ALL_SOLANA_CAIP_CHAINS],
|
|
111
|
+
methods: [...SOLANA_METHODS],
|
|
112
|
+
events: []
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
try {
|
|
117
|
+
await raceWithCancel(connectAttemptPromise);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw connectAttemptPromise?.catch(() => {
|
|
120
|
+
}), error;
|
|
121
|
+
}
|
|
122
|
+
if (!provider.session)
|
|
123
|
+
throw new Error("WalletConnect: connect completed but no session was established");
|
|
124
|
+
if (!hasSolanaNamespace(provider.session))
|
|
125
|
+
throw await raceWithCancel(safeDisconnectProvider(provider)), new Error("WalletConnect: connected session does not include Solana namespace");
|
|
126
|
+
config.onSessionEstablished && config.onSessionEstablished();
|
|
127
|
+
} finally {
|
|
128
|
+
state.connecting = false, state.cancelConnect = null, state.connectPromise = null;
|
|
129
|
+
}
|
|
130
|
+
})(), await state.connectPromise;
|
|
131
|
+
},
|
|
132
|
+
async disconnect() {
|
|
133
|
+
if (state.cancelConnect)
|
|
134
|
+
try {
|
|
135
|
+
state.cancelConnect();
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
if (!state.provider) {
|
|
139
|
+
config.onSessionDisconnected && config.onSessionDisconnected();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
state.provider.session ? await safeDisconnectProvider(state.provider) : (safeAbortPairingAttempt(state.provider), await safeCleanupPendingPairings(state.provider, false)), config.onSessionDisconnected && config.onSessionDisconnected();
|
|
143
|
+
},
|
|
144
|
+
async request(args) {
|
|
145
|
+
let provider = await initProvider();
|
|
146
|
+
if (!provider.session)
|
|
147
|
+
throw new Error("WalletConnect: no active session. Call connect() first.");
|
|
148
|
+
try {
|
|
149
|
+
return await provider.request(
|
|
150
|
+
{
|
|
151
|
+
method: args.method,
|
|
152
|
+
params: args.params
|
|
153
|
+
},
|
|
154
|
+
args.chainId
|
|
155
|
+
);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
isConnected() {
|
|
161
|
+
return state.provider?.session != null;
|
|
162
|
+
},
|
|
163
|
+
getSessionAccounts() {
|
|
164
|
+
if (!state.provider?.session)
|
|
165
|
+
return [];
|
|
166
|
+
let accounts = [], namespaces = state.provider.session.namespaces;
|
|
167
|
+
if (namespaces?.solana?.accounts)
|
|
168
|
+
for (let account of namespaces.solana.accounts) {
|
|
169
|
+
let parts = account.split(":");
|
|
170
|
+
if (parts.length >= 3) {
|
|
171
|
+
let address = parts.slice(2).join(":");
|
|
172
|
+
address && !accounts.includes(address) && accounts.push(address);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return accounts;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function createMockWalletConnectTransport(mockImplementation = {}) {
|
|
180
|
+
let connected = false;
|
|
181
|
+
return {
|
|
182
|
+
...{
|
|
183
|
+
async connect() {
|
|
184
|
+
connected = true;
|
|
185
|
+
},
|
|
186
|
+
async disconnect() {
|
|
187
|
+
connected = false;
|
|
188
|
+
},
|
|
189
|
+
async request() {
|
|
190
|
+
throw new Error("Mock transport: request not implemented");
|
|
191
|
+
},
|
|
192
|
+
isConnected() {
|
|
193
|
+
return connected;
|
|
194
|
+
},
|
|
195
|
+
getSessionAccounts() {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
...mockImplementation
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/lib/wallet/walletconnect/create-walletconnect-wallet.ts
|
|
204
|
+
var WALLETCONNECT_ICON = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiByeD0iOCIgZmlsbD0iIzMzOTZGRiIvPgo8cGF0aCBkPSJNOS42IDEyLjRDMTMuMSA5IDE4LjkgOSAyMi40IDEyLjRMMjIuOSAxMi45QzIzLjEgMTMuMSAyMy4xIDEzLjQgMjIuOSAxMy42TDIxLjQgMTUuMUMyMS4zIDE1LjIgMjEuMSAxNS4yIDIxIDE1LjFMMjAuMyAxNC40QzE4IDEyLjIgMTQgMTIuMiAxMS43IDE0LjRMMTEgMTUuMUMxMC45IDE1LjIgMTAuNyAxNS4yIDEwLjYgMTUuMUw5LjEgMTMuNkM4LjkgMTMuNCA4LjkgMTMuMSA5LjEgMTIuOUw5LjYgMTIuNFpNMjUuMyAxNS4yTDI2LjYgMTYuNUMyNi44IDE2LjcgMjYuOCAxNyAyNi42IDE3LjJMMjAuNyAyMy4xQzIwLjUgMjMuMyAyMC4yIDIzLjMgMjAgMjMuMUwxNS45IDE5QzE1LjggMTguOSAxNS43IDE4LjkgMTUuNiAxOUwxMS41IDIzLjFDMTEuMyAyMy4zIDExIDIzLjMgMTAuOCAyMy4xTDQuOSAxNy4yQzQuNyAxNyA0LjcgMTYuNyA0LjkgMTYuNUw2LjIgMTUuMkM2LjQgMTUgNi43IDE1IDYuOSAxNS4yTDExIDE5LjNDMTEuMSAxOS40IDExLjIgMTkuNCAxMS4zIDE5LjNMMTUuNCAxNS4yQzE1LjYgMTUgMTUuOSAxNSAxNi4xIDE1LjJMMjAuMiAxOS4zQzIwLjMgMTkuNCAyMC40IDE5LjQgMjAuNSAxOS4zTDI0LjYgMTUuMkMyNC44IDE1IDI1LjEgMTUgMjUuMyAxNS4yWiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==", DEFAULT_CHAINS = ["solana:mainnet", "solana:devnet", "solana:testnet"];
|
|
205
|
+
function toCaipChainId(chainId) {
|
|
206
|
+
return SOLANA_CAIP_CHAINS[chainId] || chainId;
|
|
207
|
+
}
|
|
208
|
+
function bytesToBase64(bytes) {
|
|
209
|
+
let binary = "";
|
|
210
|
+
for (let i = 0; i < bytes.length; i++)
|
|
211
|
+
binary += String.fromCharCode(bytes[i]);
|
|
212
|
+
return btoa(binary);
|
|
213
|
+
}
|
|
214
|
+
function base64ToBytes(base64) {
|
|
215
|
+
let binary = atob(base64), bytes = new Uint8Array(binary.length);
|
|
216
|
+
for (let i = 0; i < binary.length; i++)
|
|
217
|
+
bytes[i] = binary.charCodeAt(i);
|
|
218
|
+
return bytes;
|
|
219
|
+
}
|
|
220
|
+
function isLikelyBase58(str) {
|
|
221
|
+
return !/[0OIl+/=]/.test(str);
|
|
222
|
+
}
|
|
223
|
+
function decodeTransaction(encoded) {
|
|
224
|
+
if (isLikelyBase58(encoded)) {
|
|
225
|
+
let readonlyBytes = codecs.getBase58Encoder().encode(encoded);
|
|
226
|
+
return new Uint8Array(readonlyBytes);
|
|
227
|
+
} else
|
|
228
|
+
return base64ToBytes(encoded);
|
|
229
|
+
}
|
|
230
|
+
function decodeShortVecLength(data) {
|
|
231
|
+
let length = 0, size = 0;
|
|
232
|
+
for (; ; ) {
|
|
233
|
+
if (size >= data.length)
|
|
234
|
+
throw new Error("Invalid shortvec encoding: unexpected end of data");
|
|
235
|
+
let byte = data[size];
|
|
236
|
+
if (length |= (byte & 127) << size * 7, size += 1, (byte & 128) === 0)
|
|
237
|
+
break;
|
|
238
|
+
if (size > 10)
|
|
239
|
+
throw new Error("Invalid shortvec encoding: length prefix too long");
|
|
240
|
+
}
|
|
241
|
+
return { length, bytesConsumed: size };
|
|
242
|
+
}
|
|
243
|
+
function findSignerIndex(txBytes, signerPubkeyBase58) {
|
|
244
|
+
let { length: numSignatures, bytesConsumed: sigCountSize } = decodeShortVecLength(txBytes), messageOffset = sigCountSize + numSignatures * 64, messageBytes = txBytes.subarray(messageOffset), offset = 0;
|
|
245
|
+
messageBytes[0] === 128 && (offset = 1);
|
|
246
|
+
let numSignerAccounts = messageBytes[offset];
|
|
247
|
+
offset += 3;
|
|
248
|
+
let { length: numStaticAccounts, bytesConsumed } = decodeShortVecLength(messageBytes.subarray(offset));
|
|
249
|
+
offset += bytesConsumed;
|
|
250
|
+
let base58Decoder = codecs.getBase58Decoder();
|
|
251
|
+
for (let i = 0; i < Math.min(numStaticAccounts, numSignerAccounts); i++) {
|
|
252
|
+
let accountBytes = messageBytes.subarray(offset + i * 32, offset + (i + 1) * 32);
|
|
253
|
+
if (base58Decoder.decode(accountBytes) === signerPubkeyBase58)
|
|
254
|
+
return i;
|
|
255
|
+
}
|
|
256
|
+
return -1;
|
|
257
|
+
}
|
|
258
|
+
function injectSignature(txBytes, signerIndex, signatureBase58) {
|
|
259
|
+
let { bytesConsumed: sigCountSize } = decodeShortVecLength(txBytes), signatureBytes = codecs.getBase58Encoder().encode(signatureBase58);
|
|
260
|
+
if (signatureBytes.length !== 64)
|
|
261
|
+
throw new Error(`Invalid signature length: expected 64 bytes, got ${signatureBytes.length}`);
|
|
262
|
+
let result = new Uint8Array(txBytes), signatureOffset = sigCountSize + signerIndex * 64;
|
|
263
|
+
return result.set(signatureBytes, signatureOffset), result;
|
|
264
|
+
}
|
|
265
|
+
function toWalletAccount(account, chains) {
|
|
266
|
+
let base58Encoder = codecs.getBase58Encoder();
|
|
267
|
+
return {
|
|
268
|
+
address: account.pubkey,
|
|
269
|
+
publicKey: base58Encoder.encode(account.pubkey),
|
|
270
|
+
chains,
|
|
271
|
+
features: []
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function createWalletConnectWallet(config, transport) {
|
|
275
|
+
let chains = config.defaultChain ? [config.defaultChain] : DEFAULT_CHAINS;
|
|
276
|
+
function getCurrentCaipChainId() {
|
|
277
|
+
let currentChain = config.getCurrentChain?.() || config.defaultChain || "solana:mainnet";
|
|
278
|
+
return toCaipChainId(currentChain);
|
|
279
|
+
}
|
|
280
|
+
let accounts = [], changeListeners = /* @__PURE__ */ new Set();
|
|
281
|
+
function emitChange() {
|
|
282
|
+
changeListeners.forEach((fn) => fn({ accounts }));
|
|
283
|
+
}
|
|
284
|
+
let wallet = {
|
|
285
|
+
version: "1.0.0",
|
|
286
|
+
name: "WalletConnect",
|
|
287
|
+
icon: WALLETCONNECT_ICON,
|
|
288
|
+
chains,
|
|
289
|
+
get accounts() {
|
|
290
|
+
return accounts;
|
|
291
|
+
},
|
|
292
|
+
features: {
|
|
293
|
+
// Standard connect feature
|
|
294
|
+
"standard:connect": {
|
|
295
|
+
version: "1.0.0",
|
|
296
|
+
connect: async (input) => {
|
|
297
|
+
await transport.connect();
|
|
298
|
+
let sessionAccounts = transport.getSessionAccounts();
|
|
299
|
+
if (sessionAccounts.length > 0)
|
|
300
|
+
return accounts = sessionAccounts.map((pubkey) => toWalletAccount({ pubkey }, chains)), emitChange(), { accounts };
|
|
301
|
+
let method = input?.silent ? "solana_getAccounts" : "solana_requestAccounts", result, firstError;
|
|
302
|
+
try {
|
|
303
|
+
result = await transport.request({
|
|
304
|
+
method,
|
|
305
|
+
params: {},
|
|
306
|
+
chainId: getCurrentCaipChainId()
|
|
307
|
+
});
|
|
308
|
+
} catch (error) {
|
|
309
|
+
firstError = error;
|
|
310
|
+
try {
|
|
311
|
+
let fallbackMethod = method === "solana_getAccounts" ? "solana_requestAccounts" : "solana_getAccounts";
|
|
312
|
+
result = await transport.request({
|
|
313
|
+
method: fallbackMethod,
|
|
314
|
+
params: {},
|
|
315
|
+
chainId: getCurrentCaipChainId()
|
|
316
|
+
});
|
|
317
|
+
} catch (fallbackError) {
|
|
318
|
+
let firstMessage = firstError instanceof Error ? firstError.message : String(firstError), fallbackMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError), details = [firstMessage, fallbackMessage].filter(Boolean).join(" | ");
|
|
319
|
+
throw new Error(
|
|
320
|
+
`Failed to get accounts from WalletConnect. The wallet may not support Solana accounts.${details ? ` (Details: ${details})` : ""}`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return accounts = Array.isArray(result) ? result.map((acc) => toWalletAccount(acc, chains)) : [], emitChange(), { accounts };
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
// Standard disconnect feature
|
|
328
|
+
"standard:disconnect": {
|
|
329
|
+
version: "1.0.0",
|
|
330
|
+
disconnect: async () => {
|
|
331
|
+
await transport.disconnect(), accounts = [], emitChange();
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
// Standard events feature
|
|
335
|
+
"standard:events": {
|
|
336
|
+
version: "1.0.0",
|
|
337
|
+
on: (event, listener) => event !== "change" ? () => {
|
|
338
|
+
} : (changeListeners.add(listener), () => changeListeners.delete(listener))
|
|
339
|
+
},
|
|
340
|
+
// Solana sign message feature
|
|
341
|
+
"solana:signMessage": {
|
|
342
|
+
version: "1.0.0",
|
|
343
|
+
signMessage: async ({ account, message }) => {
|
|
344
|
+
let messageBase58 = codecs.getBase58Decoder().decode(message), result = await transport.request({
|
|
345
|
+
method: "solana_signMessage",
|
|
346
|
+
params: {
|
|
347
|
+
message: messageBase58,
|
|
348
|
+
pubkey: account.address
|
|
349
|
+
},
|
|
350
|
+
chainId: getCurrentCaipChainId()
|
|
351
|
+
});
|
|
352
|
+
return [{ signature: codecs.getBase58Encoder().encode(result.signature), signedMessage: message }];
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
// Solana sign transaction feature
|
|
356
|
+
"solana:signTransaction": {
|
|
357
|
+
version: "1.0.0",
|
|
358
|
+
signTransaction: async ({
|
|
359
|
+
account,
|
|
360
|
+
transaction
|
|
361
|
+
}) => {
|
|
362
|
+
let transactionBase64 = bytesToBase64(transaction), requestChainId = getCurrentCaipChainId(), result = await transport.request({
|
|
363
|
+
method: "solana_signTransaction",
|
|
364
|
+
params: {
|
|
365
|
+
transaction: transactionBase64
|
|
366
|
+
},
|
|
367
|
+
chainId: requestChainId
|
|
368
|
+
}), signedTransaction;
|
|
369
|
+
if (result.transaction)
|
|
370
|
+
signedTransaction = decodeTransaction(result.transaction);
|
|
371
|
+
else if (result.signature) {
|
|
372
|
+
let signerIndex = findSignerIndex(transaction, account.address);
|
|
373
|
+
if (signerIndex < 0)
|
|
374
|
+
throw new Error("Signer pubkey not found in transaction");
|
|
375
|
+
signedTransaction = injectSignature(transaction, signerIndex, result.signature);
|
|
376
|
+
} else
|
|
377
|
+
throw new Error("Invalid solana_signTransaction response: no signature or transaction");
|
|
378
|
+
return [{ signedTransaction }];
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
// Solana sign all transactions feature
|
|
382
|
+
"solana:signAllTransactions": {
|
|
383
|
+
version: "1.0.0",
|
|
384
|
+
signAllTransactions: async ({
|
|
385
|
+
account,
|
|
386
|
+
transactions
|
|
387
|
+
}) => {
|
|
388
|
+
let transactionsBase64 = transactions.map(bytesToBase64);
|
|
389
|
+
try {
|
|
390
|
+
return (await transport.request({
|
|
391
|
+
method: "solana_signAllTransactions",
|
|
392
|
+
params: {
|
|
393
|
+
transactions: transactionsBase64
|
|
394
|
+
},
|
|
395
|
+
chainId: getCurrentCaipChainId()
|
|
396
|
+
})).transactions.map((txEncoded) => ({
|
|
397
|
+
signedTransaction: decodeTransaction(txEncoded)
|
|
398
|
+
}));
|
|
399
|
+
} catch {
|
|
400
|
+
let signFeature = wallet.features["solana:signTransaction"];
|
|
401
|
+
return (await Promise.all(
|
|
402
|
+
transactions.map((tx) => signFeature.signTransaction({ account, transaction: tx }))
|
|
403
|
+
)).map((r) => ({ signedTransaction: r[0].signedTransaction }));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
// Solana sign and send transaction feature
|
|
408
|
+
"solana:signAndSendTransaction": {
|
|
409
|
+
version: "1.0.0",
|
|
410
|
+
signAndSendTransaction: async ({
|
|
411
|
+
transaction,
|
|
412
|
+
options
|
|
413
|
+
}) => {
|
|
414
|
+
let transactionBase64 = bytesToBase64(transaction), result = await transport.request({
|
|
415
|
+
method: "solana_signAndSendTransaction",
|
|
416
|
+
params: {
|
|
417
|
+
transaction: transactionBase64,
|
|
418
|
+
sendOptions: options ? {
|
|
419
|
+
skipPreflight: options.skipPreflight,
|
|
420
|
+
preflightCommitment: options.preflightCommitment,
|
|
421
|
+
maxRetries: options.maxRetries,
|
|
422
|
+
minContextSlot: options.minContextSlot
|
|
423
|
+
} : void 0
|
|
424
|
+
},
|
|
425
|
+
chainId: getCurrentCaipChainId()
|
|
426
|
+
});
|
|
427
|
+
return [{ signature: codecs.getBase58Encoder().encode(result.signature) }];
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
return wallet;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/lib/wallet/walletconnect/register-walletconnect.ts
|
|
436
|
+
var logger2 = chunk64LV76OK_js.createLogger("WalletConnectRegistration");
|
|
437
|
+
async function registerWalletConnectWallet(config) {
|
|
438
|
+
if (typeof window > "u")
|
|
439
|
+
throw new Error("WalletConnect registration can only be done in a browser environment");
|
|
440
|
+
logger2.debug("Registering WalletConnect wallet", {
|
|
441
|
+
projectId: config.projectId.substring(0, 8) + "...",
|
|
442
|
+
defaultChain: config.defaultChain
|
|
443
|
+
});
|
|
444
|
+
let transport = await createWalletConnectTransport(config), wallet = createWalletConnectWallet(config, transport), { getWallets } = await import('@wallet-standard/app'), unregister = getWallets().register(wallet);
|
|
445
|
+
return logger2.info("WalletConnect wallet registered successfully"), {
|
|
446
|
+
wallet,
|
|
447
|
+
unregister
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
async function isWalletConnectAvailable() {
|
|
451
|
+
if (typeof window > "u")
|
|
452
|
+
return false;
|
|
453
|
+
try {
|
|
454
|
+
return await import('@walletconnect/universal-provider'), true;
|
|
455
|
+
} catch {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
exports.createMockWalletConnectTransport = createMockWalletConnectTransport;
|
|
461
|
+
exports.createWalletConnectTransport = createWalletConnectTransport;
|
|
462
|
+
exports.createWalletConnectWallet = createWalletConnectWallet;
|
|
463
|
+
exports.isWalletConnectAvailable = isWalletConnectAvailable;
|
|
464
|
+
exports.registerWalletConnectWallet = registerWalletConnectWallet;
|
|
465
|
+
//# sourceMappingURL=chunk-4JT24DIX.js.map
|
|
466
|
+
//# sourceMappingURL=chunk-4JT24DIX.js.map
|