@rango-dev/wallets-react 0.0.0-experimental-936229e8-20251208
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 +265 -0
- package/dist/helpers/index.d.ts +2 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +2 -0
- package/dist/helpers/index.js.map +7 -0
- package/dist/hub/autoConnect.d.ts +11 -0
- package/dist/hub/autoConnect.d.ts.map +1 -0
- package/dist/hub/constants.d.ts +3 -0
- package/dist/hub/constants.d.ts.map +1 -0
- package/dist/hub/helpers.d.ts +33 -0
- package/dist/hub/helpers.d.ts.map +1 -0
- package/dist/hub/lastConnectedWallets.d.ts +22 -0
- package/dist/hub/lastConnectedWallets.d.ts.map +1 -0
- package/dist/hub/mod.d.ts +3 -0
- package/dist/hub/mod.d.ts.map +1 -0
- package/dist/hub/types.d.ts +4 -0
- package/dist/hub/types.d.ts.map +1 -0
- package/dist/hub/useHubAdapter.d.ts +11 -0
- package/dist/hub/useHubAdapter.d.ts.map +1 -0
- package/dist/hub/useHubRefs.d.ts +7 -0
- package/dist/hub/useHubRefs.d.ts.map +1 -0
- package/dist/hub/utils.d.ts +52 -0
- package/dist/hub/utils.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +7 -0
- package/dist/legacy/autoConnect.d.ts +8 -0
- package/dist/legacy/autoConnect.d.ts.map +1 -0
- package/dist/legacy/context.d.ts +3 -0
- package/dist/legacy/context.d.ts.map +1 -0
- package/dist/legacy/helpers.d.ts +23 -0
- package/dist/legacy/helpers.d.ts.map +1 -0
- package/dist/legacy/hooks.d.ts +10 -0
- package/dist/legacy/hooks.d.ts.map +1 -0
- package/dist/legacy/mod.d.ts +5 -0
- package/dist/legacy/mod.d.ts.map +1 -0
- package/dist/legacy/types.d.ts +143 -0
- package/dist/legacy/types.d.ts.map +1 -0
- package/dist/legacy/useAutoConnect.d.ts +8 -0
- package/dist/legacy/useAutoConnect.d.ts.map +1 -0
- package/dist/legacy/useLegacyProviders.d.ts +7 -0
- package/dist/legacy/useLegacyProviders.d.ts.map +1 -0
- package/dist/legacy/utils.d.ts +3 -0
- package/dist/legacy/utils.d.ts.map +1 -0
- package/dist/provider.d.ts +5 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/test-utils/env.d.ts +7 -0
- package/dist/test-utils/env.d.ts.map +1 -0
- package/dist/test-utils/fixtures.d.ts +14 -0
- package/dist/test-utils/fixtures.d.ts.map +1 -0
- package/dist/useProviders.d.ts +4 -0
- package/dist/useProviders.d.ts.map +1 -0
- package/dist/wallets-react.build.json +1 -0
- package/helpers/package.json +8 -0
- package/package.json +50 -0
- package/readme.md +3 -0
- package/src/helpers/index.ts +1 -0
- package/src/hub/autoConnect.ts +276 -0
- package/src/hub/constants.ts +2 -0
- package/src/hub/helpers.ts +179 -0
- package/src/hub/lastConnectedWallets.ts +166 -0
- package/src/hub/mod.ts +6 -0
- package/src/hub/types.ts +12 -0
- package/src/hub/useHubAdapter.ts +516 -0
- package/src/hub/useHubRefs.ts +50 -0
- package/src/hub/utils.ts +393 -0
- package/src/index.ts +4 -0
- package/src/legacy/autoConnect.ts +66 -0
- package/src/legacy/context.ts +39 -0
- package/src/legacy/helpers.ts +183 -0
- package/src/legacy/hooks.ts +54 -0
- package/src/legacy/mod.ts +13 -0
- package/src/legacy/types.ts +195 -0
- package/src/legacy/useAutoConnect.ts +23 -0
- package/src/legacy/useLegacyProviders.ts +241 -0
- package/src/legacy/utils.ts +7 -0
- package/src/provider.tsx +18 -0
- package/src/test-utils/env.ts +10 -0
- package/src/test-utils/fixtures.ts +238 -0
- package/src/useProviders.ts +120 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import type { AllProxiedNamespaces, ExtensionLink } from './types.js';
|
|
2
|
+
import type { ProviderContext } from '../index.js';
|
|
3
|
+
import type { Provider } from '@rango-dev/wallets-core';
|
|
4
|
+
import type { LegacyNamespaceInputForConnect } from '@rango-dev/wallets-core/legacy';
|
|
5
|
+
import type {
|
|
6
|
+
Accounts,
|
|
7
|
+
AccountsWithActiveChain,
|
|
8
|
+
} from '@rango-dev/wallets-core/namespaces/common';
|
|
9
|
+
import type { VersionedProviders } from '@rango-dev/wallets-core/utils';
|
|
10
|
+
|
|
11
|
+
import { utils } from '@rango-dev/wallets-core/namespaces/evm';
|
|
12
|
+
import { type WalletInfo, type WalletType } from '@rango-dev/wallets-shared';
|
|
13
|
+
import { cosmosBlockchains } from 'rango-types';
|
|
14
|
+
import { useEffect, useRef, useState } from 'react';
|
|
15
|
+
import { Ok, Result } from 'ts-results';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
type ConnectResult,
|
|
19
|
+
HUB_LAST_CONNECTED_WALLETS,
|
|
20
|
+
type ProviderProps,
|
|
21
|
+
} from '../legacy/mod.js';
|
|
22
|
+
import { useAutoConnect } from '../legacy/useAutoConnect.js';
|
|
23
|
+
|
|
24
|
+
import { autoConnect } from './autoConnect.js';
|
|
25
|
+
import { createQueue, fromAccountIdToLegacyAddressFormat } from './helpers.js';
|
|
26
|
+
import { LastConnectedWalletsFromStorage } from './lastConnectedWallets.js';
|
|
27
|
+
import { useHubRefs } from './useHubRefs.js';
|
|
28
|
+
import {
|
|
29
|
+
getSupportedChainsFromProvider,
|
|
30
|
+
isCosmosNamespace,
|
|
31
|
+
isEvmNamespace,
|
|
32
|
+
isSolanaNamespace,
|
|
33
|
+
mapHubEventsToLegacy,
|
|
34
|
+
transformHubResultToLegacyResult,
|
|
35
|
+
tryConvertNamespaceNetworkToChainInfo,
|
|
36
|
+
} from './utils.js';
|
|
37
|
+
|
|
38
|
+
export type UseAdapterParams = Omit<ProviderProps, 'providers'> & {
|
|
39
|
+
providers: Provider[];
|
|
40
|
+
/** This is only will be used to access some parts of the legacy provider that doesn't exists in Hub. */
|
|
41
|
+
allVersionedProviders: VersionedProviders[];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export function useHubAdapter(params: UseAdapterParams): ProviderContext {
|
|
45
|
+
const { getStore, getHub } = useHubRefs(params.providers);
|
|
46
|
+
const [, rerender] = useState(0);
|
|
47
|
+
// useEffect will run `subscribe` once, so we need a reference and mutate the value if it's changes.
|
|
48
|
+
const dataRef = useRef({
|
|
49
|
+
onUpdateState: params.onUpdateState,
|
|
50
|
+
allVersionedProviders: params.allVersionedProviders,
|
|
51
|
+
allBlockChains: params.allBlockChains,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* Params of each connection attempt for each wallet type are stored here.
|
|
56
|
+
* Derivation path from params is used in `mapHubEventsToLegacy` to be added to the payload of connect events.
|
|
57
|
+
*/
|
|
58
|
+
const lastConnectAttemptParamsRef = useRef<{
|
|
59
|
+
[type: WalletType]: LegacyNamespaceInputForConnect[];
|
|
60
|
+
}>({});
|
|
61
|
+
|
|
62
|
+
const updateLastConnectAttemptParams = (
|
|
63
|
+
type: WalletType,
|
|
64
|
+
namespaces: LegacyNamespaceInputForConnect[] | undefined
|
|
65
|
+
) => {
|
|
66
|
+
lastConnectAttemptParamsRef.current[type] = namespaces || [];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const queueTask = createQueue({
|
|
70
|
+
onError: (error, actions) => {
|
|
71
|
+
if (utils.isUserRejectionError(error)) {
|
|
72
|
+
actions.removeCurrentKeyFromQueue();
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
dataRef.current = {
|
|
79
|
+
onUpdateState: params.onUpdateState,
|
|
80
|
+
allVersionedProviders: params.allVersionedProviders,
|
|
81
|
+
allBlockChains: params.allBlockChains,
|
|
82
|
+
};
|
|
83
|
+
}, [params]);
|
|
84
|
+
|
|
85
|
+
// Initialize instances
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const runOnInit = () => {
|
|
88
|
+
getHub().init();
|
|
89
|
+
|
|
90
|
+
rerender((currentRender) => currentRender + 1);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Then will call init whenever page is ready.
|
|
94
|
+
const initHubWhenPageIsReady = (event: Event) => {
|
|
95
|
+
// Then will call init whenever page is ready.
|
|
96
|
+
if (
|
|
97
|
+
event.target &&
|
|
98
|
+
(event.target as Document).readyState === 'complete'
|
|
99
|
+
) {
|
|
100
|
+
runOnInit();
|
|
101
|
+
document.removeEventListener(
|
|
102
|
+
'readystatechange',
|
|
103
|
+
initHubWhenPageIsReady
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Try to run, maybe it's ready.
|
|
109
|
+
runOnInit();
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* Try again when the page has been completely loaded.
|
|
113
|
+
* Some of wallets, take some time to be fully injected and loaded.
|
|
114
|
+
*/
|
|
115
|
+
document.addEventListener('readystatechange', initHubWhenPageIsReady);
|
|
116
|
+
|
|
117
|
+
getStore()
|
|
118
|
+
.subscribe((event) => {
|
|
119
|
+
if (dataRef.current.onUpdateState) {
|
|
120
|
+
try {
|
|
121
|
+
mapHubEventsToLegacy(
|
|
122
|
+
getHub(),
|
|
123
|
+
event,
|
|
124
|
+
dataRef.current.onUpdateState,
|
|
125
|
+
{
|
|
126
|
+
allBlockChains: dataRef.current.allBlockChains,
|
|
127
|
+
lastConnectAttemptParams: lastConnectAttemptParamsRef.current,
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
console.error(e);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
rerender((currentRender) => currentRender + 1);
|
|
135
|
+
})
|
|
136
|
+
.flushEvents();
|
|
137
|
+
}, []);
|
|
138
|
+
|
|
139
|
+
useAutoConnect({
|
|
140
|
+
autoConnect: params.autoConnect,
|
|
141
|
+
allBlockChains: params.allBlockChains,
|
|
142
|
+
autoConnectHandler: () => {
|
|
143
|
+
void autoConnect({
|
|
144
|
+
allBlockChains: params.allBlockChains,
|
|
145
|
+
getHub,
|
|
146
|
+
wallets: params.configs?.wallets,
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const lastConnectedWalletsFromStorage = new LastConnectedWalletsFromStorage(
|
|
152
|
+
HUB_LAST_CONNECTED_WALLETS
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const api: ProviderContext = {
|
|
156
|
+
canSwitchNetworkTo(type, network, namespace) {
|
|
157
|
+
const provider = getHub().get(type);
|
|
158
|
+
|
|
159
|
+
if (!provider) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`You should add ${type} to provider first then call 'canSwitchNetworkTo'.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!namespace) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
'Passing namespace to `canSwitchNetworkTo` is required.'
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const proxiedNamespace = provider.findByNamespace(namespace.namespace);
|
|
172
|
+
if (!proxiedNamespace) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`We couldn't find any matched namespace on your request provider. (requested namespace: ${namespace.namespace})`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
if (!('canSwitchNetwork' in proxiedNamespace)) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
const namespacesProperty = provider
|
|
181
|
+
.info()
|
|
182
|
+
?.metadata?.properties?.find(
|
|
183
|
+
(property) => property.name === 'namespaces'
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (!dataRef.current.allBlockChains) {
|
|
187
|
+
throw new Error(`Blockchains are not available`);
|
|
188
|
+
}
|
|
189
|
+
const providerSupportedChainsOfNamespace = namespacesProperty?.value.data
|
|
190
|
+
.find(
|
|
191
|
+
(providerNamespace) => providerNamespace.value === namespace.namespace
|
|
192
|
+
)
|
|
193
|
+
?.getSupportedChains(dataRef.current.allBlockChains);
|
|
194
|
+
|
|
195
|
+
if (!providerSupportedChainsOfNamespace) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`NamespaceMeta is not defined for requested namespace: ${namespace.namespace}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return proxiedNamespace.canSwitchNetwork({
|
|
202
|
+
network,
|
|
203
|
+
supportedChains: providerSupportedChainsOfNamespace,
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
async connect(type, namespaces) {
|
|
207
|
+
const wallet = getHub().get(type);
|
|
208
|
+
if (!wallet) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`You should add ${type} to provider first then call 'connect'.`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (!namespaces) {
|
|
215
|
+
throw new Error('Passing namespace to `connect` is required.');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
updateLastConnectAttemptParams(type, namespaces);
|
|
219
|
+
|
|
220
|
+
// Check `namespace` and look into hub to see how it can match given namespace to hub namespace.
|
|
221
|
+
const targetNamespaces: [
|
|
222
|
+
LegacyNamespaceInputForConnect,
|
|
223
|
+
AllProxiedNamespaces
|
|
224
|
+
][] = [];
|
|
225
|
+
namespaces.forEach((namespace) => {
|
|
226
|
+
const targetNamespace = namespace.namespace;
|
|
227
|
+
|
|
228
|
+
const result = wallet.findByNamespace(targetNamespace);
|
|
229
|
+
if (!result) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`We couldn't find any provider matched with your request namespace. (requested namespace: ${namespace.namespace})`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
targetNamespaces.push([namespace, result]);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Try to run `connect` on matched namespaces
|
|
239
|
+
const connectResultFromTargetNamespaces = targetNamespaces.map(
|
|
240
|
+
async ([namespaceInput, namespace]) => {
|
|
241
|
+
const network = tryConvertNamespaceNetworkToChainInfo(
|
|
242
|
+
namespaceInput,
|
|
243
|
+
params.allBlockChains || []
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
let connectNamespacePromise: () => Promise<
|
|
247
|
+
Accounts | AccountsWithActiveChain
|
|
248
|
+
>;
|
|
249
|
+
|
|
250
|
+
if (isSolanaNamespace(namespace)) {
|
|
251
|
+
connectNamespacePromise = async () =>
|
|
252
|
+
namespace.connect({
|
|
253
|
+
derivationPath: namespaceInput.derivationPath,
|
|
254
|
+
});
|
|
255
|
+
} else if (isEvmNamespace(namespace)) {
|
|
256
|
+
connectNamespacePromise = async () =>
|
|
257
|
+
namespace.connect(network, {
|
|
258
|
+
derivationPath: namespaceInput.derivationPath,
|
|
259
|
+
});
|
|
260
|
+
} else if (isCosmosNamespace(namespace)) {
|
|
261
|
+
const cosmosBlockChains = cosmosBlockchains(
|
|
262
|
+
params.allBlockChains || []
|
|
263
|
+
).filter((chain) => !!chain.chainId);
|
|
264
|
+
connectNamespacePromise = async () => {
|
|
265
|
+
return namespace.connect({
|
|
266
|
+
chainIds: cosmosBlockChains
|
|
267
|
+
.filter((chain) => chain.info && !chain.info.experimental)
|
|
268
|
+
?.map((chain) => chain.chainId!),
|
|
269
|
+
customChainIds: cosmosBlockChains
|
|
270
|
+
.filter((chain) => chain.info?.experimental)
|
|
271
|
+
.map((chain) => chain.chainId!),
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
} else {
|
|
275
|
+
connectNamespacePromise = async () => namespace.connect();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const connectNamespaceProcess = async () =>
|
|
279
|
+
connectNamespacePromise()
|
|
280
|
+
.then<ConnectResult>(transformHubResultToLegacyResult)
|
|
281
|
+
.then((connectResult) => {
|
|
282
|
+
return {
|
|
283
|
+
response: connectResult,
|
|
284
|
+
input: {
|
|
285
|
+
namespace: namespaceInput.namespace,
|
|
286
|
+
network: namespaceInput.network,
|
|
287
|
+
supportsEagerConnect: 'canEagerConnect' in namespace,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
return queueTask(connectNamespaceProcess, type);
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
/*
|
|
296
|
+
* We need to connect to namespace one after another, sending multiple requests at the same time may be failed.
|
|
297
|
+
* e.g. when wallet popup opens and asking for the password from the user, it should be resolved first, then other request will be resolved.
|
|
298
|
+
*/
|
|
299
|
+
const connectResultWithLegacyFormat = await Promise.all(
|
|
300
|
+
connectResultFromTargetNamespaces
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
// Keeping only namespaces that connected successfully and support eager connect, then we'll store them on storage for auto connect functionality.
|
|
304
|
+
const successfullyConnectedSupportingEagerConnectNamespaces =
|
|
305
|
+
connectResultWithLegacyFormat
|
|
306
|
+
.filter(<T, E>(result: Result<T, E>): result is Ok<T> => result.ok)
|
|
307
|
+
.filter((result) => result.val.input.supportsEagerConnect)
|
|
308
|
+
.map((result) => ({
|
|
309
|
+
namespace: result.val.input.namespace,
|
|
310
|
+
network: result.val.input.network,
|
|
311
|
+
}));
|
|
312
|
+
|
|
313
|
+
if (successfullyConnectedSupportingEagerConnectNamespaces.length > 0) {
|
|
314
|
+
lastConnectedWalletsFromStorage.addWallet(
|
|
315
|
+
type,
|
|
316
|
+
successfullyConnectedSupportingEagerConnectNamespaces
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Getting rid of `input` from Result
|
|
321
|
+
const connectResults = connectResultWithLegacyFormat.map((result) =>
|
|
322
|
+
result.andThen((okResult) => new Ok(okResult.response))
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
const allResult = Result.all(...connectResults);
|
|
326
|
+
if (allResult.err) {
|
|
327
|
+
throw allResult.val;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return allResult.unwrap();
|
|
331
|
+
},
|
|
332
|
+
async disconnect(type, namespaces) {
|
|
333
|
+
const wallet = getHub().get(type);
|
|
334
|
+
if (!wallet) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
`You should add ${type} to provider first then call 'disconnect'.`
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
wallet.getAll().forEach((namespace) => {
|
|
341
|
+
const namespaceShouldBeDisconnected =
|
|
342
|
+
!namespaces || namespaces.includes(namespace.namespaceId);
|
|
343
|
+
const namespaceIsConnected = namespace.state()[0]().connected;
|
|
344
|
+
if (namespaceShouldBeDisconnected && namespaceIsConnected) {
|
|
345
|
+
return namespace.disconnect();
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
if (params.autoConnect) {
|
|
350
|
+
if (namespaces) {
|
|
351
|
+
lastConnectedWalletsFromStorage.removeNamespacesFromWallet(
|
|
352
|
+
type,
|
|
353
|
+
namespaces
|
|
354
|
+
);
|
|
355
|
+
} else {
|
|
356
|
+
lastConnectedWalletsFromStorage.removeWallets([type]);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
async disconnectAll() {
|
|
361
|
+
const disconnectPromises: Promise<void>[] = Array.from(
|
|
362
|
+
getHub().getAll().values()
|
|
363
|
+
).map(async (provider) => this.disconnect(provider.id));
|
|
364
|
+
|
|
365
|
+
return await Promise.allSettled(disconnectPromises);
|
|
366
|
+
},
|
|
367
|
+
async getSigners(type) {
|
|
368
|
+
const wallet = getHub().get(type);
|
|
369
|
+
if (!wallet) {
|
|
370
|
+
throw new Error(`You should add ${type} to provider first.`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const info = wallet.info();
|
|
374
|
+
if (!info) {
|
|
375
|
+
throw new Error('Your provider should have required `info`.');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const providerProperties = info.metadata.properties;
|
|
379
|
+
|
|
380
|
+
const signerProperty = providerProperties?.find(
|
|
381
|
+
(property) => property.name === 'signers'
|
|
382
|
+
);
|
|
383
|
+
if (!signerProperty) {
|
|
384
|
+
throw new Error('Your provider should contain signers property.');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return signerProperty.value.getSigners();
|
|
388
|
+
},
|
|
389
|
+
getWalletInfo(type) {
|
|
390
|
+
const wallet = getHub().get(type);
|
|
391
|
+
if (!wallet) {
|
|
392
|
+
throw new Error(`You should add ${type} to provider first.`);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const info = wallet.info();
|
|
396
|
+
if (!info) {
|
|
397
|
+
throw new Error('Your provider should have required `info`.');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const installLink: Exclude<WalletInfo['installLink'], string> = {
|
|
401
|
+
DEFAULT: '',
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
const { metadata } = info;
|
|
405
|
+
const { extensions } = metadata;
|
|
406
|
+
// `extensions` in legacy format was uppercase and also `DEFAULT` was used instead of `homepage`
|
|
407
|
+
Object.keys(extensions).forEach((k) => {
|
|
408
|
+
const key = k as ExtensionLink;
|
|
409
|
+
|
|
410
|
+
if (key === 'homepage') {
|
|
411
|
+
installLink.DEFAULT = extensions[key] || '';
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const allowedKeys: ExtensionLink[] = [
|
|
415
|
+
'firefox',
|
|
416
|
+
'chrome',
|
|
417
|
+
'brave',
|
|
418
|
+
'edge',
|
|
419
|
+
];
|
|
420
|
+
if (allowedKeys.includes(key)) {
|
|
421
|
+
const upperCasedKey = key.toUpperCase() as keyof Exclude<
|
|
422
|
+
WalletInfo['installLink'],
|
|
423
|
+
string
|
|
424
|
+
>;
|
|
425
|
+
installLink[upperCasedKey] = extensions[key] || '';
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
const providerProperties = metadata.properties;
|
|
430
|
+
|
|
431
|
+
const namespacesProperty = providerProperties?.find(
|
|
432
|
+
(property) => property.name === 'namespaces'
|
|
433
|
+
);
|
|
434
|
+
const derivationPathProperty = providerProperties?.find(
|
|
435
|
+
(property) => property.name === 'derivationPath'
|
|
436
|
+
);
|
|
437
|
+
const detailsProperty = providerProperties?.find(
|
|
438
|
+
(property) => property.name === 'details'
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
return {
|
|
442
|
+
name: metadata.name,
|
|
443
|
+
img: metadata.icon,
|
|
444
|
+
installLink: installLink,
|
|
445
|
+
// We don't have this values anymore, fill them with some values that communicate this.
|
|
446
|
+
color: 'red',
|
|
447
|
+
supportedChains: getSupportedChainsFromProvider(
|
|
448
|
+
wallet,
|
|
449
|
+
dataRef.current.allBlockChains
|
|
450
|
+
),
|
|
451
|
+
isContractWallet: detailsProperty?.value?.isContractWallet,
|
|
452
|
+
mobileWallet: detailsProperty?.value?.mobileWallet,
|
|
453
|
+
// if set to false here, it will not show the wallet in mobile in anyways. to be compatible with old behavior, undefined is more appropirate.
|
|
454
|
+
showOnMobile: detailsProperty?.value?.showOnMobile,
|
|
455
|
+
needsNamespace: namespacesProperty?.value,
|
|
456
|
+
needsDerivationPath: derivationPathProperty?.value,
|
|
457
|
+
isHub: true,
|
|
458
|
+
properties: metadata.properties,
|
|
459
|
+
};
|
|
460
|
+
},
|
|
461
|
+
providers() {
|
|
462
|
+
throw new Error('This method is not available on hub providers.');
|
|
463
|
+
},
|
|
464
|
+
state(type) {
|
|
465
|
+
const hubState = getHub().state();
|
|
466
|
+
const wallet = getHub().get(type);
|
|
467
|
+
const walletState = hubState[type];
|
|
468
|
+
|
|
469
|
+
if (!walletState || !wallet) {
|
|
470
|
+
throw new Error(
|
|
471
|
+
`It seems your requested provider doesn't exist in hub. Provider Id: ${type}`
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const accounts = walletState.namespaces
|
|
476
|
+
.filter((namespace) => namespace.connected)
|
|
477
|
+
.flatMap((namespace) =>
|
|
478
|
+
namespace.accounts?.map((accounts) =>
|
|
479
|
+
fromAccountIdToLegacyAddressFormat(
|
|
480
|
+
accounts,
|
|
481
|
+
params.allBlockChains || []
|
|
482
|
+
)
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
.filter((account): account is string => !!account);
|
|
486
|
+
|
|
487
|
+
const namespacesState = new Map(
|
|
488
|
+
Array.from(wallet.getAll(), ([_, value]) => [
|
|
489
|
+
value.namespaceId,
|
|
490
|
+
value.state()[0](),
|
|
491
|
+
])
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
const coreState = {
|
|
495
|
+
connected: walletState.connected,
|
|
496
|
+
connecting: walletState.connecting,
|
|
497
|
+
installed: walletState.installed,
|
|
498
|
+
reachable: true,
|
|
499
|
+
accounts: accounts,
|
|
500
|
+
network: null,
|
|
501
|
+
namespaces: namespacesState,
|
|
502
|
+
};
|
|
503
|
+
return coreState;
|
|
504
|
+
},
|
|
505
|
+
suggestAndConnect(_type, _network): never {
|
|
506
|
+
throw new Error('`suggestAndConnect` is not implemented');
|
|
507
|
+
},
|
|
508
|
+
hubProvider() {
|
|
509
|
+
throw new Error(
|
|
510
|
+
'Unreachable code. the method has been implemented in main adapter instance.'
|
|
511
|
+
);
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
return api;
|
|
516
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Provider, Store } from '@rango-dev/wallets-core';
|
|
2
|
+
|
|
3
|
+
import { createStore, Hub } from '@rango-dev/wallets-core';
|
|
4
|
+
import { useRef } from 'react';
|
|
5
|
+
|
|
6
|
+
import { synchronizeHubWithConfigProviders } from './utils.js';
|
|
7
|
+
|
|
8
|
+
export function useHubRefs(providers: Provider[]) {
|
|
9
|
+
const store = useRef<Store | null>(null);
|
|
10
|
+
|
|
11
|
+
const hub = useRef<Hub | null>(null);
|
|
12
|
+
|
|
13
|
+
function createHub() {
|
|
14
|
+
const createdHub = new Hub({
|
|
15
|
+
store: getStore(),
|
|
16
|
+
});
|
|
17
|
+
/*
|
|
18
|
+
* First add providers to hub
|
|
19
|
+
* This helps to `getWalletInfo` be usable, before initialize.
|
|
20
|
+
*/
|
|
21
|
+
providers.forEach((provider) => {
|
|
22
|
+
createdHub.add(provider.id, provider);
|
|
23
|
+
});
|
|
24
|
+
hub.current = createdHub;
|
|
25
|
+
return createdHub;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// https://react.dev/reference/react/useRef#avoiding-recreating-the-ref-contents
|
|
29
|
+
function getStore() {
|
|
30
|
+
if (store.current !== null) {
|
|
31
|
+
return store.current;
|
|
32
|
+
}
|
|
33
|
+
const createdStore = createStore();
|
|
34
|
+
store.current = createdStore;
|
|
35
|
+
return createdStore;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getHub(): Hub {
|
|
39
|
+
const hubProviders = hub.current?.getAll();
|
|
40
|
+
|
|
41
|
+
if (!hub.current || !hubProviders) {
|
|
42
|
+
return createHub();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
synchronizeHubWithConfigProviders(hub.current, providers);
|
|
46
|
+
return hub.current;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { getStore, getHub };
|
|
50
|
+
}
|