@gluwa/connect-kit 0.1.0-next.0 → 0.1.0-next.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/CHANGELOG.md +6 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +333 -298
- package/dist/package.json +3 -1
- package/package.json +3 -1
- package/src/ConnectModal.tsx +79 -173
- package/src/components/QRFrame.tsx +43 -0
- package/src/creditConnectConnector.ts +61 -13
- package/src/hooks/useWCState.ts +150 -0
- package/src/hooks/useWagmiConnect.ts +68 -45
- package/src/index.ts +9 -1
- package/src/types.ts +8 -4
- package/src/views/CreditWalletView.tsx +4 -17
- package/src/views/MetaMaskView.tsx +5 -30
- package/src/views/WalletConnectView.tsx +10 -70
- package/tsup.config.ts +12 -1
- package/dist/_esm-PE6HOEBI.js +0 -3909
- package/dist/ccip-UBX2BH3T.js +0 -15
- package/dist/chunk-6KUZ225H.js +0 -5259
- package/dist/chunk-EVEWD66F.js +0 -447
- package/dist/chunk-U2IU7TQD.js +0 -45
- package/dist/secp256k1-FYSVLDVL.js +0 -2311
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -48,7 +48,9 @@
|
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
51
|
+
"@wagmi/core": ">=2.0.0",
|
|
51
52
|
"react": "^18.0.0 || ^19.0.0",
|
|
53
|
+
"viem": ">=2.0.0",
|
|
52
54
|
"wagmi": ">=2.0.0"
|
|
53
55
|
},
|
|
54
56
|
"peerDependenciesMeta": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
"@gluwa/credit-connect-sdk": "0.2.0-next.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
+
"@wagmi/core": ">=2.0.0",
|
|
35
36
|
"react": "^18.0.0 || ^19.0.0",
|
|
37
|
+
"viem": ">=2.0.0",
|
|
36
38
|
"wagmi": ">=2.0.0",
|
|
37
39
|
"@gluwa/credit-connect-sdk": "0.2.0-next.1"
|
|
38
40
|
},
|
package/src/ConnectModal.tsx
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef, useMemo, type FC } from 'react';
|
|
2
2
|
import './ConnectModal.scss';
|
|
3
3
|
import { useConfig } from 'wagmi';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type ConnectModalProps,
|
|
6
|
+
type Connectors,
|
|
7
|
+
type ConnectorId,
|
|
8
|
+
type WCWallet,
|
|
9
|
+
type WCSubView,
|
|
10
|
+
} from './types';
|
|
5
11
|
import { CONNECTOR_META } from './connector-meta';
|
|
6
12
|
import { detectMetaMaskExtension } from './utils/platform';
|
|
7
|
-
import { useWagmiConnect,
|
|
13
|
+
import { useWagmiConnect, resolveWagmiConnector } from './hooks/useWagmiConnect';
|
|
14
|
+
import { useWCState, type WCState } from './hooks/useWCState';
|
|
8
15
|
import { IdleView } from './views/IdleView';
|
|
9
16
|
import { CreditWalletView } from './views/CreditWalletView';
|
|
10
17
|
import { MetaMaskView } from './views/MetaMaskView';
|
|
11
18
|
import { WalletConnectView } from './views/WalletConnectView';
|
|
12
19
|
|
|
13
|
-
// 최근 연결 기록
|
|
14
20
|
const RECENT_KEY = 'connect-kit:recent';
|
|
15
21
|
const readRecentConnector = (): ConnectorId | null => {
|
|
16
22
|
try {
|
|
@@ -26,60 +32,6 @@ const writeRecentConnector = (id: ConnectorId): void => {
|
|
|
26
32
|
} catch {}
|
|
27
33
|
};
|
|
28
34
|
|
|
29
|
-
// WC 지갑 목록 가져오기
|
|
30
|
-
const fetchWCWalletList = async (projectId: string): Promise<WCWallet[]> => {
|
|
31
|
-
const all: WCWallet[] = [];
|
|
32
|
-
let page = 1;
|
|
33
|
-
const entries = 100;
|
|
34
|
-
|
|
35
|
-
while (page <= 10) {
|
|
36
|
-
const url = new URL('https://explorer-api.walletconnect.com/v3/wallets');
|
|
37
|
-
url.searchParams.set('projectId', projectId);
|
|
38
|
-
url.searchParams.set('entries', String(entries));
|
|
39
|
-
url.searchParams.set('page', String(page));
|
|
40
|
-
|
|
41
|
-
const res = await fetch(url.toString());
|
|
42
|
-
if (!res.ok) throw new Error(`Failed to fetch wallet list: ${res.status}`);
|
|
43
|
-
|
|
44
|
-
const json = (await res.json()) as {
|
|
45
|
-
listings: Record<
|
|
46
|
-
string,
|
|
47
|
-
{
|
|
48
|
-
id: string;
|
|
49
|
-
name: string;
|
|
50
|
-
homepage?: string;
|
|
51
|
-
image_url?: { sm?: string; md?: string };
|
|
52
|
-
mobile?: { native?: string; universal?: string };
|
|
53
|
-
desktop?: { native?: string; universal?: string };
|
|
54
|
-
app?: { ios?: string; android?: string };
|
|
55
|
-
}
|
|
56
|
-
>;
|
|
57
|
-
total: number;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const listings = Object.values(json.listings ?? {});
|
|
61
|
-
for (const w of listings) {
|
|
62
|
-
all.push({
|
|
63
|
-
id: w.id,
|
|
64
|
-
name: w.name,
|
|
65
|
-
imageUrl: w.image_url?.md ?? w.image_url?.sm ?? '',
|
|
66
|
-
mobileNative: w.mobile?.native ?? '',
|
|
67
|
-
mobileUniversal: w.mobile?.universal ?? '',
|
|
68
|
-
desktopNative: w.desktop?.native ?? '',
|
|
69
|
-
desktopUniversal: w.desktop?.universal ?? '',
|
|
70
|
-
appIos: w.app?.ios ?? '',
|
|
71
|
-
appAndroid: w.app?.android ?? '',
|
|
72
|
-
homepage: w.homepage ?? '',
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (listings.length < entries || all.length >= json.total) break;
|
|
77
|
-
page += 1;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return all;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
35
|
interface SelectorPaneProps {
|
|
84
36
|
connectors: ConnectorId[];
|
|
85
37
|
selected: ConnectorId | null;
|
|
@@ -196,18 +148,9 @@ interface DetailPaneProps {
|
|
|
196
148
|
qrUri: string | null;
|
|
197
149
|
hasMetaMaskExtension: boolean;
|
|
198
150
|
connectorLogoMap: Partial<Record<ConnectorId, string>>;
|
|
199
|
-
|
|
200
|
-
wcWalletList: WCWallet[];
|
|
201
|
-
wcWalletListLoading: boolean;
|
|
202
|
-
wcWalletListSearch: string;
|
|
203
|
-
wcSelectedWallet: WCWallet | null;
|
|
151
|
+
wc: WCState;
|
|
204
152
|
onBack: () => void;
|
|
205
153
|
onClose: () => void;
|
|
206
|
-
wcFilterActive: boolean;
|
|
207
|
-
onWCShowList: () => void;
|
|
208
|
-
onWCSelectWallet: (wallet: WCWallet) => void;
|
|
209
|
-
onWCSearchChange: (q: string) => void;
|
|
210
|
-
onWCFilterToggle: () => void;
|
|
211
154
|
}
|
|
212
155
|
|
|
213
156
|
const DetailPane: FC<DetailPaneProps> = ({
|
|
@@ -215,24 +158,15 @@ const DetailPane: FC<DetailPaneProps> = ({
|
|
|
215
158
|
qrUri,
|
|
216
159
|
hasMetaMaskExtension,
|
|
217
160
|
connectorLogoMap,
|
|
218
|
-
|
|
219
|
-
wcWalletList,
|
|
220
|
-
wcWalletListLoading,
|
|
221
|
-
wcWalletListSearch,
|
|
222
|
-
wcSelectedWallet,
|
|
223
|
-
wcFilterActive,
|
|
161
|
+
wc,
|
|
224
162
|
onBack,
|
|
225
163
|
onClose,
|
|
226
|
-
onWCShowList,
|
|
227
|
-
onWCSelectWallet,
|
|
228
|
-
onWCSearchChange,
|
|
229
|
-
onWCFilterToggle,
|
|
230
164
|
}) => {
|
|
231
165
|
const title = getDetailTitle(
|
|
232
166
|
selectedConnector,
|
|
233
167
|
hasMetaMaskExtension,
|
|
234
|
-
|
|
235
|
-
|
|
168
|
+
wc.subView,
|
|
169
|
+
wc.selectedWallet,
|
|
236
170
|
);
|
|
237
171
|
const showBack = selectedConnector !== null;
|
|
238
172
|
|
|
@@ -263,18 +197,18 @@ const DetailPane: FC<DetailPaneProps> = ({
|
|
|
263
197
|
|
|
264
198
|
{selectedConnector === 'WALLET_CONNECT' && (
|
|
265
199
|
<WalletConnectView
|
|
266
|
-
subView={
|
|
200
|
+
subView={wc.subView}
|
|
267
201
|
qrUri={qrUri}
|
|
268
202
|
logoUrl={connectorLogoMap.WALLET_CONNECT}
|
|
269
|
-
walletList={
|
|
270
|
-
walletListLoading={
|
|
271
|
-
walletListSearch={
|
|
272
|
-
walletListFilterActive={
|
|
273
|
-
selectedWallet={
|
|
274
|
-
onShowList={
|
|
275
|
-
onSelectWallet={
|
|
276
|
-
onSearchChange={
|
|
277
|
-
onFilterToggle={
|
|
203
|
+
walletList={wc.walletList}
|
|
204
|
+
walletListLoading={wc.walletListLoading}
|
|
205
|
+
walletListSearch={wc.walletListSearch}
|
|
206
|
+
walletListFilterActive={wc.filterActive}
|
|
207
|
+
selectedWallet={wc.selectedWallet}
|
|
208
|
+
onShowList={wc.onShowList}
|
|
209
|
+
onSelectWallet={wc.onSelectWallet}
|
|
210
|
+
onSearchChange={wc.onSearchChange}
|
|
211
|
+
onFilterToggle={wc.onFilterToggle}
|
|
278
212
|
/>
|
|
279
213
|
)}
|
|
280
214
|
</div>
|
|
@@ -301,20 +235,43 @@ const getDetailTitle = (
|
|
|
301
235
|
return CONNECTOR_META[connector].detailTitle;
|
|
302
236
|
};
|
|
303
237
|
|
|
238
|
+
const resolveConnectorsFromConfig = (connectorsConfig?: Connectors): ConnectorId[] => {
|
|
239
|
+
if (!connectorsConfig) return [];
|
|
240
|
+
|
|
241
|
+
const connectors: ConnectorId[] = [];
|
|
242
|
+
|
|
243
|
+
if (connectorsConfig.creditWallet === 'walletConnect') connectors.push('CREDIT_WALLET');
|
|
244
|
+
if (connectorsConfig.creditWallet === 'creditConnect') connectors.push('CREDIT_CONNECT');
|
|
245
|
+
if (connectorsConfig.metamask) connectors.push('METAMASK');
|
|
246
|
+
if (connectorsConfig.walletConnect) connectors.push('WALLET_CONNECT');
|
|
247
|
+
|
|
248
|
+
return connectors;
|
|
249
|
+
};
|
|
250
|
+
|
|
304
251
|
export const ConnectModal: FC<ConnectModalProps> = (props) => {
|
|
252
|
+
// open=false면 내부 컴포넌트를 마운트하지 않음
|
|
253
|
+
// → useConfig 등 wagmi hooks가 실행되지 않아 WagmiProvider 없이도 렌더링 가능
|
|
254
|
+
if (!props.open) return null;
|
|
255
|
+
|
|
256
|
+
const resolvedConnectors = resolveConnectorsFromConfig(props.connectors);
|
|
257
|
+
|
|
305
258
|
if (
|
|
306
|
-
|
|
307
|
-
|
|
259
|
+
resolvedConnectors.includes('CREDIT_WALLET') &&
|
|
260
|
+
resolvedConnectors.includes('CREDIT_CONNECT')
|
|
308
261
|
) {
|
|
309
262
|
throw new Error('CREDIT_WALLET and CREDIT_CONNECT cannot be used together');
|
|
310
263
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return <ConnectModalInner {...props} />;
|
|
264
|
+
if (resolvedConnectors.length === 0) {
|
|
265
|
+
throw new Error('At least one connector must be configured');
|
|
266
|
+
}
|
|
267
|
+
return <ConnectModalInner {...props} connectors={resolvedConnectors} />;
|
|
315
268
|
};
|
|
316
269
|
|
|
317
|
-
|
|
270
|
+
type ConnectModalInnerProps = Omit<ConnectModalProps, 'connectors'> & {
|
|
271
|
+
connectors: ConnectorId[];
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const ConnectModalInner: FC<ConnectModalInnerProps> = ({
|
|
318
275
|
open,
|
|
319
276
|
connectors,
|
|
320
277
|
onConnect,
|
|
@@ -323,20 +280,12 @@ const ConnectModalInner: FC<ConnectModalProps> = ({
|
|
|
323
280
|
wcProjectId,
|
|
324
281
|
}) => {
|
|
325
282
|
const [selectedConnector, setSelectedConnector] = useState<ConnectorId | null>(null);
|
|
326
|
-
// 커넥터별 QR URI 캐시 — 만료 전까지 재사용
|
|
327
283
|
const [qrUriMap, setQrUriMap] = useState<Partial<Record<ConnectorId, string>>>({});
|
|
328
|
-
// handleQrUri 호출 시점에 어떤 커넥터의 QR인지 추적
|
|
329
284
|
const pendingQrConnectorRef = useRef<ConnectorId | null>(null);
|
|
330
285
|
const [recentConnector, setRecentConnector] = useState<ConnectorId | null>(null);
|
|
331
286
|
const [hasMetaMaskExtension, setHasMetaMaskExtension] = useState<boolean>(false);
|
|
332
287
|
|
|
333
|
-
const
|
|
334
|
-
const [wcWalletList, setWcWalletList] = useState<WCWallet[]>([]);
|
|
335
|
-
const [wcWalletListLoading, setWcWalletListLoading] = useState<boolean>(false);
|
|
336
|
-
const [wcWalletListSearch, setWcWalletListSearch] = useState<string>('');
|
|
337
|
-
const [wcFilterActive, setWcFilterActive] = useState<boolean>(false);
|
|
338
|
-
const [wcSelectedWallet, setWcSelectedWallet] = useState<WCWallet | null>(null);
|
|
339
|
-
const wcLoadedRef = useRef<boolean>(false);
|
|
288
|
+
const wc = useWCState();
|
|
340
289
|
|
|
341
290
|
// QR URI 수신 — 커넥터별 캐시에 저장 (null은 무시하여 캐시 유지)
|
|
342
291
|
const handleQrUri = useCallback((uri: string | null) => {
|
|
@@ -365,10 +314,9 @@ const ConnectModalInner: FC<ConnectModalProps> = ({
|
|
|
365
314
|
delete next[connectorId];
|
|
366
315
|
return next;
|
|
367
316
|
});
|
|
368
|
-
|
|
369
|
-
setWcSelectedWallet(null);
|
|
317
|
+
wc.resetView();
|
|
370
318
|
},
|
|
371
|
-
[onLog],
|
|
319
|
+
[onLog, wc.resetView],
|
|
372
320
|
);
|
|
373
321
|
|
|
374
322
|
// 연결 시도
|
|
@@ -382,10 +330,14 @@ const ConnectModalInner: FC<ConnectModalProps> = ({
|
|
|
382
330
|
const wagmiConfig = useConfig();
|
|
383
331
|
const connectorLogoMap = useMemo(() => {
|
|
384
332
|
const map: Partial<Record<ConnectorId, string>> = {};
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
333
|
+
const connectorIds: ConnectorId[] = [
|
|
334
|
+
'CREDIT_CONNECT',
|
|
335
|
+
'CREDIT_WALLET',
|
|
336
|
+
'METAMASK',
|
|
337
|
+
'WALLET_CONNECT',
|
|
338
|
+
];
|
|
339
|
+
for (const connectorId of connectorIds) {
|
|
340
|
+
const wagmiConnector = resolveWagmiConnector(wagmiConfig.connectors, connectorId);
|
|
389
341
|
if (wagmiConnector?.icon) map[connectorId] = wagmiConnector.icon;
|
|
390
342
|
}
|
|
391
343
|
return map;
|
|
@@ -403,28 +355,10 @@ const ConnectModalInner: FC<ConnectModalProps> = ({
|
|
|
403
355
|
setSelectedConnector(null);
|
|
404
356
|
setQrUriMap({});
|
|
405
357
|
pendingQrConnectorRef.current = null;
|
|
406
|
-
|
|
407
|
-
setWcWalletListSearch('');
|
|
408
|
-
setWcFilterActive(false);
|
|
409
|
-
setWcSelectedWallet(null);
|
|
358
|
+
wc.reset();
|
|
410
359
|
cancelConnect();
|
|
411
360
|
}
|
|
412
|
-
}, [open, cancelConnect]);
|
|
413
|
-
|
|
414
|
-
// WC 지갑 목록 로드
|
|
415
|
-
const loadWCWalletList = useCallback(async (projectId: string): Promise<void> => {
|
|
416
|
-
if (wcLoadedRef.current) return;
|
|
417
|
-
wcLoadedRef.current = true;
|
|
418
|
-
setWcWalletListLoading(true);
|
|
419
|
-
try {
|
|
420
|
-
const list = await fetchWCWalletList(projectId);
|
|
421
|
-
setWcWalletList(list);
|
|
422
|
-
} catch {
|
|
423
|
-
wcLoadedRef.current = false;
|
|
424
|
-
} finally {
|
|
425
|
-
setWcWalletListLoading(false);
|
|
426
|
-
}
|
|
427
|
-
}, []);
|
|
361
|
+
}, [open, cancelConnect, wc.reset]);
|
|
428
362
|
|
|
429
363
|
// 커넥터 선택 — 같은 커넥터 재선택 시 무시, 다른 커넥터 선택 시 이전 연결 취소 후 새 연결
|
|
430
364
|
const handleSelectConnector = useCallback(
|
|
@@ -433,53 +367,34 @@ const ConnectModalInner: FC<ConnectModalProps> = ({
|
|
|
433
367
|
|
|
434
368
|
pendingQrConnectorRef.current = id;
|
|
435
369
|
setSelectedConnector(id);
|
|
436
|
-
|
|
437
|
-
setWcSelectedWallet(null);
|
|
370
|
+
wc.resetView();
|
|
438
371
|
writeRecentConnector(id);
|
|
439
372
|
setRecentConnector(id);
|
|
440
373
|
|
|
441
374
|
if (id === 'WALLET_CONNECT' && wcProjectId) {
|
|
442
|
-
|
|
443
|
-
loadWCWalletList(wcProjectId);
|
|
375
|
+
wc.loadWalletList(wcProjectId);
|
|
444
376
|
}
|
|
445
377
|
|
|
446
378
|
cancelConnect();
|
|
447
379
|
triggerConnect(id);
|
|
448
380
|
},
|
|
449
|
-
[
|
|
381
|
+
[
|
|
382
|
+
selectedConnector,
|
|
383
|
+
triggerConnect,
|
|
384
|
+
cancelConnect,
|
|
385
|
+
wcProjectId,
|
|
386
|
+
wc.resetView,
|
|
387
|
+
wc.loadWalletList,
|
|
388
|
+
],
|
|
450
389
|
);
|
|
451
390
|
|
|
452
|
-
// WC 서브뷰 핸들러
|
|
453
|
-
const handleWCShowList = useCallback((): void => {
|
|
454
|
-
setWcSubView('list');
|
|
455
|
-
}, []);
|
|
456
|
-
|
|
457
|
-
const handleWCSelectWallet = useCallback((wallet: WCWallet): void => {
|
|
458
|
-
setWcSelectedWallet(wallet);
|
|
459
|
-
setWcSubView('wallet');
|
|
460
|
-
}, []);
|
|
461
|
-
|
|
462
|
-
const handleWCFilterToggle = useCallback((): void => {
|
|
463
|
-
setWcFilterActive((prev) => !prev);
|
|
464
|
-
}, []);
|
|
465
|
-
|
|
466
391
|
// 뒤로가기 — QR 캐시는 유지, wagmi만 reset
|
|
467
392
|
const handleBack = useCallback((): void => {
|
|
468
|
-
if (selectedConnector === 'WALLET_CONNECT')
|
|
469
|
-
if (wcSubView === 'wallet') {
|
|
470
|
-
setWcSelectedWallet(null);
|
|
471
|
-
setWcSubView('list');
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
if (wcSubView === 'list') {
|
|
475
|
-
setWcSubView('qr');
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
393
|
+
if (selectedConnector === 'WALLET_CONNECT' && wc.handleBack()) return;
|
|
479
394
|
pendingQrConnectorRef.current = null;
|
|
480
395
|
setSelectedConnector(null);
|
|
481
396
|
cancelConnect();
|
|
482
|
-
}, [selectedConnector,
|
|
397
|
+
}, [selectedConnector, wc.handleBack, cancelConnect]);
|
|
483
398
|
|
|
484
399
|
return (
|
|
485
400
|
<div className="ck-root">
|
|
@@ -502,18 +417,9 @@ const ConnectModalInner: FC<ConnectModalProps> = ({
|
|
|
502
417
|
qrUri={selectedConnector ? (qrUriMap[selectedConnector] ?? null) : null}
|
|
503
418
|
hasMetaMaskExtension={hasMetaMaskExtension}
|
|
504
419
|
connectorLogoMap={connectorLogoMap}
|
|
505
|
-
|
|
506
|
-
wcWalletList={wcWalletList}
|
|
507
|
-
wcWalletListLoading={wcWalletListLoading}
|
|
508
|
-
wcWalletListSearch={wcWalletListSearch}
|
|
509
|
-
wcFilterActive={wcFilterActive}
|
|
510
|
-
wcSelectedWallet={wcSelectedWallet}
|
|
420
|
+
wc={wc}
|
|
511
421
|
onBack={handleBack}
|
|
512
422
|
onClose={onClose}
|
|
513
|
-
onWCShowList={handleWCShowList}
|
|
514
|
-
onWCSelectWallet={handleWCSelectWallet}
|
|
515
|
-
onWCSearchChange={setWcWalletListSearch}
|
|
516
|
-
onWCFilterToggle={handleWCFilterToggle}
|
|
517
423
|
/>
|
|
518
424
|
</div>
|
|
519
425
|
</div>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import { QRCodeSVG } from 'qrcode.react';
|
|
3
|
+
|
|
4
|
+
interface QRFrameProps {
|
|
5
|
+
qrUri: string | null;
|
|
6
|
+
logoUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const QRFrame: FC<QRFrameProps> = ({ qrUri, logoUrl }) => (
|
|
10
|
+
<div className={`ck-qr-frame ${!qrUri ? 'ck-qr-frame--loading' : ''}`}>
|
|
11
|
+
{qrUri ? (
|
|
12
|
+
<QRCodeSVG
|
|
13
|
+
value={qrUri}
|
|
14
|
+
size={196}
|
|
15
|
+
level="H"
|
|
16
|
+
imageSettings={
|
|
17
|
+
logoUrl ? { src: logoUrl, width: 40, height: 40, excavate: true } : undefined
|
|
18
|
+
}
|
|
19
|
+
/>
|
|
20
|
+
) : (
|
|
21
|
+
<div className="ck-qr-spinner" aria-label="Loading QR code" />
|
|
22
|
+
)}
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
interface CopyLinkButtonProps {
|
|
27
|
+
qrUri: string | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const CopyLinkButton: FC<CopyLinkButtonProps> = ({ qrUri }) => {
|
|
31
|
+
if (!qrUri) return null;
|
|
32
|
+
return (
|
|
33
|
+
<button
|
|
34
|
+
type="button"
|
|
35
|
+
className="ck-copy-link"
|
|
36
|
+
onClick={() => {
|
|
37
|
+
navigator.clipboard.writeText(qrUri);
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
Copy link
|
|
41
|
+
</button>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -17,11 +17,23 @@ export type CreditConnectConnectorOptions = {
|
|
|
17
17
|
|
|
18
18
|
type CreditConnectProvider = EIP1193Provider;
|
|
19
19
|
type ProviderListener = (...args: unknown[]) => void;
|
|
20
|
+
type CreditConnectProviderWithEvents = CreditConnectProvider & {
|
|
21
|
+
on: (event: string, listener: ProviderListener) => CreditConnectProviderWithEvents;
|
|
22
|
+
removeListener: (event: string, listener: ProviderListener) => CreditConnectProviderWithEvents;
|
|
23
|
+
};
|
|
20
24
|
|
|
21
25
|
const CONNECTOR_ID = 'credit-connect';
|
|
22
26
|
const CONNECTOR_NAME = 'Credit Wallet';
|
|
23
27
|
const CONNECTOR_TYPE = 'credit-connect';
|
|
24
28
|
|
|
29
|
+
const castConnectResult = <withCapabilities extends boolean>(value: unknown) =>
|
|
30
|
+
value as {
|
|
31
|
+
accounts: withCapabilities extends true
|
|
32
|
+
? ReadonlyArray<{ address: Address; capabilities: Record<string, unknown> }>
|
|
33
|
+
: readonly Address[];
|
|
34
|
+
chainId: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
25
37
|
export const creditConnectConnector = (
|
|
26
38
|
options: CreditConnectConnectorOptions,
|
|
27
39
|
): ReturnType<typeof createConnector> => {
|
|
@@ -157,7 +169,20 @@ export const creditConnectConnector = (
|
|
|
157
169
|
const chainId = Number.parseInt(getEvmAddressInfo(session)[0].networkIdentifier, 10);
|
|
158
170
|
if (!Number.isFinite(chainId)) throw new Error(`Invalid chainId: ${chainId}`);
|
|
159
171
|
selectedChainId = chainId;
|
|
160
|
-
|
|
172
|
+
if (parameters?.withCapabilities === true) {
|
|
173
|
+
return castConnectResult<withCapabilities>({
|
|
174
|
+
accounts: accounts.map((address) => ({
|
|
175
|
+
address,
|
|
176
|
+
capabilities: {} as Record<string, unknown>,
|
|
177
|
+
})),
|
|
178
|
+
chainId,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return castConnectResult<withCapabilities>({
|
|
183
|
+
accounts,
|
|
184
|
+
chainId,
|
|
185
|
+
});
|
|
161
186
|
}
|
|
162
187
|
|
|
163
188
|
if (m.state.status === 'CONNECTING' && m.state.connectingPayload) {
|
|
@@ -202,7 +227,20 @@ export const creditConnectConnector = (
|
|
|
202
227
|
if (!Number.isFinite(chainId)) throw new Error(`Invalid chainId: ${chainId}`);
|
|
203
228
|
|
|
204
229
|
selectedChainId = chainId;
|
|
205
|
-
|
|
230
|
+
if (parameters?.withCapabilities === true) {
|
|
231
|
+
return castConnectResult<withCapabilities>({
|
|
232
|
+
accounts: accounts.map((address) => ({
|
|
233
|
+
address,
|
|
234
|
+
capabilities: {} as Record<string, unknown>,
|
|
235
|
+
})),
|
|
236
|
+
chainId,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return castConnectResult<withCapabilities>({
|
|
241
|
+
accounts,
|
|
242
|
+
chainId,
|
|
243
|
+
});
|
|
206
244
|
} catch (error) {
|
|
207
245
|
resetState();
|
|
208
246
|
throw error;
|
|
@@ -277,9 +315,17 @@ export const creditConnectConnector = (
|
|
|
277
315
|
if (provider) return provider;
|
|
278
316
|
await ensureManagerInitialized();
|
|
279
317
|
|
|
280
|
-
|
|
281
|
-
request: async (args
|
|
282
|
-
const { method, params } = args as {
|
|
318
|
+
const createdProvider = {
|
|
319
|
+
request: async (args) => {
|
|
320
|
+
const { method, params: rawParams } = args as {
|
|
321
|
+
method: string;
|
|
322
|
+
params?: unknown[] | object;
|
|
323
|
+
};
|
|
324
|
+
const params = Array.isArray(rawParams)
|
|
325
|
+
? [...rawParams]
|
|
326
|
+
: rawParams === undefined
|
|
327
|
+
? []
|
|
328
|
+
: [rawParams];
|
|
283
329
|
const session = getCurrentSession();
|
|
284
330
|
|
|
285
331
|
const getSelectedAddressInfo = (address?: string) => {
|
|
@@ -409,20 +455,22 @@ export const creditConnectConnector = (
|
|
|
409
455
|
},
|
|
410
456
|
|
|
411
457
|
on: (event: string, listener: ProviderListener) => {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
458
|
+
let listeners = providerListeners.get(event);
|
|
459
|
+
if (!listeners) {
|
|
460
|
+
listeners = new Set();
|
|
461
|
+
providerListeners.set(event, listeners);
|
|
462
|
+
}
|
|
463
|
+
listeners.add(listener);
|
|
464
|
+
return createdProvider;
|
|
417
465
|
},
|
|
418
466
|
|
|
419
467
|
removeListener: (event: string, listener: ProviderListener) => {
|
|
420
468
|
providerListeners.get(event)?.delete(listener);
|
|
421
|
-
|
|
422
|
-
return provider!;
|
|
469
|
+
return createdProvider;
|
|
423
470
|
},
|
|
424
|
-
} as
|
|
471
|
+
} as CreditConnectProviderWithEvents;
|
|
425
472
|
|
|
473
|
+
provider = createdProvider;
|
|
426
474
|
return provider;
|
|
427
475
|
},
|
|
428
476
|
|