@reown/appkit-wagmi-react-native 0.0.0-canary-20240912195440

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.
Files changed (37) hide show
  1. package/lib/commonjs/client.js +397 -0
  2. package/lib/commonjs/client.js.map +1 -0
  3. package/lib/commonjs/connectors/WalletConnectConnector.js +353 -0
  4. package/lib/commonjs/connectors/WalletConnectConnector.js.map +1 -0
  5. package/lib/commonjs/index.js +126 -0
  6. package/lib/commonjs/index.js.map +1 -0
  7. package/lib/commonjs/utils/defaultWagmiConfig.js +46 -0
  8. package/lib/commonjs/utils/defaultWagmiConfig.js.map +1 -0
  9. package/lib/commonjs/utils/helpers.js +52 -0
  10. package/lib/commonjs/utils/helpers.js.map +1 -0
  11. package/lib/module/client.js +389 -0
  12. package/lib/module/client.js.map +1 -0
  13. package/lib/module/connectors/WalletConnectConnector.js +348 -0
  14. package/lib/module/connectors/WalletConnectConnector.js.map +1 -0
  15. package/lib/module/index.js +81 -0
  16. package/lib/module/index.js.map +1 -0
  17. package/lib/module/utils/defaultWagmiConfig.js +40 -0
  18. package/lib/module/utils/defaultWagmiConfig.js.map +1 -0
  19. package/lib/module/utils/helpers.js +43 -0
  20. package/lib/module/utils/helpers.js.map +1 -0
  21. package/lib/typescript/client.d.ts +39 -0
  22. package/lib/typescript/client.d.ts.map +1 -0
  23. package/lib/typescript/connectors/WalletConnectConnector.d.ts +74 -0
  24. package/lib/typescript/connectors/WalletConnectConnector.d.ts.map +1 -0
  25. package/lib/typescript/index.d.ts +24 -0
  26. package/lib/typescript/index.d.ts.map +1 -0
  27. package/lib/typescript/utils/defaultWagmiConfig.d.ts +11 -0
  28. package/lib/typescript/utils/defaultWagmiConfig.d.ts.map +1 -0
  29. package/lib/typescript/utils/helpers.d.ts +17 -0
  30. package/lib/typescript/utils/helpers.d.ts.map +1 -0
  31. package/package.json +76 -0
  32. package/readme.md +9 -0
  33. package/src/client.ts +475 -0
  34. package/src/connectors/WalletConnectConnector.ts +469 -0
  35. package/src/index.tsx +103 -0
  36. package/src/utils/defaultWagmiConfig.ts +53 -0
  37. package/src/utils/helpers.ts +58 -0
package/src/client.ts ADDED
@@ -0,0 +1,475 @@
1
+ import { formatUnits, type Hex } from 'viem';
2
+ import {
3
+ type GetAccountReturnType,
4
+ connect,
5
+ disconnect,
6
+ signMessage,
7
+ switchChain,
8
+ watchAccount,
9
+ watchConnectors,
10
+ getEnsName,
11
+ getEnsAvatar as wagmiGetEnsAvatar,
12
+ getBalance
13
+ } from '@wagmi/core';
14
+ import { mainnet, type Chain } from '@wagmi/core/chains';
15
+ import { EthereumProvider, OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
16
+ import {
17
+ type CaipAddress,
18
+ type CaipNetwork,
19
+ type CaipNetworkId,
20
+ type ConnectionControllerClient,
21
+ type Connector,
22
+ type LibraryOptions,
23
+ type NetworkControllerClient,
24
+ type PublicStateControllerState,
25
+ type Token,
26
+ AppKitScaffold
27
+ } from '@reown/appkit-scaffold-react-native';
28
+ import {
29
+ ConstantsUtil,
30
+ HelpersUtil,
31
+ PresetsUtil,
32
+ StorageUtil
33
+ } from '@reown/appkit-scaffold-utils-react-native';
34
+ import { NetworkUtil } from '@reown/appkit-common-react-native';
35
+ import { type AppKitSIWEClient } from '@reown/appkit-siwe-react-native';
36
+ import {
37
+ getCaipDefaultChain,
38
+ getAuthCaipNetworks,
39
+ getWalletConnectCaipNetworks
40
+ } from './utils/helpers';
41
+ import { defaultWagmiConfig } from './utils/defaultWagmiConfig';
42
+
43
+ // -- Types ---------------------------------------------------------------------
44
+ type WagmiConfig = ReturnType<typeof defaultWagmiConfig>;
45
+
46
+ export interface AppKitClientOptions extends Omit<LibraryOptions, 'defaultChain' | 'tokens'> {
47
+ wagmiConfig: WagmiConfig;
48
+ siweConfig?: AppKitSIWEClient;
49
+ defaultChain?: Chain;
50
+ chainImages?: Record<number, string>;
51
+ connectorImages?: Record<string, string>;
52
+ tokens?: Record<number, Token>;
53
+ }
54
+
55
+ export type AppKitOptions = Omit<AppKitClientOptions, '_sdkVersion'>;
56
+
57
+ // @ts-expect-error: Overriden state type is correct
58
+ interface AppKitState extends PublicStateControllerState {
59
+ selectedNetworkId: number | undefined;
60
+ }
61
+
62
+ // -- Client --------------------------------------------------------------------
63
+ export class AppKit extends AppKitScaffold {
64
+ private hasSyncedConnectedAccount = false;
65
+
66
+ private options: AppKitClientOptions | undefined = undefined;
67
+
68
+ private wagmiConfig: WagmiConfig;
69
+
70
+ public constructor(options: AppKitClientOptions) {
71
+ const { wagmiConfig, siweConfig, defaultChain, tokens, _sdkVersion, ...appKitOptions } =
72
+ options;
73
+
74
+ if (!wagmiConfig) {
75
+ throw new Error('appkit:constructor - wagmiConfig is undefined');
76
+ }
77
+
78
+ if (!appKitOptions.projectId) {
79
+ throw new Error('appkit:constructor - projectId is undefined');
80
+ }
81
+
82
+ const networkControllerClient: NetworkControllerClient = {
83
+ switchCaipNetwork: async caipNetwork => {
84
+ const chainId = NetworkUtil.caipNetworkIdToNumber(caipNetwork?.id);
85
+ if (chainId) {
86
+ await switchChain(wagmiConfig, { chainId });
87
+ }
88
+ },
89
+
90
+ async getApprovedCaipNetworksData() {
91
+ const walletChoice = await StorageUtil.getConnectedConnector();
92
+ const walletConnectType =
93
+ PresetsUtil.ConnectorTypesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID];
94
+
95
+ const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID];
96
+
97
+ if (walletChoice?.includes(walletConnectType)) {
98
+ const connector = wagmiConfig.connectors.find(
99
+ c => c.id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID
100
+ );
101
+
102
+ return getWalletConnectCaipNetworks(connector);
103
+ } else if (authType) {
104
+ return getAuthCaipNetworks();
105
+ }
106
+
107
+ return { approvedCaipNetworkIds: undefined, supportsAllNetworks: true };
108
+ }
109
+ };
110
+
111
+ const connectionControllerClient: ConnectionControllerClient = {
112
+ connectWalletConnect: async (onUri, walletUniversalLink) => {
113
+ const connector = wagmiConfig.connectors.find(
114
+ c => c.id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID
115
+ );
116
+ if (!connector) {
117
+ throw new Error(
118
+ 'connectionControllerClient:getWalletConnectUri - connector is undefined'
119
+ );
120
+ }
121
+
122
+ const provider = (await connector.getProvider()) as Awaited<
123
+ ReturnType<(typeof EthereumProvider)['init']>
124
+ >;
125
+
126
+ provider.on('display_uri', data => {
127
+ onUri(data);
128
+ });
129
+
130
+ // When connecting through walletconnect, we need to set the clientId in the store
131
+ const clientId = await provider.signer?.client?.core?.crypto?.getClientId();
132
+ if (clientId) {
133
+ this.setClientId(clientId);
134
+ }
135
+
136
+ const chainId = NetworkUtil.caipNetworkIdToNumber(this.getCaipNetwork()?.id);
137
+
138
+ // SIWE
139
+ const siweParams = await siweConfig?.getMessageParams?.();
140
+ // Make sure client uses ethereum provider version that supports `authenticate`
141
+ if (
142
+ siweConfig?.options?.enabled &&
143
+ typeof provider?.authenticate === 'function' &&
144
+ siweParams &&
145
+ Object.keys(siweParams || {}).length > 0
146
+ ) {
147
+ const { SIWEController, getDidChainId, getDidAddress } = await import(
148
+ '@reown/appkit-siwe-react-native'
149
+ );
150
+ // @ts-expect-error - setting requested chains beforehand avoids wagmi auto disconnecting the session when `connect` is called because it things chains are stale
151
+ await connector.setRequestedChainsIds(siweParams.chains);
152
+ const result = await provider.authenticate(
153
+ {
154
+ nonce: await siweConfig.getNonce(),
155
+ methods: [...OPTIONAL_METHODS],
156
+ ...siweParams
157
+ },
158
+ walletUniversalLink
159
+ );
160
+
161
+ // Auths is an array of signed CACAO objects https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-74.md
162
+ const signedCacao = result?.auths?.[0];
163
+ if (signedCacao) {
164
+ const { p, s } = signedCacao;
165
+ const cacaoChainId = getDidChainId(p.iss) || '';
166
+ const address = getDidAddress(p.iss);
167
+ try {
168
+ // Kicks off verifyMessage and populates external states
169
+ const message = provider.signer.client.formatAuthMessage({
170
+ request: p,
171
+ iss: p.iss
172
+ });
173
+
174
+ await SIWEController.verifyMessage({
175
+ message,
176
+ signature: s.s,
177
+ cacao: signedCacao
178
+ });
179
+
180
+ if (address && chainId) {
181
+ const session = {
182
+ address,
183
+ chainId: parseInt(cacaoChainId, 10)
184
+ };
185
+
186
+ SIWEController.setSession(session);
187
+ SIWEController.onSignIn?.(session);
188
+ }
189
+ } catch (error) {
190
+ // eslint-disable-next-line no-console
191
+ console.error('Error verifying message', error);
192
+ // eslint-disable-next-line no-console
193
+ await provider.disconnect().catch(console.error);
194
+ // eslint-disable-next-line no-console
195
+ await SIWEController.signOut().catch(console.error);
196
+ throw error;
197
+ }
198
+ /*
199
+ * Unassign the connector from the wagmiConfig and allow connect() to reassign it in the next step
200
+ * this avoids case where wagmi throws because the connector is already connected
201
+ * what we need connect() to do is to only setup internal event listeners
202
+ */
203
+ this.wagmiConfig.state.current = '';
204
+ }
205
+ }
206
+
207
+ await connect(this.wagmiConfig, { connector, chainId });
208
+ },
209
+
210
+ connectExternal: async ({ id }) => {
211
+ const connector = wagmiConfig.connectors.find(c => c.id === id);
212
+ if (!connector) {
213
+ throw new Error('connectionControllerClient:connectExternal - connector is undefined');
214
+ }
215
+
216
+ // If connecting with something else than walletconnect, we need to clear the clientId in the store
217
+ this.setClientId(null);
218
+
219
+ const chainId = NetworkUtil.caipNetworkIdToNumber(this.getCaipNetwork()?.id);
220
+ await connect(this.wagmiConfig, { connector, chainId });
221
+ },
222
+
223
+ signMessage: async message => signMessage(this.wagmiConfig, { message }),
224
+
225
+ disconnect: async () => {
226
+ await disconnect(this.wagmiConfig);
227
+ this.setClientId(null);
228
+
229
+ if (siweConfig?.options?.signOutOnDisconnect) {
230
+ const { SIWEController } = await import('@reown/appkit-siwe-react-native');
231
+ await SIWEController.signOut();
232
+ }
233
+ }
234
+ };
235
+
236
+ super({
237
+ networkControllerClient,
238
+ connectionControllerClient,
239
+ siweControllerClient: siweConfig,
240
+ defaultChain: getCaipDefaultChain(defaultChain),
241
+ tokens: HelpersUtil.getCaipTokens(tokens),
242
+ _sdkVersion: _sdkVersion ?? `react-native-wagmi-${ConstantsUtil.VERSION}`,
243
+ ...appKitOptions
244
+ });
245
+
246
+ this.options = options;
247
+ this.wagmiConfig = wagmiConfig;
248
+
249
+ this.syncRequestedNetworks([...wagmiConfig.chains]);
250
+ this.syncConnectors([...wagmiConfig.connectors]);
251
+ this.listenAuthConnector([...wagmiConfig.connectors]);
252
+
253
+ watchConnectors(wagmiConfig, {
254
+ onChange: connectors => this.syncConnectors([...connectors])
255
+ });
256
+
257
+ watchAccount(wagmiConfig, {
258
+ onChange: accountData => {
259
+ this.syncAccount({ ...accountData });
260
+ }
261
+ });
262
+ }
263
+
264
+ // -- Public ------------------------------------------------------------------
265
+
266
+ // @ts-expect-error: Overriden state type is correct
267
+ public override getState() {
268
+ const state = super.getState();
269
+
270
+ return {
271
+ ...state,
272
+ selectedNetworkId: NetworkUtil.caipNetworkIdToNumber(state.selectedNetworkId)
273
+ };
274
+ }
275
+
276
+ // @ts-expect-error: Overriden state type is correct
277
+ public override subscribeState(callback: (state: AppKitState) => void) {
278
+ return super.subscribeState(state =>
279
+ callback({
280
+ ...state,
281
+ selectedNetworkId: NetworkUtil.caipNetworkIdToNumber(state.selectedNetworkId)
282
+ })
283
+ );
284
+ }
285
+
286
+ // -- Private -----------------------------------------------------------------
287
+ private syncRequestedNetworks(chains: Chain[]) {
288
+ const requestedCaipNetworks = chains?.map(
289
+ chain =>
290
+ ({
291
+ id: `${ConstantsUtil.EIP155}:${chain.id}`,
292
+ name: chain.name,
293
+ imageId: PresetsUtil.EIP155NetworkImageIds[chain.id],
294
+ imageUrl: this.options?.chainImages?.[chain.id]
295
+ }) as CaipNetwork
296
+ );
297
+ this.setRequestedCaipNetworks(requestedCaipNetworks ?? []);
298
+ }
299
+
300
+ private async syncAccount({
301
+ address,
302
+ isConnected,
303
+ chainId,
304
+ connector,
305
+ isConnecting,
306
+ isReconnecting
307
+ }: Pick<
308
+ GetAccountReturnType,
309
+ 'address' | 'isConnected' | 'chainId' | 'connector' | 'isConnecting' | 'isReconnecting'
310
+ >) {
311
+ this.resetAccount();
312
+ this.syncNetwork(address, chainId, isConnected);
313
+ this.setLoading(!!connector && (isConnecting || isReconnecting));
314
+
315
+ if (isConnected && address && chainId) {
316
+ const caipAddress: CaipAddress = `${ConstantsUtil.EIP155}:${chainId}:${address}`;
317
+ this.setIsConnected(isConnected);
318
+ this.setCaipAddress(caipAddress);
319
+ await Promise.all([
320
+ this.syncProfile(address, chainId),
321
+ this.syncBalance(address, chainId),
322
+ this.syncConnectedWalletInfo(connector),
323
+ this.getApprovedCaipNetworksData()
324
+ ]);
325
+ this.hasSyncedConnectedAccount = true;
326
+ } else if (!isConnected && this.hasSyncedConnectedAccount) {
327
+ this.resetWcConnection();
328
+ this.resetNetwork();
329
+ }
330
+ }
331
+
332
+ private async syncNetwork(address?: Hex, chainId?: number, isConnected?: boolean) {
333
+ const chain = this.wagmiConfig.chains.find((c: Chain) => c.id === chainId);
334
+
335
+ if (chain || chainId) {
336
+ const name = chain?.name ?? chainId?.toString();
337
+ const id = Number(chain?.id ?? chainId);
338
+ const caipChainId: CaipNetworkId = `${ConstantsUtil.EIP155}:${id}`;
339
+ this.setCaipNetwork({
340
+ id: caipChainId,
341
+ name,
342
+ imageId: PresetsUtil.EIP155NetworkImageIds[id],
343
+ imageUrl: this.options?.chainImages?.[id]
344
+ });
345
+ if (isConnected && address && chainId) {
346
+ const caipAddress: CaipAddress = `${ConstantsUtil.EIP155}:${id}:${address}`;
347
+ this.setCaipAddress(caipAddress);
348
+ if (chain?.blockExplorers?.default?.url) {
349
+ const url = `${chain.blockExplorers.default.url}/address/${address}`;
350
+ this.setAddressExplorerUrl(url);
351
+ } else {
352
+ this.setAddressExplorerUrl(undefined);
353
+ }
354
+ if (this.hasSyncedConnectedAccount) {
355
+ await this.syncProfile(address, chainId);
356
+ await this.syncBalance(address, chainId);
357
+ }
358
+ }
359
+ }
360
+ }
361
+
362
+ private async syncProfile(address: Hex, chainId: number) {
363
+ try {
364
+ const response = await this.fetchIdentity({ address });
365
+
366
+ if (!response) {
367
+ throw new Error('Couldnt fetch idendity');
368
+ }
369
+
370
+ this.setProfileName(response.name);
371
+ this.setProfileImage(response.avatar);
372
+ } catch {
373
+ if (chainId === mainnet.id) {
374
+ const profileName = await getEnsName(this.wagmiConfig, { address, chainId });
375
+ if (profileName) {
376
+ this.setProfileName(profileName);
377
+ const profileImage = await wagmiGetEnsAvatar(this.wagmiConfig, {
378
+ name: profileName,
379
+ chainId
380
+ });
381
+ if (profileImage) {
382
+ this.setProfileImage(profileImage);
383
+ }
384
+ }
385
+ } else {
386
+ this.setProfileName(undefined);
387
+ this.setProfileImage(undefined);
388
+ }
389
+ }
390
+ }
391
+
392
+ private async syncBalance(address: Hex, chainId: number) {
393
+ const chain = this.wagmiConfig.chains.find((c: Chain) => c.id === chainId);
394
+ if (chain) {
395
+ const balance = await getBalance(this.wagmiConfig, {
396
+ address,
397
+ chainId: chain.id
398
+ });
399
+ const formattedBalance = formatUnits(balance.value, balance.decimals);
400
+ this.setBalance(formattedBalance, balance.symbol);
401
+
402
+ return;
403
+ }
404
+ this.setBalance(undefined, undefined);
405
+ }
406
+
407
+ private async syncConnectedWalletInfo(connector: GetAccountReturnType['connector']) {
408
+ if (!connector) {
409
+ throw Error('syncConnectedWalletInfo - connector is undefined');
410
+ }
411
+
412
+ if (connector.id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID && connector.getProvider) {
413
+ const walletConnectProvider = (await connector.getProvider()) as Awaited<
414
+ ReturnType<(typeof EthereumProvider)['init']>
415
+ >;
416
+ if (walletConnectProvider.session) {
417
+ this.setConnectedWalletInfo({
418
+ ...walletConnectProvider.session.peer.metadata,
419
+ name: walletConnectProvider.session.peer.metadata.name,
420
+ icon: walletConnectProvider.session.peer.metadata.icons?.[0]
421
+ });
422
+ }
423
+ } else {
424
+ this.setConnectedWalletInfo({ name: connector.name, icon: connector.icon });
425
+ }
426
+ }
427
+
428
+ private syncConnectors(connectors: AppKitClientOptions['wagmiConfig']['connectors']) {
429
+ const uniqueIds = new Set();
430
+ const filteredConnectors = connectors.filter(
431
+ item => !uniqueIds.has(item.id) && uniqueIds.add(item.id)
432
+ );
433
+
434
+ const excludedConnectors = [ConstantsUtil.AUTH_CONNECTOR_ID];
435
+
436
+ const _connectors: Connector[] = [];
437
+ filteredConnectors.forEach(({ id, name, icon }) => {
438
+ if (!excludedConnectors.includes(id)) {
439
+ _connectors.push({
440
+ id,
441
+ explorerId: PresetsUtil.ConnectorExplorerIds[id],
442
+ imageId: PresetsUtil.ConnectorImageIds[id] ?? icon,
443
+ imageUrl: this.options?.connectorImages?.[id],
444
+ name: PresetsUtil.ConnectorNamesMap[id] ?? name,
445
+ type: PresetsUtil.ConnectorTypesMap[id] ?? 'EXTERNAL'
446
+ });
447
+ }
448
+ });
449
+
450
+ this.setConnectors(_connectors);
451
+ this.syncAuthConnector(filteredConnectors);
452
+ }
453
+
454
+ private async syncAuthConnector(connectors: AppKitClientOptions['wagmiConfig']['connectors']) {
455
+ const authConnector = connectors.find(({ id }) => id === ConstantsUtil.AUTH_CONNECTOR_ID);
456
+ if (authConnector) {
457
+ const provider = await authConnector.getProvider();
458
+ this.addConnector({
459
+ id: ConstantsUtil.AUTH_CONNECTOR_ID,
460
+ type: 'AUTH',
461
+ name: 'Auth',
462
+ provider
463
+ });
464
+ }
465
+ }
466
+
467
+ private async listenAuthConnector(connectors: AppKitClientOptions['wagmiConfig']['connectors']) {
468
+ const connector = connectors.find(c => c.id === ConstantsUtil.AUTH_CONNECTOR_ID);
469
+
470
+ const connectedConnector = await StorageUtil.getItem('@w3m/connected_connector');
471
+ if (connector && connectedConnector === 'AUTH') {
472
+ super.setLoading(true);
473
+ }
474
+ }
475
+ }