@gluwa/connect-kit 0.1.0-next.3 → 0.2.0-next.3
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 +17 -0
- package/assets/creditwallet.png +0 -0
- package/assets/fonts/Inter-Medium.ttf +0 -0
- package/assets/fonts/Inter-Medium.woff2 +0 -0
- package/assets/fonts/Inter-Regular.ttf +0 -0
- package/assets/fonts/Inter-Regular.woff2 +0 -0
- package/assets/fonts/Inter-SemiBold.ttf +0 -0
- package/assets/fonts/Inter-SemiBold.woff2 +0 -0
- package/assets/graphic.png +0 -0
- package/assets/metamask.png +0 -0
- package/assets/wc-logo.svg +3 -0
- package/assets/wc-search.png +0 -0
- package/dist/chunk-EDNRW47A.js +401 -0
- package/dist/credit-connect.js +2 -394
- package/dist/index.css +2074 -0
- package/dist/index.d.ts +53 -33
- package/dist/index.js +1404 -1504
- package/dist/package.json +16 -10
- package/package.json +14 -11
- package/src/ConnectKitProvider.tsx +126 -75
- package/src/api/account.ts +21 -0
- package/src/api/balance.ts +10 -0
- package/src/api/chain.ts +17 -0
- package/src/api/contract.ts +33 -0
- package/src/api/transaction.ts +12 -0
- package/src/assets.d.ts +5 -0
- package/src/components/actionItem/index.tsx +50 -0
- package/src/components/actionItem/style.scss +47 -0
- package/src/components/copyLink/index.tsx +16 -0
- package/src/components/copyLink/style.scss +16 -0
- package/src/components/qrArea/index.tsx +70 -0
- package/src/components/qrArea/style.scss +130 -0
- package/src/components/searchBar/asset/Search.tsx +20 -0
- package/src/components/searchBar/asset/XMarkCircle.tsx +24 -0
- package/src/components/searchBar/index.tsx +44 -0
- package/src/components/searchBar/style.scss +58 -0
- package/src/components/snackbar/index.tsx +25 -0
- package/src/components/snackbar/style.scss +51 -0
- package/src/components/toggle/index.tsx +27 -0
- package/src/components/toggle/style.scss +53 -0
- package/src/components/walletGrid/index.tsx +64 -0
- package/src/components/walletGrid/style.scss +108 -0
- package/src/components/walletItem/index.tsx +49 -0
- package/src/components/walletItem/style.scss +70 -0
- package/src/connector-meta.ts +12 -7
- package/src/core/config.ts +102 -0
- package/src/creditConnectConnector.ts +192 -184
- package/src/events/account.ts +49 -0
- package/src/hooks/useWCState.ts +45 -13
- package/src/hooks/useWagmiConnect.ts +13 -9
- package/src/index.ts +35 -2
- package/src/layout/allWallets/index.tsx +52 -0
- package/src/layout/allWallets/style.scss +62 -0
- package/src/layout/connectDialog/asset/backIcon.tsx +24 -0
- package/src/layout/connectDialog/asset/checkIcon.tsx +28 -0
- package/src/layout/connectDialog/asset/closeIcon.tsx +21 -0
- package/src/layout/connectDialog/asset/copyIcon.tsx +28 -0
- package/src/layout/connectDialog/asset/linkIcon.tsx +24 -0
- package/src/layout/connectDialog/asset/spinner.tsx +21 -0
- package/src/layout/connectDialog/idle/index.tsx +32 -0
- package/src/layout/connectDialog/idle/style.scss +61 -0
- package/src/layout/connectDialog/index.tsx +286 -0
- package/src/layout/connectDialog/loading/index.tsx +13 -0
- package/src/layout/connectDialog/loading/style.scss +19 -0
- package/src/layout/connectDialog/metaMask/index.tsx +61 -0
- package/src/layout/connectDialog/metaMask/style.scss +65 -0
- package/src/layout/connectDialog/qr/index.tsx +33 -0
- package/src/layout/connectDialog/style.scss +95 -0
- package/src/layout/connectDialog/timeout/index.tsx +31 -0
- package/src/layout/connectDialog/timeout/style.scss +64 -0
- package/src/layout/connectDialog/walletConnect/index.tsx +45 -0
- package/src/layout/connectDialog/walletConnect/style.scss +48 -0
- package/src/layout/connectDialog/walletQR/index.tsx +37 -0
- package/src/layout/detailPanel/index.tsx +147 -0
- package/src/layout/detailPanel/style.scss +64 -0
- package/src/layout/selectorPanel/index.tsx +100 -0
- package/src/layout/selectorPanel/style.scss +113 -0
- package/src/style/color.scss +417 -0
- package/src/style/font.scss +28 -0
- package/src/style/index.scss +5 -0
- package/src/style/mixin.scss +217 -0
- package/src/style/reset.scss +110 -0
- package/src/style/variables.scss +13 -0
- package/src/types.ts +19 -7
- package/src/utils/platform.ts +7 -4
- package/tsup.config.ts +32 -2
- package/dist/chunk-DDA6FP6U.js +0 -7
- package/src/ConnectModal.scss +0 -665
- package/src/ConnectModal.tsx +0 -559
- package/src/components/QRFrame.tsx +0 -43
- package/src/views/CreditWalletView.tsx +0 -59
- package/src/views/IdleView.tsx +0 -10
- package/src/views/MetaMaskView.tsx +0 -64
- package/src/views/SwitchChainView.tsx +0 -67
- package/src/views/WalletConnectView.tsx +0 -206
package/dist/package.json
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-next.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
+
"types": "./src/index.ts",
|
|
7
8
|
"default": "./src/index.ts"
|
|
8
9
|
},
|
|
9
10
|
"./credit-connect": {
|
|
11
|
+
"types": "./src/credit-connect.ts",
|
|
10
12
|
"default": "./src/credit-connect.ts"
|
|
11
13
|
},
|
|
14
|
+
"./index.css": "./dist/index.css",
|
|
12
15
|
"./package.json": "./package.json"
|
|
13
16
|
},
|
|
14
17
|
"publishConfig": {
|
|
@@ -27,7 +30,10 @@
|
|
|
27
30
|
"./index.css": "./dist/index.css"
|
|
28
31
|
}
|
|
29
32
|
},
|
|
30
|
-
"sideEffects":
|
|
33
|
+
"sideEffects": [
|
|
34
|
+
"**/*.scss",
|
|
35
|
+
"**/*.css"
|
|
36
|
+
],
|
|
31
37
|
"scripts": {
|
|
32
38
|
"prepack": "pnpm build && cp package.json dist/ && cp README.md dist/",
|
|
33
39
|
"build": "tsup",
|
|
@@ -38,7 +44,13 @@
|
|
|
38
44
|
"author": "",
|
|
39
45
|
"license": "ISC",
|
|
40
46
|
"dependencies": {
|
|
41
|
-
"qrcode.react": "^
|
|
47
|
+
"qrcode.react": "^4.2.0",
|
|
48
|
+
"wagmi": "^2.15.6",
|
|
49
|
+
"@wagmi/core": "^2.16.7",
|
|
50
|
+
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
51
|
+
"@gluwa/credit-connect-storage-local": "workspace:*",
|
|
52
|
+
"@gluwa/credit-connect-e2ee-tweetnacl": "workspace:*",
|
|
53
|
+
"@gluwa/credit-connect-hub-node-ws": "workspace:*"
|
|
42
54
|
},
|
|
43
55
|
"devDependencies": {
|
|
44
56
|
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
@@ -55,17 +67,11 @@
|
|
|
55
67
|
"wagmi": "^2.15.6"
|
|
56
68
|
},
|
|
57
69
|
"peerDependencies": {
|
|
58
|
-
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
59
70
|
"@tanstack/react-query": ">=5.0.0",
|
|
60
|
-
"@wagmi/core": ">=2.0.0",
|
|
61
71
|
"react": "^18.0.0 || ^19.0.0",
|
|
62
|
-
"viem": ">=2.0.0"
|
|
63
|
-
"wagmi": ">=2.0.0"
|
|
72
|
+
"viem": ">=2.0.0"
|
|
64
73
|
},
|
|
65
74
|
"peerDependenciesMeta": {
|
|
66
|
-
"@gluwa/credit-connect-sdk": {
|
|
67
|
-
"optional": true
|
|
68
|
-
},
|
|
69
75
|
"@tanstack/react-query": {
|
|
70
76
|
"optional": true
|
|
71
77
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-next.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -16,11 +16,20 @@
|
|
|
16
16
|
"publishConfig": {
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
|
-
"sideEffects":
|
|
19
|
+
"sideEffects": [
|
|
20
|
+
"**/*.scss",
|
|
21
|
+
"**/*.css"
|
|
22
|
+
],
|
|
20
23
|
"author": "",
|
|
21
24
|
"license": "ISC",
|
|
22
25
|
"dependencies": {
|
|
23
|
-
"qrcode.react": "^
|
|
26
|
+
"qrcode.react": "^4.2.0",
|
|
27
|
+
"wagmi": "^2.15.6",
|
|
28
|
+
"@wagmi/core": "^2.16.7",
|
|
29
|
+
"@gluwa/credit-connect-sdk": "0.2.0-next.3",
|
|
30
|
+
"@gluwa/credit-connect-storage-local": "0.2.0-next.3",
|
|
31
|
+
"@gluwa/credit-connect-e2ee-tweetnacl": "0.2.0-next.3",
|
|
32
|
+
"@gluwa/credit-connect-hub-node-ws": "0.1.0-next.3"
|
|
24
33
|
},
|
|
25
34
|
"devDependencies": {
|
|
26
35
|
"@tanstack/react-query": "^5.62.0",
|
|
@@ -34,20 +43,14 @@
|
|
|
34
43
|
"typescript-eslint": "^8.18.2",
|
|
35
44
|
"viem": "^2.31.7",
|
|
36
45
|
"wagmi": "^2.15.6",
|
|
37
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.
|
|
46
|
+
"@gluwa/credit-connect-sdk": "0.2.0-next.3"
|
|
38
47
|
},
|
|
39
48
|
"peerDependencies": {
|
|
40
49
|
"@tanstack/react-query": ">=5.0.0",
|
|
41
|
-
"@wagmi/core": ">=2.0.0",
|
|
42
50
|
"react": "^18.0.0 || ^19.0.0",
|
|
43
|
-
"viem": ">=2.0.0"
|
|
44
|
-
"wagmi": ">=2.0.0",
|
|
45
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.1"
|
|
51
|
+
"viem": ">=2.0.0"
|
|
46
52
|
},
|
|
47
53
|
"peerDependenciesMeta": {
|
|
48
|
-
"@gluwa/credit-connect-sdk": {
|
|
49
|
-
"optional": true
|
|
50
|
-
},
|
|
51
54
|
"@tanstack/react-query": {
|
|
52
55
|
"optional": true
|
|
53
56
|
}
|
|
@@ -9,53 +9,45 @@ import {
|
|
|
9
9
|
type FC,
|
|
10
10
|
type ReactNode,
|
|
11
11
|
} from 'react';
|
|
12
|
-
import { WagmiProvider, useAccount, useDisconnect } from 'wagmi';
|
|
13
|
-
import
|
|
12
|
+
import { WagmiProvider, useAccount, useConfig, useDisconnect, useSwitchChain } from 'wagmi';
|
|
13
|
+
import { getAccount } from '@wagmi/core';
|
|
14
14
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
15
|
-
import { ConnectModal } from './ConnectModal';
|
|
16
|
-
import
|
|
15
|
+
// import { ConnectModal } from './ConnectModal';
|
|
16
|
+
import { ConnectDialog } from './layout/connectDialog';
|
|
17
|
+
import { getConfig, getKitConfig, initConfig } from './core/config';
|
|
18
|
+
import { resolveConnectorId } from './connector-meta';
|
|
19
|
+
import type {
|
|
20
|
+
ConnectErrorContext,
|
|
21
|
+
ConnectKitConfig,
|
|
22
|
+
ConnectKitTheme,
|
|
23
|
+
ConnectResult,
|
|
24
|
+
ConnectorId,
|
|
25
|
+
ConnectorKey,
|
|
26
|
+
Connectors,
|
|
27
|
+
} from './types';
|
|
17
28
|
|
|
18
|
-
// wagmiConfig prop으로 기존 프로젝트 통합 시 내부에서 사용하는 QueryClient.
|
|
19
|
-
// 모듈 레벨에 한 번만 생성 — 연결 플로우용으로만 쓰이므로 공유해도 무방.
|
|
20
29
|
const internalQueryClient = new QueryClient();
|
|
21
30
|
|
|
22
31
|
export interface ConnectKitProviderProps {
|
|
23
32
|
children: ReactNode;
|
|
33
|
+
kitConfig?: ConnectKitConfig;
|
|
24
34
|
connectors: Connectors;
|
|
25
|
-
wcProjectId?: string;
|
|
26
|
-
/**
|
|
27
|
-
* 연결돼 있는 동안 강제할 체인 ID. 다른 체인에 연결돼 있으면
|
|
28
|
-
* 자동으로 스위치 모달이 떠서 사용자에게 전환 또는 disconnect를 요구.
|
|
29
|
-
*/
|
|
30
35
|
requiredChainId?: number;
|
|
31
|
-
|
|
32
|
-
* 연결이 정상적으로 끝나고(체인 검증까지 통과) "사용 가능한 상태"가 됐을 때 한 번 호출.
|
|
33
|
-
* 재연결(reconnect)에서는 호출되지 않음 — 그쪽은 dApp의 watchAccount 책임.
|
|
34
|
-
*/
|
|
36
|
+
theme: ConnectKitTheme;
|
|
35
37
|
onConnect?: (result: ConnectResult) => void;
|
|
36
38
|
onLog?: (message: string, error?: Error) => void;
|
|
37
|
-
/**
|
|
38
|
-
* 연결 실패(거절/미설치/기타) 시 모달 안에 표시할 fallback UI를 dApp이 직접 그리고 싶을 때.
|
|
39
|
-
* 미제공 시 기본 동작은 selector로 복귀.
|
|
40
|
-
*/
|
|
41
39
|
renderConnectError?: (ctx: ConnectErrorContext) => ReactNode;
|
|
42
|
-
/**
|
|
43
|
-
* 기존 프로젝트 통합용. wagmi config를 넘기면 ConnectKitProvider 내부에서
|
|
44
|
-
* WagmiProvider를 직접 세운다.
|
|
45
|
-
*
|
|
46
|
-
* - 기존 프로젝트: 앱에 WagmiProvider가 없으므로 wagmiConfig를 넘긴다.
|
|
47
|
-
* ConnectKitProvider가 같은 config 인스턴스로 WagmiProvider를 셀프 마운트하므로
|
|
48
|
-
* 기존 wagmi 상태 store와 단일 config를 공유한다.
|
|
49
|
-
* - 신규 프로젝트: 앱이 이미 WagmiProvider를 감싸므로 이 prop은 불필요하다.
|
|
50
|
-
*/
|
|
51
|
-
wagmiConfig?: Config;
|
|
52
40
|
}
|
|
53
|
-
|
|
54
41
|
export interface ConnectKitContextValue {
|
|
55
42
|
isOpen: boolean;
|
|
56
43
|
open: () => void;
|
|
57
44
|
close: () => void;
|
|
58
45
|
isConnected: boolean;
|
|
46
|
+
needsChainSwitch: boolean;
|
|
47
|
+
requiredChainId: number | undefined;
|
|
48
|
+
currentChainId: number | undefined;
|
|
49
|
+
isSwitchingChain: boolean;
|
|
50
|
+
switchToRequiredChain: () => Promise<void>;
|
|
59
51
|
address: `0x${string}` | undefined;
|
|
60
52
|
connectorId: ConnectorId | null;
|
|
61
53
|
disconnect: () => Promise<void>;
|
|
@@ -63,58 +55,80 @@ export interface ConnectKitContextValue {
|
|
|
63
55
|
|
|
64
56
|
const ConnectKitContext = createContext<ConnectKitContextValue | null>(null);
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
58
|
+
// 외부 API Connectors (ConnectorKey 배열) → 내부 ConnectorId[] 매핑.
|
|
59
|
+
// 입력 순서 그대로 selector 표시 순서.
|
|
60
|
+
const CONNECTOR_KEY_TO_ID: Record<ConnectorKey, ConnectorId> = {
|
|
61
|
+
creditWallet: 'CREDIT_CONNECT',
|
|
62
|
+
metamask: 'METAMASK',
|
|
63
|
+
walletConnect: 'WALLET_CONNECT',
|
|
64
|
+
};
|
|
65
|
+
const resolveConnectorsFromConfig = (connectorsConfig?: Connectors): ConnectorId[] => {
|
|
66
|
+
if (!connectorsConfig) return [];
|
|
67
|
+
return connectorsConfig.map((key) => CONNECTOR_KEY_TO_ID[key]);
|
|
74
68
|
};
|
|
75
69
|
|
|
76
70
|
export const ConnectKitProvider: FC<ConnectKitProviderProps> = (props) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
71
|
+
const wagmiConfig = useMemo(
|
|
72
|
+
() => (props.kitConfig ? initConfig(props.kitConfig) : getConfig()),
|
|
73
|
+
[props.kitConfig],
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const resolvedKitConfig = props.kitConfig ?? getKitConfig();
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<WagmiProvider config={wagmiConfig} reconnectOnMount={false}>
|
|
80
|
+
<QueryClientProvider client={internalQueryClient}>
|
|
81
|
+
<ConnectKitProviderInner {...props} kitConfig={resolvedKitConfig} />
|
|
82
|
+
</QueryClientProvider>
|
|
83
|
+
</WagmiProvider>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
type ConnectKitProviderInnerProps = Omit<ConnectKitProviderProps, 'kitConfig'> & {
|
|
88
|
+
kitConfig: ConnectKitConfig;
|
|
87
89
|
};
|
|
88
90
|
|
|
89
|
-
const ConnectKitProviderInner: FC<
|
|
91
|
+
const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
90
92
|
children,
|
|
91
93
|
connectors,
|
|
92
|
-
|
|
94
|
+
kitConfig,
|
|
93
95
|
requiredChainId,
|
|
96
|
+
theme,
|
|
94
97
|
onConnect,
|
|
95
98
|
onLog,
|
|
96
|
-
renderConnectError,
|
|
97
99
|
}) => {
|
|
100
|
+
// NOTE: renderConnectError 는 ConnectDialog 가 아직 error UI customization 을 받지 않으므로
|
|
101
|
+
// destructure 에서 제외. 추후 ConnectDialog 의 timeout/error content 에 wire 필요 시 복원.
|
|
98
102
|
const [isOpen, setIsOpen] = useState(false);
|
|
99
103
|
const [pendingResult, setPendingResult] = useState<ConnectResult | null>(null);
|
|
100
104
|
|
|
101
105
|
const account = useAccount();
|
|
106
|
+
const wagmiConfig = useConfig();
|
|
102
107
|
const { disconnectAsync } = useDisconnect();
|
|
108
|
+
const { switchChainAsync } = useSwitchChain();
|
|
103
109
|
|
|
104
|
-
// dApp의 onConnect는 ref로 잡아 effect 재실행 노이즈 차단
|
|
105
110
|
const onConnectRef = useRef(onConnect);
|
|
106
111
|
useEffect(() => {
|
|
107
112
|
onConnectRef.current = onConnect;
|
|
108
113
|
}, [onConnect]);
|
|
109
114
|
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
const isMountedRef = useRef(true);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
isMountedRef.current = true;
|
|
118
|
+
return () => {
|
|
119
|
+
isMountedRef.current = false;
|
|
120
|
+
};
|
|
121
|
+
}, []);
|
|
122
|
+
|
|
123
|
+
const needsChainSwitch =
|
|
112
124
|
requiredChainId != null &&
|
|
113
125
|
account.status === 'connected' &&
|
|
114
126
|
account.chainId != null &&
|
|
115
127
|
account.chainId !== requiredChainId;
|
|
116
128
|
|
|
117
|
-
const
|
|
129
|
+
const [isSwitchingChain, setIsSwitchingChain] = useState(false);
|
|
130
|
+
|
|
131
|
+
const effectiveOpen = isOpen;
|
|
118
132
|
|
|
119
133
|
const open = useCallback((): void => {
|
|
120
134
|
setIsOpen(true);
|
|
@@ -122,34 +136,62 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
122
136
|
|
|
123
137
|
const close = useCallback((): void => {
|
|
124
138
|
setIsOpen(false);
|
|
125
|
-
|
|
139
|
+
const status = getAccount(wagmiConfig).status;
|
|
140
|
+
if (status === 'connecting' || status === 'reconnecting') {
|
|
141
|
+
disconnectAsync().catch(() => undefined);
|
|
142
|
+
}
|
|
143
|
+
}, [wagmiConfig, disconnectAsync]);
|
|
126
144
|
|
|
127
145
|
const disconnect = useCallback(async (): Promise<void> => {
|
|
128
146
|
await disconnectAsync();
|
|
129
147
|
}, [disconnectAsync]);
|
|
130
148
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
const switchToRequiredChain = useCallback(async (): Promise<void> => {
|
|
150
|
+
if (requiredChainId == null) return;
|
|
151
|
+
setIsSwitchingChain(true);
|
|
152
|
+
try {
|
|
153
|
+
await switchChainAsync({ chainId: requiredChainId });
|
|
154
|
+
} finally {
|
|
155
|
+
if (isMountedRef.current) setIsSwitchingChain(false);
|
|
156
|
+
}
|
|
157
|
+
}, [requiredChainId, switchChainAsync]);
|
|
158
|
+
|
|
159
|
+
// ConnectDialog 의 wagmi connect 성공 → pendingResult set → 아래 useEffect 가
|
|
160
|
+
// account.status === 'connected' 확인 후 외부 onConnect 호출 + modal close.
|
|
161
|
+
// wagmi state 가 비동기로 'connected' 로 전환되는 race 흡수용.
|
|
162
|
+
const handleDialogConnect = useCallback((result: ConnectResult): void => {
|
|
134
163
|
setPendingResult(result);
|
|
135
164
|
}, []);
|
|
136
165
|
|
|
137
|
-
|
|
138
|
-
|
|
166
|
+
const handleDialogError = useCallback(
|
|
167
|
+
(error: Error, connectorId: ConnectorId): void => {
|
|
168
|
+
onLog?.(`[connect-kit] connect failed: ${connectorId} — ${error.message}`, error);
|
|
169
|
+
},
|
|
170
|
+
[onLog],
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// 연결 성공 시 modal 자동 close — wagmi state 만 기준으로.
|
|
174
|
+
// 이전 구현은 pendingResult 가 set 된 경우만 close 했는데, `setPendingResult` 는
|
|
175
|
+
// ConnectDialog 의 onConnect (`connectAsync.then`) 안에서만 호출됨. MM deeplink 같은
|
|
176
|
+
// 시나리오 (앱 이동 → 승인 → 복귀) 에서 wagmi 가 자체적으로 'connected' 로 전이하지만
|
|
177
|
+
// connectAsync 의 promise 는 resolve 안 될 수 있음 → pendingResult set 안 됨 → modal 안 닫힘.
|
|
178
|
+
// 모든 connector (WC/CC/MM) 의 connected 가 일관된 close 트리거가 되도록 단순화.
|
|
179
|
+
useEffect((): void => {
|
|
180
|
+
if (!effectiveOpen) return;
|
|
181
|
+
if (account.status !== 'connected') return;
|
|
182
|
+
setIsOpen(false);
|
|
183
|
+
}, [effectiveOpen, account.status]);
|
|
184
|
+
|
|
185
|
+
// 외부 onConnect 콜백은 best-effort — pendingResult 가 set 된 경우만 호출.
|
|
186
|
+
useEffect((): void => {
|
|
139
187
|
if (!pendingResult) return;
|
|
140
188
|
if (account.status !== 'connected') {
|
|
141
|
-
// 연결이 끊겼거나 진행 중 — pending 폐기
|
|
142
189
|
setPendingResult(null);
|
|
143
190
|
return;
|
|
144
191
|
}
|
|
145
|
-
if (requiredChainId != null && account.chainId !== requiredChainId) {
|
|
146
|
-
// chain 아직 안 맞음 — switch 후 다시 평가
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
192
|
onConnectRef.current?.(pendingResult);
|
|
150
193
|
setPendingResult(null);
|
|
151
|
-
|
|
152
|
-
}, [pendingResult, account.status, account.chainId, requiredChainId]);
|
|
194
|
+
}, [pendingResult, account.status]);
|
|
153
195
|
|
|
154
196
|
const value = useMemo<ConnectKitContextValue>(
|
|
155
197
|
() => ({
|
|
@@ -157,6 +199,11 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
157
199
|
open,
|
|
158
200
|
close,
|
|
159
201
|
isConnected: account.status === 'connected',
|
|
202
|
+
needsChainSwitch,
|
|
203
|
+
requiredChainId,
|
|
204
|
+
currentChainId: account.chainId,
|
|
205
|
+
isSwitchingChain,
|
|
206
|
+
switchToRequiredChain,
|
|
160
207
|
address: account.address,
|
|
161
208
|
connectorId: resolveConnectorId(account.connector?.id),
|
|
162
209
|
disconnect,
|
|
@@ -166,6 +213,11 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
166
213
|
open,
|
|
167
214
|
close,
|
|
168
215
|
account.status,
|
|
216
|
+
needsChainSwitch,
|
|
217
|
+
requiredChainId,
|
|
218
|
+
account.chainId,
|
|
219
|
+
isSwitchingChain,
|
|
220
|
+
switchToRequiredChain,
|
|
169
221
|
account.address,
|
|
170
222
|
account.connector?.id,
|
|
171
223
|
disconnect,
|
|
@@ -175,15 +227,14 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
175
227
|
return (
|
|
176
228
|
<ConnectKitContext.Provider value={value}>
|
|
177
229
|
{children}
|
|
178
|
-
<
|
|
230
|
+
<ConnectDialog
|
|
179
231
|
open={effectiveOpen}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
renderConnectError={renderConnectError}
|
|
184
|
-
onConnect={handleModalConnect}
|
|
232
|
+
theme={theme}
|
|
233
|
+
connectors={resolveConnectorsFromConfig(connectors)}
|
|
234
|
+
wcProjectId={kitConfig.wcProjectId}
|
|
185
235
|
onClose={close}
|
|
186
|
-
|
|
236
|
+
onConnect={handleDialogConnect}
|
|
237
|
+
onError={handleDialogError}
|
|
187
238
|
/>
|
|
188
239
|
</ConnectKitContext.Provider>
|
|
189
240
|
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAccount as wagmiGetAccount,
|
|
3
|
+
signMessage as wagmiSignMessage,
|
|
4
|
+
signTypedData as wagmiSignTypedData,
|
|
5
|
+
type GetAccountReturnType,
|
|
6
|
+
type SignMessageParameters,
|
|
7
|
+
type SignTypedDataParameters,
|
|
8
|
+
} from '@wagmi/core';
|
|
9
|
+
import { getConfig } from '../core/config';
|
|
10
|
+
|
|
11
|
+
export const getAccount = (): GetAccountReturnType => {
|
|
12
|
+
return wagmiGetAccount(getConfig());
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const signMessage = (params: SignMessageParameters): Promise<`0x${string}`> => {
|
|
16
|
+
return wagmiSignMessage(getConfig(), params);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const signTypedData = (params: SignTypedDataParameters): Promise<`0x${string}`> => {
|
|
20
|
+
return wagmiSignTypedData(getConfig(), params);
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBalance as wagmiGetBalance,
|
|
3
|
+
type GetBalanceParameters,
|
|
4
|
+
type GetBalanceReturnType,
|
|
5
|
+
} from '@wagmi/core';
|
|
6
|
+
import { getConfig } from '../core/config';
|
|
7
|
+
|
|
8
|
+
export const getBalance = (params: GetBalanceParameters): Promise<GetBalanceReturnType> => {
|
|
9
|
+
return wagmiGetBalance(getConfig(), params);
|
|
10
|
+
};
|
package/src/api/chain.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
switchChain as wagmiSwitchChain,
|
|
3
|
+
getPublicClient as wagmiGetPublicClient,
|
|
4
|
+
type SwitchChainParameters,
|
|
5
|
+
type GetPublicClientParameters,
|
|
6
|
+
type GetPublicClientReturnType,
|
|
7
|
+
} from '@wagmi/core';
|
|
8
|
+
import type { Chain } from 'viem';
|
|
9
|
+
import { getConfig } from '../core/config';
|
|
10
|
+
|
|
11
|
+
export const switchChain = (params: SwitchChainParameters): Promise<Chain> => {
|
|
12
|
+
return wagmiSwitchChain(getConfig(), params);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const getPublicClient = (params?: GetPublicClientParameters): GetPublicClientReturnType => {
|
|
16
|
+
return wagmiGetPublicClient(getConfig(), params);
|
|
17
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readContract as wagmiReadContract,
|
|
3
|
+
writeContract as wagmiWriteContract,
|
|
4
|
+
type ReadContractParameters,
|
|
5
|
+
type ReadContractReturnType,
|
|
6
|
+
type WriteContractParameters,
|
|
7
|
+
type WriteContractReturnType,
|
|
8
|
+
type Config,
|
|
9
|
+
} from '@wagmi/core';
|
|
10
|
+
import type { Abi, ContractFunctionArgs, ContractFunctionName } from 'viem';
|
|
11
|
+
import { getConfig } from '../core/config';
|
|
12
|
+
|
|
13
|
+
export function readContract<
|
|
14
|
+
const abi extends Abi | readonly unknown[],
|
|
15
|
+
functionName extends ContractFunctionName<abi, 'pure' | 'view'>,
|
|
16
|
+
args extends ContractFunctionArgs<abi, 'pure' | 'view', functionName>,
|
|
17
|
+
>(
|
|
18
|
+
parameters: ReadContractParameters<abi, functionName, args, Config>,
|
|
19
|
+
): Promise<ReadContractReturnType<abi, functionName, args>> {
|
|
20
|
+
return wagmiReadContract(getConfig(), parameters as any) as Promise<
|
|
21
|
+
ReadContractReturnType<abi, functionName, args>
|
|
22
|
+
>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function writeContract<
|
|
26
|
+
const abi extends Abi | readonly unknown[],
|
|
27
|
+
functionName extends ContractFunctionName<abi, 'nonpayable' | 'payable'>,
|
|
28
|
+
args extends ContractFunctionArgs<abi, 'nonpayable' | 'payable', functionName>,
|
|
29
|
+
>(
|
|
30
|
+
parameters: WriteContractParameters<abi, functionName, args, Config>,
|
|
31
|
+
): Promise<WriteContractReturnType> {
|
|
32
|
+
return wagmiWriteContract(getConfig(), parameters as any);
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
waitForTransactionReceipt as wagmiWaitForTransactionReceipt,
|
|
3
|
+
type WaitForTransactionReceiptParameters,
|
|
4
|
+
type WaitForTransactionReceiptReturnType,
|
|
5
|
+
} from '@wagmi/core';
|
|
6
|
+
import { getConfig } from '../core/config';
|
|
7
|
+
|
|
8
|
+
export const waitForTransactionReceipt = (
|
|
9
|
+
params: WaitForTransactionReceiptParameters,
|
|
10
|
+
): Promise<WaitForTransactionReceiptReturnType> => {
|
|
11
|
+
return wagmiWaitForTransactionReceipt(getConfig(), params);
|
|
12
|
+
};
|
package/src/assets.d.ts
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ReactNode, type AnchorHTMLAttributes, type ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import './style.scss';
|
|
3
|
+
|
|
4
|
+
interface ActionItemContent {
|
|
5
|
+
label?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
action?: string;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type ActionItemAsAnchor = { as: 'a' } & AnchorHTMLAttributes<HTMLAnchorElement> & ActionItemContent;
|
|
12
|
+
type ActionItemAsButton = { as: 'button' } & ButtonHTMLAttributes<HTMLButtonElement> &
|
|
13
|
+
ActionItemContent;
|
|
14
|
+
|
|
15
|
+
type ActionItemProps = ActionItemAsAnchor | ActionItemAsButton;
|
|
16
|
+
|
|
17
|
+
const ActionItemBody = ({ label, description, action, children }: ActionItemContent): ReactNode => {
|
|
18
|
+
if (children) return <>{children}</>;
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<span className="ck-action-item-content">
|
|
22
|
+
<span className="ck-action-item-label">{label}</span>
|
|
23
|
+
{description && <span className="ck-action-item-desc">{description}</span>}
|
|
24
|
+
</span>
|
|
25
|
+
{action && <span className="ck-action-item-action">{action}</span>}
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const ActionItem = (props: ActionItemProps) => {
|
|
31
|
+
if (props.as === 'a') {
|
|
32
|
+
const { as: _, label, description, action, children, className, ...rest } = props;
|
|
33
|
+
return (
|
|
34
|
+
<a className={`ck-action-item${className ? ` ${className}` : ''}`} {...rest}>
|
|
35
|
+
<ActionItemBody label={label} description={description} action={action}>
|
|
36
|
+
{children}
|
|
37
|
+
</ActionItemBody>
|
|
38
|
+
</a>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { as: _, label, description, action, children, className, ...rest } = props;
|
|
43
|
+
return (
|
|
44
|
+
<button className={`ck-action-item${className ? ` ${className}` : ''}`} {...rest}>
|
|
45
|
+
<ActionItemBody label={label} description={description} action={action}>
|
|
46
|
+
{children}
|
|
47
|
+
</ActionItemBody>
|
|
48
|
+
</button>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
@use '../../style/mixin.scss' as *;
|
|
2
|
+
|
|
3
|
+
.ck-root .ck-action-item {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 16px;
|
|
7
|
+
width: 100%;
|
|
8
|
+
padding: 16px 20px;
|
|
9
|
+
border-radius: 12px;
|
|
10
|
+
background: var(--scale-gray-100);
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
margin-top: auto;
|
|
13
|
+
flex-shrink: 0;
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.ck-action-item-content {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: 2px;
|
|
21
|
+
flex: 1;
|
|
22
|
+
min-width: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.ck-action-item-label {
|
|
26
|
+
@include textToken('subtitle2-bold');
|
|
27
|
+
color: var(--scale-gray-900);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.ck-action-item-desc {
|
|
31
|
+
@include textToken('label5-regular');
|
|
32
|
+
color: var(--scale-gray-600);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ck-action-item-action {
|
|
36
|
+
display: inline-flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
padding: 0 20px;
|
|
40
|
+
height: 44px;
|
|
41
|
+
border-radius: 6px;
|
|
42
|
+
background: var(--scale-blue2-alpha-100);
|
|
43
|
+
@include textToken('label5-bold');
|
|
44
|
+
color: var(--semantic-brand-trugi-primary);
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
flex-shrink: 0;
|
|
47
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import './style.scss';
|
|
3
|
+
import { CopyIcon } from '../../layout/connectDialog/asset/copyIcon';
|
|
4
|
+
|
|
5
|
+
interface CopyLinkProps {
|
|
6
|
+
onCopy?: () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const CopyLink: FC<CopyLinkProps> = ({ onCopy }) => {
|
|
10
|
+
return (
|
|
11
|
+
<button type="button" className="ck-copy-link" onClick={onCopy}>
|
|
12
|
+
<CopyIcon className="ck-copy-link-icon" />
|
|
13
|
+
Copy link
|
|
14
|
+
</button>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@use '../../style/mixin.scss' as *;
|
|
2
|
+
|
|
3
|
+
.ck-root .ck-copy-link {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
align-self: center;
|
|
7
|
+
gap: 6px;
|
|
8
|
+
@include textToken('body3-l1-regular');
|
|
9
|
+
color: var(--scale-gray-500);
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ck-copy-link-icon {
|
|
14
|
+
flex-shrink: 0;
|
|
15
|
+
color: var(--scale-gray-500);
|
|
16
|
+
}
|