@satoshai/kit 0.3.1 → 0.4.1
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 +44 -15
- package/dist/index.cjs +157 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +158 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WalletConnect,
|
|
1
|
+
import { WalletConnect, DEFAULT_PROVIDERS, WALLET_CONNECT_PROVIDER, clearSelectedProviderId, request, getSelectedProviderId, getSelectedProvider, setSelectedProviderId } from '@stacks/connect';
|
|
2
2
|
import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
|
|
3
3
|
import { jsx } from 'react/jsx-runtime';
|
|
4
4
|
import { PostConditionMode, postConditionToHex, cvToHex } from '@stacks/transactions';
|
|
@@ -8,10 +8,17 @@ import { getPrimaryName } from 'bns-v2-sdk';
|
|
|
8
8
|
var STACKS_TO_STACKS_CONNECT_PROVIDERS = {
|
|
9
9
|
xverse: "XverseProviders.BitcoinProvider",
|
|
10
10
|
leather: "LeatherProvider",
|
|
11
|
+
okx: "OkxStacksProvider",
|
|
11
12
|
asigna: "AsignaProvider",
|
|
12
13
|
fordefi: "FordefiProviders.UtxoProvider",
|
|
13
14
|
"wallet-connect": "WalletConnectProvider"
|
|
14
15
|
};
|
|
16
|
+
var STACKS_CONNECT_TO_STACKS_PROVIDERS = Object.fromEntries(
|
|
17
|
+
Object.entries(STACKS_TO_STACKS_CONNECT_PROVIDERS).map(([kit, connect]) => [
|
|
18
|
+
connect,
|
|
19
|
+
kit
|
|
20
|
+
])
|
|
21
|
+
);
|
|
15
22
|
|
|
16
23
|
// src/constants/storage-keys.ts
|
|
17
24
|
var LOCAL_STORAGE_STACKS = "@satoshai/kit";
|
|
@@ -20,10 +27,10 @@ var LOCAL_STORAGE_STACKS = "@satoshai/kit";
|
|
|
20
27
|
var SUPPORTED_STACKS_WALLETS = [
|
|
21
28
|
"xverse",
|
|
22
29
|
"leather",
|
|
23
|
-
"okx",
|
|
24
30
|
"asigna",
|
|
25
31
|
"fordefi",
|
|
26
|
-
"wallet-connect"
|
|
32
|
+
"wallet-connect",
|
|
33
|
+
"okx"
|
|
27
34
|
];
|
|
28
35
|
|
|
29
36
|
// src/utils/get-stacks-wallets.ts
|
|
@@ -35,7 +42,7 @@ var getStacksWallets = () => {
|
|
|
35
42
|
return { supported, installed };
|
|
36
43
|
};
|
|
37
44
|
var checkIfStacksProviderIsInstalled = (wallet) => {
|
|
38
|
-
if (typeof window === "undefined") return
|
|
45
|
+
if (typeof window === "undefined") return wallet === "wallet-connect";
|
|
39
46
|
switch (wallet) {
|
|
40
47
|
case "xverse":
|
|
41
48
|
return !!window.XverseProviders;
|
|
@@ -90,6 +97,38 @@ var getOKXStacksAddress = async () => {
|
|
|
90
97
|
provider: "okx"
|
|
91
98
|
};
|
|
92
99
|
};
|
|
100
|
+
var OKX_PROVIDER_META = {
|
|
101
|
+
id: "OkxStacksProvider",
|
|
102
|
+
name: "OKX Wallet",
|
|
103
|
+
icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiICAgICB4bWxuczp4b2RtPSJodHRwOi8vd3d3LmNvcmVsLmNvbS9jb3JlbGRyYXcvb2RtLzIwMDMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjUwMCAyNTAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAwIDI1MDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgIC5zdDB7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7fQogICAgLnN0MXtmaWxsOiNGRkZGRkY7fQo8L3N0eWxlPgo8ZyBpZD0iTGF5ZXJfeDAwMjBfMSI+CiAgICA8ZyBpZD0iXzIxODczODEzMjM4NTYiPgogICAgICAgIDxyZWN0IHk9IjAiIGNsYXNzPSJzdDAiIHdpZHRoPSIyNTAwIiBoZWlnaHQ9IjI1MDAiPjwvcmVjdD4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggY2xhc3M9InN0MSIgZD0iTTE0NjMsMTAxNWgtNDA0Yy0xNywwLTMxLDE0LTMxLDMxdjQwNGMwLDE3LDE0LDMxLDMxLDMxaDQwNGMxNywwLDMxLTE0LDMxLTMxdi00MDQgICAgIEMxNDk0LDEwMjksMTQ4MCwxMDE1LDE0NjMsMTAxNXoiPjwvcGF0aD4KICAgICAgICAgICAgPHBhdGggY2xhc3M9InN0MSIgZD0iTTk5Niw1NDlINTkyYy0xNywwLTMxLDE0LTMxLDMxdjQwNGMwLDE3LDE0LDMxLDMxLDMxaDQwNGMxNywwLDMxLTE0LDMxLTMxVjU4MEMxMDI3LDU2MywxMDEzLDU0OSw5OTYsNTQ5eiI+PC9wYXRoPgogICAgICAgICAgICA8cGF0aCBjbGFzcz0ic3QxIiBkPSJNMTkzMCw1NDloLTQwNGMtMTcsMC0zMSwxNC0zMSwzMXY0MDRjMCwxNywxNCwzMSwzMSwzMWg0MDRjMTcsMCwzMS0xNCwzMS0zMVY1ODAgICAgIEMxOTYxLDU2MywxOTQ3LDU0OSwxOTMwLDU0OXoiPjwvcGF0aD4KICAgICAgICAgICAgPHBhdGggY2xhc3M9InN0MSIgZD0iTTk5NiwxNDgySDU5MmMtMTcsMC0zMSwxNC0zMSwzMXY0MDRjMCwxNywxNCwzMSwzMSwzMWg0MDRjMTcsMCwzMS0xNCwzMS0zMXYtNDA0ICAgICBDMTAyNywxNDk2LDEwMTMsMTQ4Miw5OTYsMTQ4MnoiPjwvcGF0aD4KICAgICAgICAgICAgPHBhdGggY2xhc3M9InN0MSIgZD0iTTE5MzAsMTQ4MmgtNDA0Yy0xNywwLTMxLDE0LTMxLDMxdjQwNGMwLDE3LDE0LDMxLDMxLDMxaDQwNGMxNywwLDMxLTE0LDMxLTMxdi00MDQgICAgIEMxOTYxLDE0OTYsMTk0NywxNDgyLDE5MzAsMTQ4MnoiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+CjwvZz4KPC9zdmc+",
|
|
104
|
+
webUrl: "https://www.okx.com/"
|
|
105
|
+
};
|
|
106
|
+
var registerOkxProvider = () => {
|
|
107
|
+
if (typeof window === "undefined") return;
|
|
108
|
+
if (!window.OkxStacksProvider) {
|
|
109
|
+
window.OkxStacksProvider = {
|
|
110
|
+
request: async (method) => {
|
|
111
|
+
if (method === "getAddresses") {
|
|
112
|
+
const data = await getOKXStacksAddress();
|
|
113
|
+
return {
|
|
114
|
+
result: {
|
|
115
|
+
addresses: [
|
|
116
|
+
{ address: data.address, symbol: "STX" }
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
throw new Error(
|
|
122
|
+
`OKX adapter: unsupported method "${method}". Use connect('okx') for direct OKX SDK access.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
var unregisterOkxProvider = () => {
|
|
129
|
+
if (typeof window === "undefined") return;
|
|
130
|
+
delete window.OkxStacksProvider;
|
|
131
|
+
};
|
|
93
132
|
var extractStacksAddress = (typedProvider, addresses) => {
|
|
94
133
|
if (!addresses.length) {
|
|
95
134
|
throw new Error(`No addresses provided for ${typedProvider} wallet`);
|
|
@@ -221,12 +260,21 @@ var getLocalStorageWallet = () => {
|
|
|
221
260
|
return null;
|
|
222
261
|
}
|
|
223
262
|
};
|
|
263
|
+
var PROVIDER_META_BY_KIT_ID = Object.fromEntries(
|
|
264
|
+
[...DEFAULT_PROVIDERS, WALLET_CONNECT_PROVIDER, OKX_PROVIDER_META].map(
|
|
265
|
+
(p) => [
|
|
266
|
+
STACKS_CONNECT_TO_STACKS_PROVIDERS[p.id],
|
|
267
|
+
{ name: p.name, icon: p.icon ?? "", webUrl: p.webUrl ?? "" }
|
|
268
|
+
]
|
|
269
|
+
)
|
|
270
|
+
);
|
|
224
271
|
var StacksWalletContext = createContext(
|
|
225
272
|
void 0
|
|
226
273
|
);
|
|
227
274
|
var StacksWalletProvider = ({
|
|
228
275
|
children,
|
|
229
276
|
wallets,
|
|
277
|
+
connectModal = true,
|
|
230
278
|
walletConnect,
|
|
231
279
|
onConnect,
|
|
232
280
|
onAddressChange,
|
|
@@ -236,15 +284,23 @@ var StacksWalletProvider = ({
|
|
|
236
284
|
const [provider, setProvider] = useState();
|
|
237
285
|
const [isConnecting, setIsConnecting] = useState(false);
|
|
238
286
|
const connectGenRef = useRef(0);
|
|
287
|
+
const wasConnectedRef = useRef(false);
|
|
239
288
|
const wcInitRef = useRef(null);
|
|
289
|
+
const walletConnectRef = useRef(walletConnect);
|
|
290
|
+
walletConnectRef.current = walletConnect;
|
|
240
291
|
const walletsKey = wallets?.join(",");
|
|
292
|
+
if (wallets?.includes("wallet-connect") && !walletConnect?.projectId) {
|
|
293
|
+
throw new Error(
|
|
294
|
+
'StacksWalletProvider: "wallet-connect" is listed in wallets but no walletConnect.projectId was provided.'
|
|
295
|
+
);
|
|
296
|
+
}
|
|
241
297
|
useEffect(() => {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
);
|
|
298
|
+
const okxConfigured = !wallets || wallets.includes("okx");
|
|
299
|
+
if (connectModal && okxConfigured) {
|
|
300
|
+
registerOkxProvider();
|
|
301
|
+
return () => unregisterOkxProvider();
|
|
246
302
|
}
|
|
247
|
-
}, [
|
|
303
|
+
}, [connectModal, walletsKey]);
|
|
248
304
|
useEffect(() => {
|
|
249
305
|
const loadPersistedWallet = async () => {
|
|
250
306
|
const persisted = getLocalStorageWallet();
|
|
@@ -284,6 +340,65 @@ var StacksWalletProvider = ({
|
|
|
284
340
|
}, [walletConnect?.projectId]);
|
|
285
341
|
const connect = useCallback(
|
|
286
342
|
async (providerId, options) => {
|
|
343
|
+
if (connectModal && !providerId) {
|
|
344
|
+
const gen2 = ++connectGenRef.current;
|
|
345
|
+
setIsConnecting(true);
|
|
346
|
+
try {
|
|
347
|
+
clearSelectedProviderId();
|
|
348
|
+
const requestOptions = {
|
|
349
|
+
forceWalletSelect: true,
|
|
350
|
+
// OKX at the end so it appears last among installed wallets
|
|
351
|
+
defaultProviders: [
|
|
352
|
+
...DEFAULT_PROVIDERS,
|
|
353
|
+
OKX_PROVIDER_META
|
|
354
|
+
]
|
|
355
|
+
};
|
|
356
|
+
if (wallets) {
|
|
357
|
+
requestOptions.approvedProviderIds = wallets.map(
|
|
358
|
+
(w) => STACKS_TO_STACKS_CONNECT_PROVIDERS[w]
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
const wc2 = walletConnectRef.current;
|
|
362
|
+
if (wc2?.projectId) {
|
|
363
|
+
requestOptions.walletConnect = buildWalletConnectConfig(
|
|
364
|
+
wc2.projectId,
|
|
365
|
+
wc2.metadata,
|
|
366
|
+
wc2.chains
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
const data = await request(
|
|
370
|
+
requestOptions,
|
|
371
|
+
"getAddresses",
|
|
372
|
+
{}
|
|
373
|
+
);
|
|
374
|
+
if (connectGenRef.current !== gen2) return;
|
|
375
|
+
const selectedId = getSelectedProviderId();
|
|
376
|
+
const resolvedProvider = selectedId ? STACKS_CONNECT_TO_STACKS_PROVIDERS[selectedId] : void 0;
|
|
377
|
+
if (!resolvedProvider) {
|
|
378
|
+
throw new Error(
|
|
379
|
+
`Unknown provider returned from @stacks/connect modal: ${selectedId ?? "none"}`
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const extractedAddress = extractStacksAddress(
|
|
383
|
+
resolvedProvider,
|
|
384
|
+
data.addresses
|
|
385
|
+
);
|
|
386
|
+
setAddress(extractedAddress);
|
|
387
|
+
setProvider(resolvedProvider);
|
|
388
|
+
options?.onSuccess?.(extractedAddress, resolvedProvider);
|
|
389
|
+
} catch (error) {
|
|
390
|
+
if (connectGenRef.current !== gen2) return;
|
|
391
|
+
console.error("Failed to connect wallet:", error);
|
|
392
|
+
getSelectedProvider()?.disconnect?.();
|
|
393
|
+
clearSelectedProviderId();
|
|
394
|
+
options?.onError?.(error);
|
|
395
|
+
} finally {
|
|
396
|
+
if (connectGenRef.current === gen2) {
|
|
397
|
+
setIsConnecting(false);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
287
402
|
const typedProvider = SUPPORTED_STACKS_WALLETS.find(
|
|
288
403
|
(wallet) => wallet === providerId
|
|
289
404
|
);
|
|
@@ -303,7 +418,8 @@ var StacksWalletProvider = ({
|
|
|
303
418
|
options?.onError?.(error);
|
|
304
419
|
return;
|
|
305
420
|
}
|
|
306
|
-
|
|
421
|
+
const wc = walletConnectRef.current;
|
|
422
|
+
if (typedProvider === "wallet-connect" && !wc?.projectId) {
|
|
307
423
|
const error = new Error(
|
|
308
424
|
"WalletConnect requires a project ID. Please provide walletConnect.projectId to the StacksWalletProvider."
|
|
309
425
|
);
|
|
@@ -325,10 +441,10 @@ var StacksWalletProvider = ({
|
|
|
325
441
|
setSelectedProviderId(
|
|
326
442
|
STACKS_TO_STACKS_CONNECT_PROVIDERS[typedProvider]
|
|
327
443
|
);
|
|
328
|
-
const wcConfig = typedProvider === "wallet-connect" &&
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
444
|
+
const wcConfig = typedProvider === "wallet-connect" && wc ? buildWalletConnectConfig(
|
|
445
|
+
wc.projectId,
|
|
446
|
+
wc.metadata,
|
|
447
|
+
wc.chains
|
|
332
448
|
) : void 0;
|
|
333
449
|
if (wcConfig) {
|
|
334
450
|
if (wcInitRef.current) await wcInitRef.current;
|
|
@@ -365,7 +481,7 @@ var StacksWalletProvider = ({
|
|
|
365
481
|
}
|
|
366
482
|
}
|
|
367
483
|
},
|
|
368
|
-
[
|
|
484
|
+
[connectModal, walletsKey]
|
|
369
485
|
);
|
|
370
486
|
const reset = useCallback(() => {
|
|
371
487
|
connectGenRef.current++;
|
|
@@ -392,24 +508,35 @@ var StacksWalletProvider = ({
|
|
|
392
508
|
);
|
|
393
509
|
}, [address, provider]);
|
|
394
510
|
useEffect(() => {
|
|
395
|
-
|
|
396
|
-
|
|
511
|
+
const isConnected = !!address && !!provider;
|
|
512
|
+
if (isConnected && !wasConnectedRef.current) {
|
|
513
|
+
onConnect?.(provider, address);
|
|
514
|
+
}
|
|
515
|
+
wasConnectedRef.current = isConnected;
|
|
397
516
|
}, [address, provider, onConnect]);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
provider,
|
|
401
|
-
onAddressChange: (newAddress) => {
|
|
517
|
+
const handleAddressChange = useCallback(
|
|
518
|
+
(newAddress) => {
|
|
402
519
|
setAddress(newAddress);
|
|
403
520
|
onAddressChange?.(newAddress);
|
|
404
521
|
},
|
|
522
|
+
[onAddressChange]
|
|
523
|
+
);
|
|
524
|
+
useXverse({
|
|
525
|
+
address,
|
|
526
|
+
provider,
|
|
527
|
+
onAddressChange: handleAddressChange,
|
|
405
528
|
connect
|
|
406
529
|
});
|
|
407
530
|
const { installed } = getStacksWallets();
|
|
408
531
|
const configured = wallets ?? [...SUPPORTED_STACKS_WALLETS];
|
|
409
532
|
const walletInfos = configured.map((w) => ({
|
|
410
533
|
id: w,
|
|
534
|
+
name: PROVIDER_META_BY_KIT_ID[w]?.name ?? w,
|
|
535
|
+
icon: PROVIDER_META_BY_KIT_ID[w]?.icon ?? "",
|
|
536
|
+
webUrl: PROVIDER_META_BY_KIT_ID[w]?.webUrl ?? "",
|
|
411
537
|
available: w === "wallet-connect" ? !!walletConnect?.projectId : installed.includes(w)
|
|
412
538
|
}));
|
|
539
|
+
const walletInfosKey = walletInfos.map((w) => `${w.id}:${w.available}`).join(",");
|
|
413
540
|
const value = useMemo(() => {
|
|
414
541
|
const walletState = isConnecting ? { status: "connecting", address: void 0, provider: void 0 } : address && provider ? { status: "connected", address, provider } : {
|
|
415
542
|
status: "disconnected",
|
|
@@ -423,7 +550,7 @@ var StacksWalletProvider = ({
|
|
|
423
550
|
reset,
|
|
424
551
|
wallets: walletInfos
|
|
425
552
|
};
|
|
426
|
-
}, [address, provider, isConnecting, connect, disconnect, reset,
|
|
553
|
+
}, [address, provider, isConnecting, connect, disconnect, reset, walletInfosKey]);
|
|
427
554
|
return /* @__PURE__ */ jsx(StacksWalletContext.Provider, { value, children });
|
|
428
555
|
};
|
|
429
556
|
var useStacksWalletContext = () => {
|
|
@@ -739,20 +866,28 @@ var useBnsName = (address) => {
|
|
|
739
866
|
setIsLoading(false);
|
|
740
867
|
return;
|
|
741
868
|
}
|
|
869
|
+
let cancelled = false;
|
|
742
870
|
const fetchBnsName = async () => {
|
|
743
871
|
setIsLoading(true);
|
|
744
872
|
try {
|
|
745
873
|
const network = getNetworkFromAddress(address);
|
|
746
874
|
const result = await getPrimaryName({ address, network });
|
|
875
|
+
if (cancelled) return;
|
|
747
876
|
const fullName = result ? `${result.name}.${result.namespace}` : null;
|
|
748
877
|
setBnsName(fullName);
|
|
749
878
|
} catch {
|
|
879
|
+
if (cancelled) return;
|
|
750
880
|
setBnsName(null);
|
|
751
881
|
} finally {
|
|
752
|
-
|
|
882
|
+
if (!cancelled) {
|
|
883
|
+
setIsLoading(false);
|
|
884
|
+
}
|
|
753
885
|
}
|
|
754
886
|
};
|
|
755
887
|
void fetchBnsName();
|
|
888
|
+
return () => {
|
|
889
|
+
cancelled = true;
|
|
890
|
+
};
|
|
756
891
|
}, [address]);
|
|
757
892
|
return { bnsName, isLoading };
|
|
758
893
|
};
|