@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/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gluwa/connect-kit",
3
- "version": "0.1.0-next.0",
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.0",
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
  },
@@ -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 { type ConnectModalProps, type ConnectorId, type WCWallet, type WCSubView } from './types';
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, WAGMI_CONNECTOR_ID } from './hooks/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
- wcSubView: WCSubView;
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
- wcSubView,
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
- wcSubView,
235
- wcSelectedWallet,
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={wcSubView}
200
+ subView={wc.subView}
267
201
  qrUri={qrUri}
268
202
  logoUrl={connectorLogoMap.WALLET_CONNECT}
269
- walletList={wcWalletList}
270
- walletListLoading={wcWalletListLoading}
271
- walletListSearch={wcWalletListSearch}
272
- walletListFilterActive={wcFilterActive}
273
- selectedWallet={wcSelectedWallet}
274
- onShowList={onWCShowList}
275
- onSelectWallet={onWCSelectWallet}
276
- onSearchChange={onWCSearchChange}
277
- onFilterToggle={onWCFilterToggle}
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
- (props.connectors as ConnectorId[]).includes('CREDIT_WALLET') &&
307
- (props.connectors as ConnectorId[]).includes('CREDIT_CONNECT')
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
- // open=false면 내부 컴포넌트를 마운트하지 않음
312
- // useConfig wagmi hooks가 실행되지 않아 WagmiProvider 없이도 렌더링 가능
313
- if (!props.open) return null;
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
- const ConnectModalInner: FC<ConnectModalProps> = ({
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 [wcSubView, setWcSubView] = useState<WCSubView>('qr');
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
- setWcSubView('qr');
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
- for (const [connectorId, wagmiId] of Object.entries(WAGMI_CONNECTOR_ID) as Array<
386
- [ConnectorId, string]
387
- >) {
388
- const wagmiConnector = wagmiConfig.connectors.find((c) => c.id === wagmiId);
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
- setWcSubView('qr');
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
- setWcSubView('qr');
437
- setWcSelectedWallet(null);
370
+ wc.resetView();
438
371
  writeRecentConnector(id);
439
372
  setRecentConnector(id);
440
373
 
441
374
  if (id === 'WALLET_CONNECT' && wcProjectId) {
442
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
443
- loadWCWalletList(wcProjectId);
375
+ wc.loadWalletList(wcProjectId);
444
376
  }
445
377
 
446
378
  cancelConnect();
447
379
  triggerConnect(id);
448
380
  },
449
- [selectedConnector, triggerConnect, cancelConnect, wcProjectId, loadWCWalletList],
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, wcSubView, cancelConnect]);
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
- wcSubView={wcSubView}
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
- return { accounts, chainId } as any;
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
- return { accounts, chainId } as any;
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
- provider = {
281
- request: async (args: unknown) => {
282
- const { method, params } = args as { method: string; params?: unknown[] };
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
- if (!providerListeners.has(event)) providerListeners.set(event, new Set());
413
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
414
- providerListeners.get(event)!.add(listener);
415
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
416
- return provider!;
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
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
422
- return provider!;
469
+ return createdProvider;
423
470
  },
424
- } as unknown as CreditConnectProvider;
471
+ } as CreditConnectProviderWithEvents;
425
472
 
473
+ provider = createdProvider;
426
474
  return provider;
427
475
  },
428
476