@reown/appkit-react-native 0.0.0-feat-multichain-phantom-20250609201736 → 0.0.0-feat-multi-siwe-20250619154334

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 (40) hide show
  1. package/lib/commonjs/AppKit.js +63 -7
  2. package/lib/commonjs/AppKit.js.map +1 -1
  3. package/lib/commonjs/connectors/WalletConnectConnector.js +79 -6
  4. package/lib/commonjs/connectors/WalletConnectConnector.js.map +1 -1
  5. package/lib/commonjs/modal/w3m-modal/index.js +7 -47
  6. package/lib/commonjs/modal/w3m-modal/index.js.map +1 -1
  7. package/lib/commonjs/modal/w3m-router/index.js +2 -2
  8. package/lib/commonjs/modal/w3m-router/index.js.map +1 -1
  9. package/lib/commonjs/views/w3m-connecting-siwe-view/index.js +138 -0
  10. package/lib/commonjs/views/w3m-connecting-siwe-view/index.js.map +1 -0
  11. package/lib/commonjs/views/w3m-connecting-siwe-view/styles.js +35 -0
  12. package/lib/commonjs/views/w3m-connecting-siwe-view/styles.js.map +1 -0
  13. package/lib/module/AppKit.js +63 -8
  14. package/lib/module/AppKit.js.map +1 -1
  15. package/lib/module/connectors/WalletConnectConnector.js +79 -6
  16. package/lib/module/connectors/WalletConnectConnector.js.map +1 -1
  17. package/lib/module/modal/w3m-modal/index.js +8 -48
  18. package/lib/module/modal/w3m-modal/index.js.map +1 -1
  19. package/lib/module/modal/w3m-router/index.js +1 -1
  20. package/lib/module/modal/w3m-router/index.js.map +1 -1
  21. package/lib/module/views/w3m-connecting-siwe-view/index.js +131 -0
  22. package/lib/module/views/w3m-connecting-siwe-view/index.js.map +1 -0
  23. package/lib/module/views/w3m-connecting-siwe-view/styles.js +29 -0
  24. package/lib/module/views/w3m-connecting-siwe-view/styles.js.map +1 -0
  25. package/lib/typescript/AppKit.d.ts +6 -3
  26. package/lib/typescript/AppKit.d.ts.map +1 -1
  27. package/lib/typescript/AppKitContext.d.ts +1 -1
  28. package/lib/typescript/connectors/WalletConnectConnector.d.ts.map +1 -1
  29. package/lib/typescript/modal/w3m-modal/index.d.ts.map +1 -1
  30. package/lib/typescript/views/w3m-connecting-siwe-view/index.d.ts +2 -0
  31. package/lib/typescript/views/w3m-connecting-siwe-view/index.d.ts.map +1 -0
  32. package/lib/typescript/views/w3m-connecting-siwe-view/styles.d.ts +28 -0
  33. package/lib/typescript/views/w3m-connecting-siwe-view/styles.d.ts.map +1 -0
  34. package/package.json +5 -5
  35. package/src/AppKit.ts +63 -9
  36. package/src/connectors/WalletConnectConnector.ts +80 -6
  37. package/src/modal/w3m-modal/index.tsx +10 -60
  38. package/src/modal/w3m-router/index.tsx +1 -1
  39. package/src/views/w3m-connecting-siwe-view/index.tsx +142 -0
  40. package/src/views/w3m-connecting-siwe-view/styles.ts +29 -0
@@ -12,6 +12,7 @@ import {
12
12
  type ConnectorInitOptions,
13
13
  type Metadata
14
14
  } from '@reown/appkit-common-react-native';
15
+ import { getDidAddress, getDidChainId, SIWEController } from '@reown/appkit-siwe-react-native';
15
16
 
16
17
  interface WalletConnectConnectorConfig {
17
18
  projectId: string;
@@ -85,6 +86,7 @@ export class WalletConnectConnector extends WalletConnector {
85
86
  }
86
87
 
87
88
  override async connect(opts: ConnectOptions) {
89
+ const { siweConfig, namespaces, defaultChain, universalLink } = opts;
88
90
  function onUri(uri: string) {
89
91
  ConnectionController.setWcUri(uri);
90
92
  }
@@ -94,13 +96,84 @@ export class WalletConnectConnector extends WalletConnector {
94
96
  // @ts-ignore
95
97
  provider.on('display_uri', onUri);
96
98
 
97
- const session = await (this.provider as IUniversalProvider).connect({
98
- namespaces: {},
99
- optionalNamespaces: opts.namespaces
100
- });
99
+ let session;
100
+
101
+ // SIWE
102
+ const params = await siweConfig?.getMessageParams?.();
103
+ if (siweConfig?.options?.enabled && params && Object.keys(params).length > 0) {
104
+ // @ts-ignore
105
+ const result = await provider.authenticate(
106
+ {
107
+ ...params,
108
+ nonce: await siweConfig.getNonce(),
109
+ methods: namespaces?.['eip155']?.methods,
110
+ chains: params.chains.map(chain => `eip155:${chain}`)
111
+ },
112
+ universalLink
113
+ );
114
+
115
+ console.log('result SIWE', result);
116
+
117
+ // Auths is an array of signed CACAO objects https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-74.md
118
+ const signedCacao = result?.auths?.[0];
119
+ if (signedCacao) {
120
+ const { p, s } = signedCacao;
121
+ const chainId = getDidChainId(p.iss);
122
+ const address = getDidAddress(p.iss);
123
+
124
+ try {
125
+ // Kicks off verifyMessage and populates external states
126
+ const message = provider?.client?.formatAuthMessage({
127
+ request: p,
128
+ iss: p.iss
129
+ })!;
130
+
131
+ await SIWEController.verifyMessage({
132
+ message,
133
+ signature: s.s,
134
+ cacao: signedCacao
135
+ });
136
+
137
+ if (address && chainId) {
138
+ const session = {
139
+ address,
140
+ chainId: parseInt(chainId, 10)
141
+ };
142
+
143
+ SIWEController.setSession(session);
144
+ SIWEController.onSignIn?.(session);
145
+ }
146
+ } catch (error) {
147
+ // eslint-disable-next-line no-console
148
+ console.error('Error verifying message', error);
149
+ // eslint-disable-next-line no-console
150
+ await provider.disconnect().catch(console.error);
151
+ // eslint-disable-next-line no-console
152
+ await SIWEController.signOut().catch(console.error);
153
+ throw error;
154
+ }
155
+ }
156
+ session = result?.session;
157
+ } else {
158
+ session = await (this.provider as IUniversalProvider).connect({
159
+ namespaces: {},
160
+ optionalNamespaces: namespaces
161
+ });
162
+ }
163
+
164
+ const metadata = session?.peer?.metadata;
165
+ if (metadata) {
166
+ this.wallet = {
167
+ ...metadata,
168
+ name: metadata?.name,
169
+ icon: metadata?.icons?.[0]
170
+ };
171
+ } else {
172
+ this.wallet = undefined;
173
+ }
101
174
 
102
- if (opts.defaultChain) {
103
- (this.provider as IUniversalProvider).setDefaultChain(opts.defaultChain);
175
+ if (defaultChain) {
176
+ (this.provider as IUniversalProvider).setDefaultChain(defaultChain);
104
177
  }
105
178
 
106
179
  this.namespaces = session?.namespaces as Namespaces;
@@ -133,6 +206,7 @@ export class WalletConnectConnector extends WalletConnector {
133
206
  }
134
207
 
135
208
  override getWalletInfo(): WalletInfo | undefined {
209
+ console.log('getWalletInfo', this.wallet);
136
210
  return this.wallet;
137
211
  }
138
212
 
@@ -4,21 +4,17 @@ import { useWindowDimensions, StatusBar } from 'react-native';
4
4
  import Modal from 'react-native-modal';
5
5
  import { Card, ThemeProvider } from '@reown/appkit-ui-react-native';
6
6
  import {
7
- AccountController,
8
7
  ApiController,
9
- ConnectionController,
10
8
  ConnectorController,
11
- CoreHelperUtil,
12
9
  EventsController,
13
10
  ModalController,
14
11
  OptionsController,
15
12
  RouterController,
16
- TransactionsController,
17
13
  type AppKitFrameProvider,
18
14
  WebviewController,
19
- ThemeController
15
+ ThemeController,
16
+ ConnectionsController
20
17
  } from '@reown/appkit-core-react-native';
21
- import type { CaipAddress } from '@reown/appkit-common-react-native';
22
18
  import { SIWEController } from '@reown/appkit-siwe-react-native';
23
19
 
24
20
  import { AppKitRouter } from '../w3m-router';
@@ -26,11 +22,12 @@ import { Header } from '../../partials/w3m-header';
26
22
  import { Snackbar } from '../../partials/w3m-snackbar';
27
23
  import { useCustomDimensions } from '../../hooks/useCustomDimensions';
28
24
  import styles from './styles';
25
+ import { useAppKit } from '../../AppKitContext';
29
26
 
30
27
  export function AppKit() {
31
- const { open, loading } = useSnapshot(ModalController.state);
28
+ const { disconnect } = useAppKit();
29
+ const { open } = useSnapshot(ModalController.state);
32
30
  const { connectors, connectedConnector } = useSnapshot(ConnectorController.state);
33
- const { caipAddress, isConnected } = useSnapshot(AccountController.state);
34
31
  const { frameViewVisible, webviewVisible } = useSnapshot(WebviewController.state);
35
32
  const { themeMode, themeVariables } = useSnapshot(ThemeController.state);
36
33
  const { projectId } = useSnapshot(OptionsController.state);
@@ -58,8 +55,11 @@ export function AppKit() {
58
55
 
59
56
  const handleClose = async () => {
60
57
  if (OptionsController.state.isSiweEnabled) {
61
- if (SIWEController.state.status !== 'success' && AccountController.state.isConnected) {
62
- await ConnectionController.disconnect();
58
+ if (
59
+ SIWEController.state.status !== 'success' &&
60
+ !!ConnectionsController.state.activeAddress
61
+ ) {
62
+ await disconnect();
63
63
  }
64
64
  }
65
65
 
@@ -71,62 +71,12 @@ export function AppKit() {
71
71
  EventsController.sendEvent({ type: 'track', event: 'BUY_CANCEL' });
72
72
  }
73
73
  };
74
-
75
- const onNewAddress = useCallback(
76
- async (address?: CaipAddress) => {
77
- if (!isConnected || loading) {
78
- return;
79
- }
80
-
81
- const newAddress = CoreHelperUtil.getPlainAddress(address);
82
- TransactionsController.resetTransactions();
83
-
84
- if (OptionsController.state.isSiweEnabled) {
85
- const newNetworkId = CoreHelperUtil.getNetworkId(address);
86
-
87
- const { signOutOnAccountChange, signOutOnNetworkChange } =
88
- SIWEController.state._client?.options ?? {};
89
- const session = await SIWEController.getSession();
90
-
91
- if (session && newAddress && signOutOnAccountChange) {
92
- // If the address has changed and signOnAccountChange is enabled, sign out
93
- await SIWEController.signOut();
94
- onSiweNavigation();
95
- } else if (
96
- newNetworkId &&
97
- session?.chainId.toString() !== newNetworkId &&
98
- signOutOnNetworkChange
99
- ) {
100
- // If the network has changed and signOnNetworkChange is enabled, sign out
101
- await SIWEController.signOut();
102
- onSiweNavigation();
103
- } else if (!session) {
104
- // If it's connected but there's no session, show sign view
105
- onSiweNavigation();
106
- }
107
- }
108
- },
109
- [isConnected, loading]
110
- );
111
-
112
- const onSiweNavigation = () => {
113
- if (ModalController.state.open) {
114
- RouterController.push('ConnectingSiwe');
115
- } else {
116
- ModalController.open({ view: 'ConnectingSiwe' });
117
- }
118
- };
119
-
120
74
  useEffect(() => {
121
75
  if (projectId) {
122
76
  prefetch();
123
77
  }
124
78
  }, [projectId, prefetch]);
125
79
 
126
- useEffect(() => {
127
- onNewAddress(caipAddress);
128
- }, [caipAddress, onNewAddress]);
129
-
130
80
  return (
131
81
  <>
132
82
  <ThemeProvider themeMode={themeMode} themeVariables={themeVariables}>
@@ -12,7 +12,7 @@ import { ConnectingExternalView } from '../../views/w3m-connecting-external-view
12
12
  import { ConnectingFarcasterView } from '../../views/w3m-connecting-farcaster-view';
13
13
  import { ConnectingSocialView } from '../../views/w3m-connecting-social-view';
14
14
  import { CreateView } from '../../views/w3m-create-view';
15
- import { ConnectingSiweView } from '@reown/appkit-siwe-react-native';
15
+ import { ConnectingSiweView } from '../../views/w3m-connecting-siwe-view';
16
16
  import { EmailVerifyOtpView } from '../../views/w3m-email-verify-otp-view';
17
17
  import { EmailVerifyDeviceView } from '../../views/w3m-email-verify-device-view';
18
18
  import { GetWalletView } from '../../views/w3m-get-wallet-view';
@@ -0,0 +1,142 @@
1
+ import { useSnapshot } from 'valtio';
2
+ import {
3
+ Avatar,
4
+ Button,
5
+ DoubleImageLoader,
6
+ FlexView,
7
+ IconLink,
8
+ Text
9
+ } from '@reown/appkit-ui-react-native';
10
+ import {
11
+ AccountController,
12
+ AssetUtil,
13
+ ConnectionController,
14
+ ConnectionsController,
15
+ EventsController,
16
+ ModalController,
17
+ OptionsController,
18
+ RouterController,
19
+ SnackController
20
+ } from '@reown/appkit-core-react-native';
21
+
22
+ import { useState } from 'react';
23
+ import { SIWEController } from '@reown/appkit-siwe-react-native';
24
+ import styles from './styles';
25
+ import { useAppKit } from '../../AppKitContext';
26
+
27
+ export function ConnectingSiweView() {
28
+ const { disconnect } = useAppKit();
29
+ const { metadata } = useSnapshot(OptionsController.state);
30
+ const { connectedWalletImageUrl, pressedWallet } = useSnapshot(ConnectionController.state);
31
+ const { activeAddress } = useSnapshot(ConnectionsController.state);
32
+ const [isSigning, setIsSigning] = useState(false);
33
+ const [isDisconnecting, setIsDisconnecting] = useState(false);
34
+
35
+ const dappName = metadata?.name || 'Dapp';
36
+ const dappIcon = metadata?.icons[0] || '';
37
+ const walletIcon = AssetUtil.getWalletImage(pressedWallet) || connectedWalletImageUrl;
38
+
39
+ const onSign = async () => {
40
+ setIsSigning(true);
41
+ EventsController.sendEvent({
42
+ event: 'CLICK_SIGN_SIWE_MESSAGE',
43
+ type: 'track',
44
+ properties: {
45
+ network: ConnectionsController.state.activeNetwork?.caipNetworkId || '',
46
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
47
+ }
48
+ });
49
+ try {
50
+ const session = await SIWEController.signIn();
51
+
52
+ EventsController.sendEvent({
53
+ event: 'SIWE_AUTH_SUCCESS',
54
+ type: 'track',
55
+ properties: {
56
+ network: ConnectionsController.state.activeNetwork?.caipNetworkId || '',
57
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
58
+ }
59
+ });
60
+
61
+ return session;
62
+ } catch (error) {
63
+ SnackController.showError('Signature declined');
64
+
65
+ SIWEController.setStatus('error');
66
+
67
+ return EventsController.sendEvent({
68
+ event: 'SIWE_AUTH_ERROR',
69
+ type: 'track',
70
+ properties: {
71
+ network: ConnectionsController.state.activeNetwork?.caipNetworkId || '',
72
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
73
+ }
74
+ });
75
+ } finally {
76
+ setIsSigning(false);
77
+ }
78
+ };
79
+
80
+ const onCancel = async () => {
81
+ if (ConnectionsController.state.activeAddress) {
82
+ setIsDisconnecting(true);
83
+ await disconnect();
84
+ ModalController.close();
85
+ setIsDisconnecting(false);
86
+ } else {
87
+ RouterController.push('Connect');
88
+ }
89
+ EventsController.sendEvent({
90
+ event: 'CLICK_CANCEL_SIWE',
91
+ type: 'track',
92
+ properties: {
93
+ network: ConnectionsController.state.activeNetwork?.caipNetworkId || '',
94
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
95
+ }
96
+ });
97
+ };
98
+
99
+ return (
100
+ <FlexView padding={['2xl', 's', '3xl', 's']}>
101
+ <IconLink
102
+ icon="close"
103
+ size="md"
104
+ onPress={onCancel}
105
+ testID="header-close"
106
+ style={styles.closeButton}
107
+ />
108
+ <Text variant="paragraph-600" numberOfLines={1} center>
109
+ Sign in
110
+ </Text>
111
+ <DoubleImageLoader
112
+ style={styles.logoContainer}
113
+ leftImage={dappIcon}
114
+ rightImage={walletIcon}
115
+ renderRightPlaceholder={() => (
116
+ <Avatar imageSrc={undefined} address={activeAddress} size={60} borderWidth={0} />
117
+ )}
118
+ rightItemStyle={!walletIcon && styles.walletAvatar}
119
+ />
120
+ <Text center variant="medium-600" color="fg-100" style={styles.title}>
121
+ {dappName} needs to connect to your wallet
122
+ </Text>
123
+ <Text center variant="small-400" color="fg-200" style={styles.subtitle}>
124
+ Sign this message to prove you own this wallet and proceed. Cancelling will disconnect you
125
+ </Text>
126
+ <FlexView flexDirection="row" justifyContent="space-between" margin={['s', '0', '0', '0']}>
127
+ <Button variant="shade" onPress={onCancel} style={styles.button} loading={isDisconnecting}>
128
+ Cancel
129
+ </Button>
130
+ <Button
131
+ variant="fill"
132
+ loading={isSigning}
133
+ disabled={isDisconnecting}
134
+ onPress={onSign}
135
+ style={styles.button}
136
+ >
137
+ Sign
138
+ </Button>
139
+ </FlexView>
140
+ </FlexView>
141
+ );
142
+ }
@@ -0,0 +1,29 @@
1
+ import { BorderRadius, Spacing } from '@reown/appkit-ui-react-native';
2
+ import { StyleSheet } from 'react-native';
3
+
4
+ export default StyleSheet.create({
5
+ logoContainer: {
6
+ marginTop: Spacing.xl,
7
+ marginBottom: Spacing.m
8
+ },
9
+ button: {
10
+ width: '48%'
11
+ },
12
+ title: {
13
+ marginHorizontal: '15%'
14
+ },
15
+ subtitle: {
16
+ marginHorizontal: '10%',
17
+ marginVertical: Spacing.l
18
+ },
19
+ closeButton: {
20
+ alignSelf: 'flex-end',
21
+ right: Spacing.xl,
22
+ top: Spacing.l,
23
+ position: 'absolute',
24
+ zIndex: 2
25
+ },
26
+ walletAvatar: {
27
+ borderRadius: BorderRadius.full
28
+ }
29
+ });