@btc-vision/walletconnect 1.5.0 → 1.5.2
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/.prettierrc.json +1 -1
- package/CHANGELOG.md +83 -0
- package/README.md +11 -11
- package/browser/consts.d.ts +2 -0
- package/browser/context/WalletConnectContext.d.ts +18 -0
- package/browser/hooks/WalletConnectHook.d.ts +2 -0
- package/browser/index.d.ts +4 -2
- package/browser/index.js +1 -1
- package/browser/index.js.LICENSE.txt +0 -2
- package/browser/provider/WalletConnectProvider.d.ts +9 -0
- package/browser/types.d.ts +11 -0
- package/browser/utils/accessibility/definitions.d.ts +2 -0
- package/browser/utils/accessibility/errorDecoder.d.ts +2 -0
- package/browser/utils/accessibility/patterns.d.ts +13 -0
- package/browser/wallets/controller.d.ts +29 -0
- package/browser/wallets/index.d.ts +4 -0
- package/browser/wallets/opwallet/controller.d.ts +26 -0
- package/browser/wallets/opwallet/interface.d.ts +5 -0
- package/browser/wallets/types.d.ts +34 -0
- package/browser/wallets/unisat/controller.d.ts +26 -0
- package/browser/wallets/unisat/interface.d.ts +5 -0
- package/build/consts.d.ts +2 -0
- package/build/consts.js +6 -0
- package/build/context/WalletConnectContext.d.ts +18 -0
- package/build/context/WalletConnectContext.js +2 -0
- package/build/hooks/WalletConnectHook.d.ts +2 -0
- package/build/hooks/WalletConnectHook.js +9 -0
- package/build/index.d.ts +4 -2
- package/build/index.js +4 -2
- package/build/provider/WalletConnectProvider.d.ts +9 -0
- package/build/provider/WalletConnectProvider.js +178 -0
- package/build/types.d.ts +11 -0
- package/build/types.js +1 -0
- package/build/utils/accessibility/definitions.d.ts +2 -0
- package/build/utils/accessibility/definitions.js +8 -0
- package/build/utils/accessibility/errorDecoder.d.ts +2 -0
- package/build/utils/accessibility/errorDecoder.js +73 -0
- package/build/utils/accessibility/patterns.d.ts +13 -0
- package/build/utils/accessibility/patterns.js +51 -0
- package/build/wallets/controller.d.ts +29 -0
- package/build/wallets/controller.js +205 -0
- package/build/wallets/index.d.ts +4 -0
- package/build/wallets/index.js +16 -0
- package/build/wallets/opwallet/controller.d.ts +26 -0
- package/build/wallets/opwallet/controller.js +132 -0
- package/build/wallets/opwallet/interface.d.ts +5 -0
- package/build/wallets/opwallet/interface.js +35 -0
- package/build/wallets/types.d.ts +34 -0
- package/build/wallets/types.js +1 -0
- package/build/wallets/unisat/controller.d.ts +26 -0
- package/build/wallets/unisat/controller.js +135 -0
- package/build/wallets/unisat/interface.d.ts +5 -0
- package/build/wallets/unisat/interface.js +285 -0
- package/eslint.config.js +23 -2
- package/package.json +10 -5
- package/src/README.md +24 -0
- package/src/consts.ts +8 -0
- package/src/context/WalletConnectContext.ts +21 -0
- package/src/hooks/WalletConnectHook.tsx +13 -0
- package/src/index.ts +5 -2
- package/src/provider/WalletConnectProvider.tsx +341 -0
- package/src/types.ts +13 -0
- package/src/utils/accessibility/definitions.ts +9 -0
- package/src/utils/accessibility/errorDecoder.ts +105 -0
- package/src/utils/accessibility/patterns.ts +86 -0
- package/src/utils/style.css +131 -0
- package/src/utils/theme.css +26 -0
- package/src/wallets/controller.ts +231 -0
- package/src/wallets/index.ts +22 -0
- package/src/wallets/opwallet/controller.ts +177 -0
- package/src/wallets/opwallet/interface.ts +42 -0
- package/src/wallets/types.ts +39 -0
- package/src/wallets/unisat/controller.ts +179 -0
- package/src/wallets/unisat/interface.ts +292 -0
- package/tsconfig.webpack.json +2 -6
- package/webpack.config.js +4 -0
- package/browser/WalletConnection.d.ts +0 -21
- package/browser/WalletProvider.d.ts +0 -25
- package/build/WalletConnection.d.ts +0 -21
- package/build/WalletConnection.js +0 -152
- package/build/WalletProvider.d.ts +0 -25
- package/build/WalletProvider.js +0 -178
- package/src/WalletConnection.ts +0 -210
- package/src/WalletProvider.tsx +0 -240
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { Address, Unisat, UnisatSigner } from '@btc-vision/transaction';
|
|
2
|
+
import React, { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { DefaultWalletConnectNetwork } from '../consts';
|
|
4
|
+
import { WalletConnectContext } from '../context/WalletConnectContext';
|
|
5
|
+
import type { WalletConnectNetwork, WalletInformation } from '../types.ts';
|
|
6
|
+
import '../utils/style.css';
|
|
7
|
+
import '../utils/theme.css';
|
|
8
|
+
import { SupportedWallets, WalletController } from '../wallets';
|
|
9
|
+
import type {
|
|
10
|
+
ControllerConnectAccounts,
|
|
11
|
+
ControllerErrorResponse,
|
|
12
|
+
ControllerResponse,
|
|
13
|
+
WalletConnectWallet,
|
|
14
|
+
} from '../wallets/types.ts';
|
|
15
|
+
|
|
16
|
+
const AUTO_RECONNECT_RETRIES = 5;
|
|
17
|
+
|
|
18
|
+
interface WalletConnectProviderProps {
|
|
19
|
+
theme?: 'light' | 'dark' | 'moto';
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const WalletConnectProvider: React.FC<WalletConnectProviderProps> = ({ theme, children }) => {
|
|
24
|
+
const [connectError, setConnectError] = useState<string | undefined>(undefined);
|
|
25
|
+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
26
|
+
|
|
27
|
+
const [network, setNetwork] = useState<WalletConnectNetwork>(DefaultWalletConnectNetwork);
|
|
28
|
+
|
|
29
|
+
const [supportedWallets] = useState<WalletConnectWallet[]>(WalletController.getWallets);
|
|
30
|
+
const [selectedWallet, setSelectedWallet] = useState<SupportedWallets | null>(
|
|
31
|
+
() => (localStorage.getItem('WC_SelectedWallet') as SupportedWallets) || null,
|
|
32
|
+
);
|
|
33
|
+
const [connecting, setConnecting] = useState<boolean>(false);
|
|
34
|
+
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
|
35
|
+
|
|
36
|
+
const [walletAddress, setWalletAddress] = useState<string | null>(null);
|
|
37
|
+
const [publicKey, setPublicKey] = useState<string | null>(null);
|
|
38
|
+
const [walletType, setWalletType] = useState<SupportedWallets | null>(null);
|
|
39
|
+
const [provider, setProvider] = useState<Unisat | null>(null);
|
|
40
|
+
const [signer, setSigner] = useState<UnisatSigner | null>(null);
|
|
41
|
+
|
|
42
|
+
const clearConnectError = useCallback(() => {
|
|
43
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
44
|
+
timeoutRef.current = setTimeout(() => setConnectError(undefined), 5000);
|
|
45
|
+
}, []);
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (connectError) {
|
|
49
|
+
clearConnectError();
|
|
50
|
+
}
|
|
51
|
+
}, [connectError, clearConnectError]);
|
|
52
|
+
|
|
53
|
+
const openConnectModal = () => {
|
|
54
|
+
setConnectError(undefined);
|
|
55
|
+
setModalOpen(true);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const closeConnectModal = () => {
|
|
59
|
+
setModalOpen(false);
|
|
60
|
+
setConnectError(undefined);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const disconnect = useCallback(async () => {
|
|
64
|
+
console.log('DISCONNECTING FROM WALLET');
|
|
65
|
+
localStorage.removeItem('WC_SelectedWallet');
|
|
66
|
+
setSelectedWallet(null);
|
|
67
|
+
setPublicKey(null);
|
|
68
|
+
setWalletAddress(null);
|
|
69
|
+
setConnecting(false);
|
|
70
|
+
WalletController.removeDisconnectHook();
|
|
71
|
+
WalletController.removeChainChangedHook();
|
|
72
|
+
WalletController.removeAccountsChangedHook();
|
|
73
|
+
await WalletController.disconnect();
|
|
74
|
+
setNetwork(DefaultWalletConnectNetwork); // Triggers allWallets update after disconnecting
|
|
75
|
+
}, []);
|
|
76
|
+
|
|
77
|
+
const connectToWallet = useCallback(
|
|
78
|
+
async (wallet: SupportedWallets) => {
|
|
79
|
+
setConnecting(true);
|
|
80
|
+
try {
|
|
81
|
+
const response: ControllerResponse<
|
|
82
|
+
ControllerConnectAccounts | ControllerErrorResponse
|
|
83
|
+
> = await WalletController.connect(wallet);
|
|
84
|
+
|
|
85
|
+
if (response.code === 200 && Array.isArray(response.data)) {
|
|
86
|
+
if (!response.data || response.data.length === 0) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
setWalletAddress(response.data[0]);
|
|
90
|
+
const publicKey = await WalletController.getPublicKey();
|
|
91
|
+
setPublicKey(publicKey);
|
|
92
|
+
const network = await WalletController.getNetwork();
|
|
93
|
+
setNetwork(network);
|
|
94
|
+
|
|
95
|
+
WalletController.setAccountsChangedHook(accountsChanged);
|
|
96
|
+
WalletController.setChainChangedHook(chainChanged);
|
|
97
|
+
WalletController.setDisconnectHook(disconnect);
|
|
98
|
+
|
|
99
|
+
closeConnectModal();
|
|
100
|
+
setSelectedWallet(wallet);
|
|
101
|
+
localStorage.setItem('WC_SelectedWallet', wallet);
|
|
102
|
+
} else if (response.data && 'message' in response.data) {
|
|
103
|
+
setConnectError(response.data.message);
|
|
104
|
+
} else {
|
|
105
|
+
setConnectError('Unknown error');
|
|
106
|
+
}
|
|
107
|
+
} catch (err: unknown) {
|
|
108
|
+
setConnectError((err as Error).message || 'Unexpected error');
|
|
109
|
+
} finally {
|
|
110
|
+
setConnecting(false);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
// eslint-disable-next-line
|
|
114
|
+
[disconnect],
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const attemptReconnect = useCallback(async () => {
|
|
118
|
+
console.warn('Trying to reconnect...', selectedWallet, connecting);
|
|
119
|
+
if (!selectedWallet || connecting) return;
|
|
120
|
+
|
|
121
|
+
// Ensure we can connect without launching modal popup windows!
|
|
122
|
+
const canAutoConnect = await WalletController.canAutoConnect(selectedWallet);
|
|
123
|
+
console.log('CanAutoConnect', canAutoConnect);
|
|
124
|
+
if (!canAutoConnect) return;
|
|
125
|
+
|
|
126
|
+
let attempts = 0;
|
|
127
|
+
|
|
128
|
+
const reconnect = async () => {
|
|
129
|
+
attempts++;
|
|
130
|
+
|
|
131
|
+
const walletAvailable = WalletController.isWalletInstalled(selectedWallet);
|
|
132
|
+
if (walletAvailable) {
|
|
133
|
+
console.log(`Attempting to reconnect to ${selectedWallet} (Attempt ${attempts})`);
|
|
134
|
+
await connectToWallet(selectedWallet);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (attempts < AUTO_RECONNECT_RETRIES) {
|
|
139
|
+
setTimeout(reconnect, 1000 * attempts);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
await reconnect();
|
|
144
|
+
// eslint-disable-next-line
|
|
145
|
+
}, [selectedWallet, connectToWallet]);
|
|
146
|
+
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
void attemptReconnect();
|
|
149
|
+
}, [attemptReconnect]);
|
|
150
|
+
|
|
151
|
+
const accountsChanged = useCallback(
|
|
152
|
+
async (accounts: string[]) => {
|
|
153
|
+
console.log('Accounts', accounts);
|
|
154
|
+
if (selectedWallet) {
|
|
155
|
+
const account = accounts.length > 0 ? accounts[0] : null;
|
|
156
|
+
setWalletAddress(account);
|
|
157
|
+
const publicKey = account ? await WalletController.getPublicKey() : null;
|
|
158
|
+
setPublicKey(publicKey);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
[selectedWallet, setWalletAddress, setPublicKey],
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const chainChanged = useCallback(
|
|
165
|
+
(network: WalletConnectNetwork): void => {
|
|
166
|
+
if (selectedWallet) {
|
|
167
|
+
setNetwork(network);
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
[selectedWallet, setNetwork],
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const allWallets = useMemo(() => {
|
|
174
|
+
//console.log("Refreshing all wallets");
|
|
175
|
+
return supportedWallets.map((wallet): WalletInformation => {
|
|
176
|
+
//console.log(" --> ", wallet.name, wallet.controller.isInstalled(), wallet.controller.isConnected());
|
|
177
|
+
return {
|
|
178
|
+
name: wallet.name,
|
|
179
|
+
icon: wallet.icon,
|
|
180
|
+
isInstalled: wallet.controller.isInstalled(),
|
|
181
|
+
isConnected: wallet.controller.isConnected(),
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
// eslint-disable-next-line
|
|
185
|
+
}, [supportedWallets, network]);
|
|
186
|
+
|
|
187
|
+
const availableWallets = useMemo(() => {
|
|
188
|
+
return supportedWallets.filter((wallet) => wallet.controller.isInstalled());
|
|
189
|
+
//return supportedWallets
|
|
190
|
+
// eslint-disable-next-line
|
|
191
|
+
}, [supportedWallets, network]);
|
|
192
|
+
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
const walletType = walletAddress ? WalletController.getWalletType() : null;
|
|
195
|
+
setWalletType(walletType);
|
|
196
|
+
const provider = walletAddress ? WalletController.getProvider() : null;
|
|
197
|
+
setProvider(provider);
|
|
198
|
+
}, [walletAddress]);
|
|
199
|
+
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
const updateSigner = async () => {
|
|
202
|
+
const signer = publicKey ? await WalletController.getSigner() : null;
|
|
203
|
+
setSigner(signer);
|
|
204
|
+
};
|
|
205
|
+
void updateSigner();
|
|
206
|
+
}, [network, publicKey]);
|
|
207
|
+
|
|
208
|
+
const currentTheme = useMemo(() => {
|
|
209
|
+
const currentTheme = theme || 'light';
|
|
210
|
+
return `wallet-connect-${currentTheme}-theme`;
|
|
211
|
+
}, [theme]);
|
|
212
|
+
|
|
213
|
+
const address = useMemo(() => {
|
|
214
|
+
return publicKey ? Address.fromString(publicKey) : null;
|
|
215
|
+
}, [publicKey]);
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<WalletConnectContext.Provider
|
|
219
|
+
value={{
|
|
220
|
+
walletAddress,
|
|
221
|
+
publicKey,
|
|
222
|
+
address,
|
|
223
|
+
connecting,
|
|
224
|
+
connectToWallet,
|
|
225
|
+
disconnect,
|
|
226
|
+
openConnectModal,
|
|
227
|
+
network,
|
|
228
|
+
allWallets,
|
|
229
|
+
provider,
|
|
230
|
+
signer,
|
|
231
|
+
walletType,
|
|
232
|
+
}}>
|
|
233
|
+
{children}
|
|
234
|
+
{modalOpen && (
|
|
235
|
+
<div className={`wallet-connect-modal-backdrop ${currentTheme}`}>
|
|
236
|
+
<div
|
|
237
|
+
className="wallet-connect-modal"
|
|
238
|
+
role="dialog"
|
|
239
|
+
aria-modal="true"
|
|
240
|
+
aria-labelledby="wallet-connect-modal-title">
|
|
241
|
+
<div className="wallet-connect-header">
|
|
242
|
+
<span>Connect Wallet</span>
|
|
243
|
+
<button
|
|
244
|
+
className="close"
|
|
245
|
+
onClick={() => closeConnectModal()}>
|
|
246
|
+
<span className="close-icon">
|
|
247
|
+
<svg
|
|
248
|
+
width="30px"
|
|
249
|
+
height="30px"
|
|
250
|
+
viewBox="0 0 24 24"
|
|
251
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
252
|
+
<path
|
|
253
|
+
className="close-x-path"
|
|
254
|
+
d="M16 8L8 16M8.00001 8L16 16"
|
|
255
|
+
stroke="#fff"
|
|
256
|
+
strokeWidth="1.5"
|
|
257
|
+
strokeLinecap="round"
|
|
258
|
+
strokeLinejoin="round"
|
|
259
|
+
/>
|
|
260
|
+
</svg>
|
|
261
|
+
</span>
|
|
262
|
+
</button>
|
|
263
|
+
</div>
|
|
264
|
+
{connectError && (
|
|
265
|
+
<div className="wallet-connect-error">
|
|
266
|
+
<p className="error-message">{connectError}</p>
|
|
267
|
+
</div>
|
|
268
|
+
)}
|
|
269
|
+
{availableWallets.length > 0 ? (
|
|
270
|
+
<div className="wallet-list">
|
|
271
|
+
{availableWallets.map((wallet) => (
|
|
272
|
+
<button
|
|
273
|
+
key={wallet.name}
|
|
274
|
+
onClick={() => connectToWallet(wallet.name)}
|
|
275
|
+
disabled={connecting || !wallet.controller.isInstalled()}
|
|
276
|
+
className={`wallet-button ${
|
|
277
|
+
wallet.controller.isInstalled()
|
|
278
|
+
? 'wallet-installed'
|
|
279
|
+
: 'wallet-not-installed'
|
|
280
|
+
}`}>
|
|
281
|
+
{wallet.icon ? (
|
|
282
|
+
<div
|
|
283
|
+
className="wallet-icon"
|
|
284
|
+
title={wallet.name}>
|
|
285
|
+
<img
|
|
286
|
+
src={wallet.icon}
|
|
287
|
+
alt={wallet.name}
|
|
288
|
+
/>
|
|
289
|
+
</div>
|
|
290
|
+
) : (
|
|
291
|
+
<div className="wallet-name">{wallet.name}</div>
|
|
292
|
+
)}
|
|
293
|
+
|
|
294
|
+
{wallet.controller.isConnected() ? (
|
|
295
|
+
<div className="wallet-connected">(Connected)</div>
|
|
296
|
+
) : (
|
|
297
|
+
<></>
|
|
298
|
+
)}
|
|
299
|
+
{wallet.controller.isInstalled() ? (
|
|
300
|
+
<></>
|
|
301
|
+
) : (
|
|
302
|
+
<div className="wallet-not-installed">
|
|
303
|
+
(Not Installed)
|
|
304
|
+
</div>
|
|
305
|
+
)}
|
|
306
|
+
</button>
|
|
307
|
+
))}
|
|
308
|
+
</div>
|
|
309
|
+
) : (
|
|
310
|
+
<div>
|
|
311
|
+
<p>No wallets available</p>
|
|
312
|
+
<p>Supporting the following wallets</p>
|
|
313
|
+
<div className="wallet-list">
|
|
314
|
+
{supportedWallets.map((wallet) => (
|
|
315
|
+
<a
|
|
316
|
+
href={`https://chromewebstore.google.com/search/${wallet.name}`}>
|
|
317
|
+
{wallet.icon ? (
|
|
318
|
+
<div
|
|
319
|
+
className="wallet-icon"
|
|
320
|
+
title={wallet.name}>
|
|
321
|
+
<img
|
|
322
|
+
src={wallet.icon}
|
|
323
|
+
alt={wallet.name}
|
|
324
|
+
/>
|
|
325
|
+
</div>
|
|
326
|
+
) : (
|
|
327
|
+
<div className="wallet-name">{wallet.name}</div>
|
|
328
|
+
)}
|
|
329
|
+
</a>
|
|
330
|
+
))}
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
)}
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
)}
|
|
337
|
+
</WalletConnectContext.Provider>
|
|
338
|
+
);
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export default WalletConnectProvider;
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Network } from '@btc-vision/bitcoin';
|
|
2
|
+
import { UnisatChainType } from '@btc-vision/transaction';
|
|
3
|
+
|
|
4
|
+
export interface WalletConnectNetwork extends Network {
|
|
5
|
+
chainType: UnisatChainType;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface WalletInformation {
|
|
9
|
+
name: string;
|
|
10
|
+
icon: string;
|
|
11
|
+
isInstalled: boolean;
|
|
12
|
+
isConnected: boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const genericErrors: Record<string, string> = {
|
|
2
|
+
UserRejected: 'Wallet Dialog was closed by the user',
|
|
3
|
+
UnknownError: 'Unknown error occurred',
|
|
4
|
+
IndexingInProgress: 'Node is still indexing. Please try again shortly',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const errorDefinitions: Record<string, string> = {
|
|
8
|
+
...genericErrors,
|
|
9
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ErrorTranslations } from './patterns';
|
|
2
|
+
import { patternMap, patternRegExp } from './patterns';
|
|
3
|
+
|
|
4
|
+
// Sample: Error in calling function: Spender can not be dead at ~lib/@btc-vision/btc-runtime/runtime/contracts/DeployableOP_20.ts:291:50
|
|
5
|
+
// matches[2] == null
|
|
6
|
+
// matches[3] == 'Spender can not be dead'
|
|
7
|
+
// Sample: Error in calling function: NATIVE_SWAP: LOCKED at ~lib/@btc-vision/btc-runtime/runtime/contracts/DeployableOP_20.ts:291:50
|
|
8
|
+
// matches[2] == 'NATIVE_SWAP'
|
|
9
|
+
// matches[3] == 'LOCKED'
|
|
10
|
+
const RE_EXTRACT_ERROR = new RegExp(
|
|
11
|
+
'^(.*?):\\s*(?:([^:]+):)?\\s*(.*?)\\s+at\\s(\\S+\\s\\()?\\S+\\d+:\\d+\\)?',
|
|
12
|
+
'm',
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const _translation = (err: ErrorTranslations, locale: string | null) => {
|
|
16
|
+
// Using a switch here to be sure we are safe as to not try to use
|
|
17
|
+
// a function or other attributes. For exemple if someone create
|
|
18
|
+
// a 'get' locale, we should not try to call err['get']...
|
|
19
|
+
switch (locale) {
|
|
20
|
+
case 'en':
|
|
21
|
+
return err['en'] || '';
|
|
22
|
+
case 'en-us':
|
|
23
|
+
return err['en-US'] || '';
|
|
24
|
+
case 'fr':
|
|
25
|
+
return err['fr'] || '';
|
|
26
|
+
case 'fr-ca':
|
|
27
|
+
return err['fr-CA'] || '';
|
|
28
|
+
default:
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const _errors = (err: string | ErrorTranslations, locales: string[]) => {
|
|
34
|
+
if (typeof err === 'string') {
|
|
35
|
+
return err;
|
|
36
|
+
} else {
|
|
37
|
+
for (const locale of locales) {
|
|
38
|
+
const translation = _translation(err, locale);
|
|
39
|
+
if (translation) return translation;
|
|
40
|
+
}
|
|
41
|
+
return err['en']; // Return default locale
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const _normalizeLocales = (locales: string[]) => {
|
|
46
|
+
const _locales = locales.map((l) => l.toLowerCase().trim());
|
|
47
|
+
// Add fallback locales if needed
|
|
48
|
+
for (const locale of _locales) {
|
|
49
|
+
const language = locale.split('-')[0];
|
|
50
|
+
if (!_locales.includes(language)) {
|
|
51
|
+
_locales.push(language);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return _locales;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// When translation will be enabled, will need to feed locale
|
|
58
|
+
// with the locale from the user's browser
|
|
59
|
+
export const _e = (err: string | Error, locales: string[] = ['en']): string => {
|
|
60
|
+
const [, , error] = _match_e(err.toString(), locales);
|
|
61
|
+
return error;
|
|
62
|
+
};
|
|
63
|
+
// This is mostly for debugging as it return the full matched information.
|
|
64
|
+
// returns [orig, pattern, translation] where
|
|
65
|
+
// - orig is the original key in the patterns definition
|
|
66
|
+
// - pattern is the transformed (lowercase, regex, etc.) key
|
|
67
|
+
// - translation is the resulting translation for the current key
|
|
68
|
+
export const _match_e = (err: string, locales: string[] = ['en']): string[] => {
|
|
69
|
+
const normalizedLocales = _normalizeLocales(locales);
|
|
70
|
+
const matches = RE_EXTRACT_ERROR.exec(err);
|
|
71
|
+
const packageName = matches ? matches[2] : '';
|
|
72
|
+
let msg = matches ? matches[3] : err;
|
|
73
|
+
|
|
74
|
+
const lookup = `${packageName}: ${msg}`.trim();
|
|
75
|
+
const lookupLower = lookup.toLowerCase();
|
|
76
|
+
|
|
77
|
+
// First checks with regex as these messages may be catched by includes later
|
|
78
|
+
for (const [orig, pattern, translation] of patternRegExp) {
|
|
79
|
+
const placeHolders = pattern.exec(lookup);
|
|
80
|
+
if (placeHolders) {
|
|
81
|
+
msg = _errors(translation, normalizedLocales) || msg;
|
|
82
|
+
for (let i = 0; i < placeHolders.length; i++) {
|
|
83
|
+
const regex = new RegExp(`\\$${i}`, 'g');
|
|
84
|
+
msg = msg.replace(regex, placeHolders[i] ?? '');
|
|
85
|
+
}
|
|
86
|
+
return [orig, pattern.source, msg];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Next checks fast patterns that are matched as lower case strings
|
|
91
|
+
for (const [orig, pattern, translation] of patternMap) {
|
|
92
|
+
if (lookupLower == pattern) {
|
|
93
|
+
return [orig, pattern, _errors(translation, normalizedLocales) || msg];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Finally checks fast patterns that are matched as lower case includes
|
|
98
|
+
for (const [orig, pattern, translation] of patternMap) {
|
|
99
|
+
if (lookupLower.includes(pattern)) {
|
|
100
|
+
return [orig, pattern, _errors(translation, normalizedLocales) || msg];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return ['', '', msg];
|
|
105
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { errorDefinitions } from './definitions';
|
|
2
|
+
|
|
3
|
+
export type ErrorTranslations = {
|
|
4
|
+
en: ErrorMessage; // Default language, required
|
|
5
|
+
'en-US'?: ErrorMessage;
|
|
6
|
+
fr?: ErrorMessage;
|
|
7
|
+
'fr-CA'?: ErrorMessage;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type ErrorMessage = (typeof errorDefinitions)[keyof typeof errorDefinitions];
|
|
11
|
+
type ErrorMessages = ErrorMessage | ErrorTranslations;
|
|
12
|
+
|
|
13
|
+
const rawPatternGeneric: Record<string, ErrorMessages> = {
|
|
14
|
+
'User rejected the request.': errorDefinitions.UserRejected,
|
|
15
|
+
"TypeError: Cannot read properties of undefined (reading 'addresses')":
|
|
16
|
+
errorDefinitions.UserRejected,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const rawPatternUnitTest: Record<string, ErrorMessages> = {
|
|
20
|
+
//'TEST_CASE: not there': ''
|
|
21
|
+
'TEST_CASE: empty': '',
|
|
22
|
+
'TEST_CASE: simple': 'simple',
|
|
23
|
+
'TEST_CASE: regex1 ${value}': 'regex1',
|
|
24
|
+
'TEST_CASE: regex2 ${value}': 'regex2 $1',
|
|
25
|
+
|
|
26
|
+
//'Test case not there': ''
|
|
27
|
+
'Test case empty': '',
|
|
28
|
+
'Test case simple': 'simple',
|
|
29
|
+
'Test case regex1 ${value}': 'regex1',
|
|
30
|
+
'Test case regex2 ${value.get()}': 'regex2 $1',
|
|
31
|
+
|
|
32
|
+
// Multi-language
|
|
33
|
+
'TEST_MULTI: multi1': {
|
|
34
|
+
en: 'Test English',
|
|
35
|
+
'en-US': 'Test American English',
|
|
36
|
+
fr: 'Test French',
|
|
37
|
+
'fr-CA': 'Test Canadian French',
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
'TEST_MULTI: multi2 ${value}': {
|
|
41
|
+
en: 'Test English: $1',
|
|
42
|
+
'en-US': 'Test American English: $1',
|
|
43
|
+
fr: 'Test French: $1',
|
|
44
|
+
'fr-CA': 'Test Canadian French: $1',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Patterns may be
|
|
49
|
+
// - simple string (if key don't contain a closing parenthesis '(' ).
|
|
50
|
+
// - regex expression (if key contains at least one '(' for regex group matching).
|
|
51
|
+
// The group matching don't need to be used in translation
|
|
52
|
+
// Group matching start at $0 (full match) and $1 (first group), $2...
|
|
53
|
+
//
|
|
54
|
+
// Simple key
|
|
55
|
+
// 'Test': 'This is a translated test',
|
|
56
|
+
// Regex key
|
|
57
|
+
// 'Test for (\\w+)': 'This is a test for some function',
|
|
58
|
+
// 'Test function (\\w+)': 'This is a testing sample for function $1',
|
|
59
|
+
const rawPatternMap: Record<string, ErrorMessage> = {
|
|
60
|
+
'NATIVE_SWAP: Liquidity value is too low in satoshis.':
|
|
61
|
+
errorDefinitions.NativeSwapLiquidityValueTooLow,
|
|
62
|
+
'Unknown Error': errorDefinitions.UnknownError,
|
|
63
|
+
'Invalid Address': errorDefinitions.IndexingInProgress,
|
|
64
|
+
'Error Indexing at Block': errorDefinitions.IndexingInProgress,
|
|
65
|
+
'Valid Reservation for this Address': errorDefinitions.NoValidReservation,
|
|
66
|
+
|
|
67
|
+
...rawPatternGeneric,
|
|
68
|
+
...rawPatternUnitTest,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const patternMap: Array<[string, string, ErrorMessages]> = Object.entries(rawPatternMap)
|
|
72
|
+
.filter(([key, value]) => !!value && !key.includes('${'))
|
|
73
|
+
.sort((a, b) => b[0].length - a[0].length)
|
|
74
|
+
.map(([key, value]) => [key, key.toLowerCase(), value]);
|
|
75
|
+
|
|
76
|
+
export const escapeKey = (key: string): string => {
|
|
77
|
+
return key
|
|
78
|
+
.replace(/\(/g, '\\(')
|
|
79
|
+
.replace(/\)/g, '\\)')
|
|
80
|
+
.replace(/\./g, '\\.')
|
|
81
|
+
.replace(/\$\{.*?}/g, '(.+)');
|
|
82
|
+
};
|
|
83
|
+
export const patternRegExp: Array<[string, RegExp, ErrorMessages]> = Object.entries(rawPatternMap)
|
|
84
|
+
.filter(([key, value]) => !!value && key.includes('${'))
|
|
85
|
+
.sort((a, b) => b[0].length - a[0].length)
|
|
86
|
+
.map(([key, value]) => [key, new RegExp(escapeKey(key), 'i'), value]);
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
.wallet-connect-modal-backdrop {
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
background-color: rgba(10, 11, 13, 0.5);
|
|
8
|
+
backdrop-filter: blur(10px);
|
|
9
|
+
z-index: 9999;
|
|
10
|
+
display: flex;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
align-items: center;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.wallet-connect-modal {
|
|
16
|
+
background-color: var(--background-color);
|
|
17
|
+
border: 1px solid var(--border-color);
|
|
18
|
+
color: var(--primaryColor);
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
21
|
+
width: 400px;
|
|
22
|
+
max-width: 90%;
|
|
23
|
+
z-index: 10000;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.wallet-connect-header {
|
|
27
|
+
padding: 16px;
|
|
28
|
+
border-bottom: 1px solid var(--border-color);
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: space-between;
|
|
32
|
+
font-size: 14px;
|
|
33
|
+
font-weight: bold;
|
|
34
|
+
user-select: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.wallet-connect-header > button.close {
|
|
38
|
+
width: 30px;
|
|
39
|
+
height: 30px;
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
justify-content: center;
|
|
43
|
+
color: var(--primaryColor);
|
|
44
|
+
fill: var(--primaryColor);
|
|
45
|
+
background-color: var(--background-color);
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
}
|
|
48
|
+
.wallet-connect-header > button.close:hover {
|
|
49
|
+
border: 1px solid rgba(254, 121, 1, 0.3);
|
|
50
|
+
background-color: rgba(254, 121, 1, 0.1);
|
|
51
|
+
}
|
|
52
|
+
.wallet-connect-header > button.close svg {
|
|
53
|
+
display: flex;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.wallet-connect-header > button.close .close-x-path {
|
|
57
|
+
stroke: var(--primaryColor);
|
|
58
|
+
transition: stroke 0.2s ease;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.wallet-connect-header > button.close:hover .close-x-path {
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.wallet-list {
|
|
65
|
+
max-height: 400px;
|
|
66
|
+
overflow-y: auto;
|
|
67
|
+
padding: 16px;
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
gap: 10px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.wallet-list > button {
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: 12px;
|
|
77
|
+
height: 64px;
|
|
78
|
+
justify-content: space-between;
|
|
79
|
+
padding: 12px;
|
|
80
|
+
color: #fff;
|
|
81
|
+
width: 100%;
|
|
82
|
+
text-align: left;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
border-radius: 10px;
|
|
85
|
+
border: 1px solid var(--border-color);
|
|
86
|
+
background-color: var(--button-background-color);
|
|
87
|
+
}
|
|
88
|
+
.wallet-list > button:disabled {
|
|
89
|
+
opacity: 0.3;
|
|
90
|
+
cursor: not-allowed;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.wallet-list > button:hover {
|
|
94
|
+
border: 1px solid rgba(254, 121, 1, 0.3);
|
|
95
|
+
background-color: rgba(254, 121, 1, 0.1);
|
|
96
|
+
}
|
|
97
|
+
.wallet-icon {
|
|
98
|
+
display: flex;
|
|
99
|
+
}
|
|
100
|
+
.wallet-icon img {
|
|
101
|
+
max-height: 32px;
|
|
102
|
+
filter: var(--icon-filter);
|
|
103
|
+
}
|
|
104
|
+
.wallet-name {
|
|
105
|
+
font-size: x-large;
|
|
106
|
+
text-align: left;
|
|
107
|
+
}
|
|
108
|
+
.wallet-connected {
|
|
109
|
+
padding: 10px;
|
|
110
|
+
font-size: medium;
|
|
111
|
+
color: green;
|
|
112
|
+
}
|
|
113
|
+
div.wallet-not-installed {
|
|
114
|
+
padding: 10px;
|
|
115
|
+
font-size: medium;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.wallet-connect-error {
|
|
119
|
+
padding: 16px 16px 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.wallet-connect-error > p {
|
|
123
|
+
color: #ff4d4d;
|
|
124
|
+
text-align: center;
|
|
125
|
+
background-color: rgba(255, 77, 77, 0.1);
|
|
126
|
+
font-size: 14px;
|
|
127
|
+
font-weight: bolder;
|
|
128
|
+
padding: 20px 10px;
|
|
129
|
+
border-radius: 10px;
|
|
130
|
+
border: 1px solid #ff4d4d;
|
|
131
|
+
}
|