From f423bfa3c66084fa2efefe96628e20494da0bd90 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 6 Aug 2024 14:26:19 -0300
Subject: [PATCH 001/114] chore: implementing new account view
---
.../core/src/controllers/RouterController.ts | 1 +
packages/scaffold/src/index.ts | 2 +-
.../scaffold/src/modal/w3m-router/index.tsx | 5 +-
.../partials/w3m-account-activity/index.tsx | 11 +
.../src/partials/w3m-account-nfts/index.tsx | 11 +
.../w3m-account-placeholder/index.tsx | 32 +++
.../src/partials/w3m-account-tokens/index.tsx | 11 +
.../w3m-account-wallet-features/index.tsx | 61 ++++++
.../w3m-account-wallet-features/styles.ts | 21 ++
.../src/partials/w3m-header/index.tsx | 1 +
.../components/upgrade-wallet-button.tsx | 0
.../views/w3m-account-settings-view/index.tsx | 200 ++++++++++++++++++
.../views/w3m-account-settings-view/styles.ts | 21 ++
.../src/views/w3m-account-view/index.tsx | 194 ++---------------
.../src/views/w3m-account-view/styles.ts | 16 +-
.../ui/src/assets/svg/ArrowBottomCircle.tsx | 12 ++
packages/ui/src/assets/svg/Paperplane.tsx | 12 ++
packages/ui/src/components/wui-icon/index.tsx | 4 +
.../composites/wui-network-button/index.tsx | 33 +--
.../composites/wui-network-button/styles.ts | 2 +-
packages/ui/src/composites/wui-tabs/index.tsx | 42 +++-
packages/ui/src/composites/wui-tabs/styles.ts | 3 +-
packages/ui/src/utils/TypesUtil.ts | 5 +-
23 files changed, 485 insertions(+), 215 deletions(-)
create mode 100644 packages/scaffold/src/partials/w3m-account-activity/index.tsx
create mode 100644 packages/scaffold/src/partials/w3m-account-nfts/index.tsx
create mode 100644 packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
create mode 100644 packages/scaffold/src/partials/w3m-account-tokens/index.tsx
create mode 100644 packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
create mode 100644 packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
rename packages/scaffold/src/views/{w3m-account-view => w3m-account-settings-view}/components/upgrade-wallet-button.tsx (100%)
create mode 100644 packages/scaffold/src/views/w3m-account-settings-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-account-settings-view/styles.ts
create mode 100644 packages/ui/src/assets/svg/ArrowBottomCircle.tsx
create mode 100644 packages/ui/src/assets/svg/Paperplane.tsx
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index 9eecdd34d..88962e0a5 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -5,6 +5,7 @@ import type { WcWallet, CaipNetwork, Connector } from '../utils/TypeUtil';
export interface RouterControllerState {
view:
| 'Account'
+ | 'AccountSettings'
| 'Connect'
| 'ConnectingWalletConnect'
| 'ConnectingExternal'
diff --git a/packages/scaffold/src/index.ts b/packages/scaffold/src/index.ts
index 766ef5854..907b9dc96 100644
--- a/packages/scaffold/src/index.ts
+++ b/packages/scaffold/src/index.ts
@@ -5,7 +5,7 @@ export * from './modal/w3m-network-button';
export * from './modal/w3m-modal';
export * from './modal/w3m-router';
-export * from './views/w3m-account-view';
+export * from './views/w3m-account-settings-view';
export * from './views/w3m-all-wallets-view';
export * from './views/w3m-connect-view';
export * from './views/w3m-connecting-view';
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index fabe66c7c..37f58f0c8 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -8,7 +8,7 @@ import { AllWalletsView } from '../../views/w3m-all-wallets-view';
import { ConnectingView } from '../../views/w3m-connecting-view';
import { WhatIsAWalletView } from '../../views/w3m-what-is-a-wallet-view';
import { GetWalletView } from '../../views/w3m-get-wallet-view';
-import { AccountView } from '../../views/w3m-account-view';
+import { AccountSettingsView } from '../../views/w3m-account-settings-view';
import { NetworksView } from '../../views/w3m-networks-view';
import { WhatIsNetworkView } from '../../views/w3m-what-is-a-network-view';
import { NetworkSwitchView } from '../../views/w3m-network-switch-view';
@@ -20,6 +20,7 @@ import { UpdateEmailWalletView } from '../../views/w3m-update-email-wallet-view'
import { UpdateEmailPrimaryOtpView } from '../../views/w3m-update-email-primary-otp-view';
import { UpdateEmailSecondaryOtpView } from '../../views/w3m-update-email-secondary-otp-view';
import { UpgradeEmailWalletView } from '../../views/w3m-upgrade-email-wallet-view';
+import { AccountView } from '../../views/w3m-account-view';
export function Web3Router() {
const { view } = useSnapshot(RouterController.state);
@@ -50,6 +51,8 @@ export function Web3Router() {
return NetworkSwitchView;
case 'Account':
return AccountView;
+ case 'AccountSettings':
+ return AccountSettingsView;
case 'EmailVerifyDevice':
return EmailVerifyDeviceView;
case 'EmailVerifyOtp':
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
new file mode 100644
index 000000000..9b91cf4b7
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -0,0 +1,11 @@
+import { AccountPlaceholder } from '../w3m-account-placeholder';
+
+export function AccountActivity() {
+ return (
+
+ );
+}
diff --git a/packages/scaffold/src/partials/w3m-account-nfts/index.tsx b/packages/scaffold/src/partials/w3m-account-nfts/index.tsx
new file mode 100644
index 000000000..59643cabc
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-nfts/index.tsx
@@ -0,0 +1,11 @@
+import { AccountPlaceholder } from '../w3m-account-placeholder';
+
+export function AccountNfts() {
+ return (
+
+ );
+}
diff --git a/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx b/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
new file mode 100644
index 000000000..8c0974c9c
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
@@ -0,0 +1,32 @@
+import { StyleSheet } from 'react-native';
+import { IconBox, Text, FlexView, Spacing, type IconType } from '@web3modal/ui-react-native';
+
+interface Props {
+ icon: IconType;
+ title: string;
+ description: string;
+}
+
+export function AccountPlaceholder({ icon, title, description }: Props) {
+ return (
+
+
+
+ {title}
+
+
+ {description}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ title: {
+ marginTop: Spacing.xl,
+ marginBottom: Spacing.xs
+ },
+ description: {
+ maxWidth: '50%'
+ }
+});
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
new file mode 100644
index 000000000..9ed0ec60c
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -0,0 +1,11 @@
+import { AccountPlaceholder } from '../w3m-account-placeholder';
+
+export function AccountTokens() {
+ return (
+
+ );
+}
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
new file mode 100644
index 000000000..1cb73c0e9
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -0,0 +1,61 @@
+import { View } from 'react-native';
+import { FlexView, IconLink, Tabs, Text } from '@web3modal/ui-react-native';
+import styles from './styles';
+import { useState } from 'react';
+import { AccountNfts } from '../w3m-account-nfts';
+import { AccountActivity } from '../w3m-account-activity';
+import { AccountTokens } from '../w3m-account-tokens';
+
+export interface AccountWalletFeaturesProps {
+ value: string;
+}
+
+export function AccountWalletFeatures() {
+ const [activeTab, setActiveTab] = useState(0);
+
+ const onTabChange = (index: number) => {
+ setActiveTab(index);
+ };
+
+ return (
+
+
+ $4798
+
+ .75
+
+
+
+
+
+
+
+
+ {activeTab === 0 && }
+ {activeTab === 1 && }
+ {activeTab === 2 && }
+
+
+ );
+}
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
new file mode 100644
index 000000000..80388b3c2
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
@@ -0,0 +1,21 @@
+import { Spacing } from '@web3modal/ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ container: {
+ alignItems: 'center'
+ },
+ balanceText: {
+ fontSize: 40,
+ fontWeight: '500'
+ },
+ actionsContainer: {
+ width: '100%',
+ marginTop: Spacing.s,
+ marginBottom: Spacing.l
+ },
+ action: {
+ flex: 1,
+ height: 52
+ }
+});
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index ec120b185..c4cc1a9a5 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -18,6 +18,7 @@ export function Header() {
return {
Connect: 'Connect wallet',
Account: undefined,
+ AccountSettings: undefined,
ConnectingWalletConnect: walletName ?? 'WalletConnect',
ConnectingExternal: connectorName ?? 'Connect wallet',
ConnectingSiwe: 'Sign In',
diff --git a/packages/scaffold/src/views/w3m-account-view/components/upgrade-wallet-button.tsx b/packages/scaffold/src/views/w3m-account-settings-view/components/upgrade-wallet-button.tsx
similarity index 100%
rename from packages/scaffold/src/views/w3m-account-view/components/upgrade-wallet-button.tsx
rename to packages/scaffold/src/views/w3m-account-settings-view/components/upgrade-wallet-button.tsx
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/index.tsx b/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
new file mode 100644
index 000000000..a486e61ea
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
@@ -0,0 +1,200 @@
+import { useSnapshot } from 'valtio';
+import { useState } from 'react';
+import { Linking, ScrollView } from 'react-native';
+import {
+ AccountController,
+ ApiController,
+ AssetUtil,
+ ConnectionController,
+ ConnectorController,
+ CoreHelperUtil,
+ EventsController,
+ ModalController,
+ NetworkController,
+ OptionsController,
+ RouterController,
+ SnackController,
+ type W3mFrameProvider
+} from '@web3modal/core-react-native';
+import {
+ Avatar,
+ Button,
+ FlexView,
+ IconLink,
+ Text,
+ UiUtil,
+ Spacing,
+ ListItem
+} from '@web3modal/ui-react-native';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import { UpgradeWalletButton } from './components/upgrade-wallet-button';
+import styles from './styles';
+
+export function AccountSettingsView() {
+ const { address, profileName, profileImage, balance, balanceSymbol, addressExplorerUrl } =
+ useSnapshot(AccountController.state);
+ const [disconnecting, setDisconnecting] = useState(false);
+ const { caipNetwork } = useSnapshot(NetworkController.state);
+ const { connectedConnector } = useSnapshot(ConnectorController.state);
+ const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+ const showCopy = OptionsController.isClipboardAvailable();
+ const isEmail = connectedConnector === 'EMAIL';
+ const { padding } = useCustomDimensions();
+
+ async function onDisconnect() {
+ try {
+ setDisconnecting(true);
+ await ConnectionController.disconnect();
+ AccountController.setIsConnected(false);
+ ModalController.close();
+ setDisconnecting(false);
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'DISCONNECT_SUCCESS'
+ });
+ } catch (error) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'DISCONNECT_ERROR'
+ });
+ }
+ }
+
+ const onExplorerPress = () => {
+ if (addressExplorerUrl) {
+ Linking.openURL(addressExplorerUrl);
+ }
+ };
+
+ const onCopyAddress = () => {
+ if (address) {
+ OptionsController.copyToClipboard(profileName ?? address);
+ SnackController.showSuccess('Address copied');
+ }
+ };
+
+ const onNetworkPress = () => {
+ RouterController.push('Networks');
+
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'CLICK_NETWORKS'
+ });
+ };
+
+ const onUpgradePress = () => {
+ EventsController.sendEvent({ type: 'track', event: 'EMAIL_UPGRADE_FROM_MODAL' });
+ RouterController.push('UpgradeEmailWallet');
+ };
+
+ const getUserEmail = () => {
+ const provider = ConnectorController.getEmailConnector()?.provider as W3mFrameProvider;
+ if (!provider) return '';
+
+ return provider.getEmail();
+ };
+
+ const addressExplorerTemplate = () => {
+ if (!addressExplorerUrl) return null;
+
+ return (
+
+ );
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ {profileName
+ ? UiUtil.getTruncateString({
+ string: profileName,
+ charsStart: 20,
+ charsEnd: 0,
+ truncate: 'end'
+ })
+ : UiUtil.getTruncateString({
+ string: address ?? '',
+ charsStart: 4,
+ charsEnd: 6,
+ truncate: 'middle'
+ })}
+
+ {showCopy && (
+
+ )}
+
+ {balance && (
+
+ {CoreHelperUtil.formatBalance(balance, balanceSymbol)}
+
+ )}
+ {addressExplorerTemplate()}
+
+ {isEmail && (
+ <>
+
+
+ RouterController.push('UpdateEmailWallet', { email: getUserEmail() })
+ }
+ chevron
+ testID="button-email"
+ >
+ {getUserEmail()}
+
+ >
+ )}
+
+
+ {caipNetwork?.name}
+
+
+
+ Disconnect
+
+
+
+
+ >
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/styles.ts b/packages/scaffold/src/views/w3m-account-settings-view/styles.ts
new file mode 100644
index 000000000..9aadd0d31
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-account-settings-view/styles.ts
@@ -0,0 +1,21 @@
+import { Spacing } from '@web3modal/ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ closeIcon: {
+ alignSelf: 'flex-end',
+ position: 'absolute',
+ zIndex: 1,
+ top: Spacing.l,
+ right: Spacing.xl
+ },
+ copyButton: {
+ marginLeft: Spacing['4xs']
+ },
+ networkButton: {
+ marginVertical: Spacing.xs
+ },
+ upgradeButton: {
+ marginBottom: Spacing.s
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index 0a6487910..498c5bfd4 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -1,200 +1,38 @@
import { useSnapshot } from 'valtio';
-import { useState } from 'react';
-import { Linking, ScrollView } from 'react-native';
+import { FlexView, Icon, IconLink, NetworkButton, useTheme } from '@web3modal/ui-react-native';
import {
- AccountController,
ApiController,
AssetUtil,
- ConnectionController,
- ConnectorController,
- CoreHelperUtil,
- EventsController,
ModalController,
NetworkController,
- OptionsController,
- RouterController,
- SnackController,
- type W3mFrameProvider
+ RouterController
} from '@web3modal/core-react-native';
-import {
- Avatar,
- Button,
- FlexView,
- IconLink,
- Text,
- UiUtil,
- Spacing,
- ListItem
-} from '@web3modal/ui-react-native';
-import { useCustomDimensions } from '../../hooks/useCustomDimensions';
-import { UpgradeWalletButton } from './components/upgrade-wallet-button';
+import { AccountWalletFeatures } from '../../partials/w3m-account-wallet-features';
import styles from './styles';
export function AccountView() {
- const { address, profileName, profileImage, balance, balanceSymbol, addressExplorerUrl } =
- useSnapshot(AccountController.state);
- const [disconnecting, setDisconnecting] = useState(false);
+ const Theme = useTheme();
const { caipNetwork } = useSnapshot(NetworkController.state);
- const { connectedConnector } = useSnapshot(ConnectorController.state);
- const networkImage = AssetUtil.getNetworkImage(caipNetwork);
- const showCopy = OptionsController.isClipboardAvailable();
- const isEmail = connectedConnector === 'EMAIL';
- const { padding } = useCustomDimensions();
-
- async function onDisconnect() {
- try {
- setDisconnecting(true);
- await ConnectionController.disconnect();
- AccountController.setIsConnected(false);
- ModalController.close();
- setDisconnecting(false);
- EventsController.sendEvent({
- type: 'track',
- event: 'DISCONNECT_SUCCESS'
- });
- } catch (error) {
- EventsController.sendEvent({
- type: 'track',
- event: 'DISCONNECT_ERROR'
- });
- }
- }
-
- const onExplorerPress = () => {
- if (addressExplorerUrl) {
- Linking.openURL(addressExplorerUrl);
- }
- };
-
- const onCopyAddress = () => {
- if (address) {
- OptionsController.copyToClipboard(profileName ?? address);
- SnackController.showSuccess('Address copied');
- }
- };
const onNetworkPress = () => {
RouterController.push('Networks');
-
- EventsController.sendEvent({
- type: 'track',
- event: 'CLICK_NETWORKS'
- });
- };
-
- const onUpgradePress = () => {
- EventsController.sendEvent({ type: 'track', event: 'EMAIL_UPGRADE_FROM_MODAL' });
- RouterController.push('UpgradeEmailWallet');
- };
-
- const getUserEmail = () => {
- const provider = ConnectorController.getEmailConnector()?.provider as W3mFrameProvider;
- if (!provider) return '';
-
- return provider.getEmail();
- };
-
- const addressExplorerTemplate = () => {
- if (!addressExplorerUrl) return null;
-
- return (
-
- );
};
return (
<>
+
+
+
-
-
-
-
-
- {profileName
- ? UiUtil.getTruncateString({
- string: profileName,
- charsStart: 20,
- charsEnd: 0,
- truncate: 'end'
- })
- : UiUtil.getTruncateString({
- string: address ?? '',
- charsStart: 4,
- charsEnd: 6,
- truncate: 'middle'
- })}
-
- {showCopy && (
-
- )}
-
- {balance && (
-
- {CoreHelperUtil.formatBalance(balance, balanceSymbol)}
-
- )}
- {addressExplorerTemplate()}
-
- {isEmail && (
- <>
-
-
- RouterController.push('UpdateEmailWallet', { email: getUserEmail() })
- }
- chevron
- testID="button-email"
- >
- {getUserEmail()}
-
- >
- )}
-
-
- {caipNetwork?.name}
-
-
-
- Disconnect
-
-
-
-
+
+
+
>
);
}
diff --git a/packages/scaffold/src/views/w3m-account-view/styles.ts b/packages/scaffold/src/views/w3m-account-view/styles.ts
index 9aadd0d31..f373bdaa8 100644
--- a/packages/scaffold/src/views/w3m-account-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-account-view/styles.ts
@@ -2,20 +2,18 @@ import { Spacing } from '@web3modal/ui-react-native';
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
+ networkIcon: {
+ alignSelf: 'flex-start',
+ position: 'absolute',
+ zIndex: 1,
+ top: Spacing.l,
+ left: Spacing.l
+ },
closeIcon: {
alignSelf: 'flex-end',
position: 'absolute',
zIndex: 1,
top: Spacing.l,
right: Spacing.xl
- },
- copyButton: {
- marginLeft: Spacing['4xs']
- },
- networkButton: {
- marginVertical: Spacing.xs
- },
- upgradeButton: {
- marginBottom: Spacing.s
}
});
diff --git a/packages/ui/src/assets/svg/ArrowBottomCircle.tsx b/packages/ui/src/assets/svg/ArrowBottomCircle.tsx
new file mode 100644
index 000000000..4f19838a7
--- /dev/null
+++ b/packages/ui/src/assets/svg/ArrowBottomCircle.tsx
@@ -0,0 +1,12 @@
+import Svg, { Path, type SvgProps } from 'react-native-svg';
+const SvgArrowBottomCircle = (props: SvgProps) => (
+
+);
+export default SvgArrowBottomCircle;
diff --git a/packages/ui/src/assets/svg/Paperplane.tsx b/packages/ui/src/assets/svg/Paperplane.tsx
new file mode 100644
index 000000000..131e45f28
--- /dev/null
+++ b/packages/ui/src/assets/svg/Paperplane.tsx
@@ -0,0 +1,12 @@
+import Svg, { Path, type SvgProps } from 'react-native-svg';
+const SvgPaperplane = (props: SvgProps) => (
+
+);
+export default SvgPaperplane;
diff --git a/packages/ui/src/components/wui-icon/index.tsx b/packages/ui/src/components/wui-icon/index.tsx
index d34d7c9e7..f587e8628 100644
--- a/packages/ui/src/components/wui-icon/index.tsx
+++ b/packages/ui/src/components/wui-icon/index.tsx
@@ -5,6 +5,7 @@ import type { ColorType, IconType, SizeType, ThemeKeys } from '../../utils/Types
import AllWalletsSvg from '../../assets/svg/AllWallets';
import AppleSvg from '../../assets/svg/Apple';
import ArrowBottomSvg from '../../assets/svg/ArrowBottom';
+import ArrowBottomCircleSvg from '../../assets/svg/ArrowBottomCircle';
import ArrowLeftSvg from '../../assets/svg/ArrowLeft';
import ArrowRightSvg from '../../assets/svg/ArrowRight';
import ArrowTopSvg from '../../assets/svg/ArrowTop';
@@ -39,6 +40,7 @@ import MobileSvg from '../../assets/svg/Mobile';
import NetworkPlaceholderSvg from '../../assets/svg/NetworkPlaceholder';
import NftPlaceholderSvg from '../../assets/svg/NftPlaceholder';
import OffSvg from '../../assets/svg/Off';
+import PaperplaneSvg from '../../assets/svg/Paperplane';
import QrCodeSvg from '../../assets/svg/QrCode';
import RefreshSvg from '../../assets/svg/Refresh';
import SearchSvg from '../../assets/svg/Search';
@@ -61,6 +63,7 @@ const svgOptions: Record JSX.Element> = {
allWallets: AllWalletsSvg,
apple: AppleSvg,
arrowBottom: ArrowBottomSvg,
+ arrowBottomCircle: ArrowBottomCircleSvg,
arrowLeft: ArrowLeftSvg,
arrowRight: ArrowRightSvg,
arrowTop: ArrowTopSvg,
@@ -95,6 +98,7 @@ const svgOptions: Record JSX.Element> = {
networkPlaceholder: NetworkPlaceholderSvg,
nftPlaceholder: NftPlaceholderSvg,
off: OffSvg,
+ paperplane: PaperplaneSvg,
qrCode: QrCodeSvg,
refresh: RefreshSvg,
search: SearchSvg,
diff --git a/packages/ui/src/composites/wui-network-button/index.tsx b/packages/ui/src/composites/wui-network-button/index.tsx
index 11fe94841..b85600782 100644
--- a/packages/ui/src/composites/wui-network-button/index.tsx
+++ b/packages/ui/src/composites/wui-network-button/index.tsx
@@ -1,4 +1,4 @@
-import { Animated, Pressable, type StyleProp, type ViewStyle } from 'react-native';
+import { Animated, Pressable, View, type StyleProp, type ViewStyle } from 'react-native';
import { Image } from '../../components/wui-image';
import { Text } from '../../components/wui-text';
import { useTheme } from '../../hooks/useTheme';
@@ -11,37 +11,40 @@ import { LoadingSpinner } from '../../components/wui-loading-spinner';
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
export interface NetworkButtonProps {
- children: string;
+ children: string | React.ReactNode;
onPress: () => void;
+ background?: boolean;
+ disabled?: boolean;
imageSrc?: string;
imageHeaders?: Record;
- disabled?: boolean;
- style?: StyleProp;
loading?: boolean;
+ style?: StyleProp;
}
export function NetworkButton({
+ children,
+ onPress,
+ background = true,
+ disabled,
imageSrc,
imageHeaders,
- disabled,
- onPress,
- style,
loading,
- children
+ style
}: NetworkButtonProps) {
const Theme = useTheme();
const textColor = disabled ? 'fg-300' : 'fg-100';
const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
- Theme['gray-glass-005'],
+ background ? Theme['gray-glass-005'] : 'transparent',
Theme['gray-glass-010']
);
const backgroundColor = disabled ? Theme['gray-glass-015'] : animatedValue;
+ const borderColor = background ? Theme['gray-glass-005'] : 'transparent';
return (
-
- {children}
-
+ {typeof children === 'string' ? (
+
+ {children}
+
+ ) : (
+ {children}
+ )}
);
}
diff --git a/packages/ui/src/composites/wui-network-button/styles.ts b/packages/ui/src/composites/wui-network-button/styles.ts
index eb36d0188..cdc38c9b9 100644
--- a/packages/ui/src/composites/wui-network-button/styles.ts
+++ b/packages/ui/src/composites/wui-network-button/styles.ts
@@ -11,7 +11,7 @@ export default StyleSheet.create({
borderRadius: 100,
paddingHorizontal: Spacing['2xs']
},
- text: {
+ children: {
paddingHorizontal: Spacing['2xs']
},
loader: {
diff --git a/packages/ui/src/composites/wui-tabs/index.tsx b/packages/ui/src/composites/wui-tabs/index.tsx
index f71114cb3..7514e823b 100644
--- a/packages/ui/src/composites/wui-tabs/index.tsx
+++ b/packages/ui/src/composites/wui-tabs/index.tsx
@@ -1,5 +1,12 @@
import { useRef, useState } from 'react';
-import { Animated, Pressable, View } from 'react-native';
+import {
+ Animated,
+ Pressable,
+ View,
+ type LayoutChangeEvent,
+ type StyleProp,
+ type ViewStyle
+} from 'react-native';
import { Icon } from '../../components/wui-icon';
import { Text } from '../../components/wui-text';
import { useTheme } from '../../hooks/useTheme';
@@ -8,13 +15,16 @@ import styles from './styles';
export interface TabsProps {
onTabChange: (index: number) => void;
- tabs: TabOptionType[];
+ tabs: TabOptionType[] | string[];
+ style?: StyleProp;
}
-export function Tabs({ tabs, onTabChange }: TabsProps) {
+export function Tabs({ tabs, onTabChange, style }: TabsProps) {
const Theme = useTheme();
const [activeTab, setActiveTab] = useState(0);
const animatedPosition = useRef(new Animated.Value(0));
+ const [viewWidth, setViewWidth] = useState(1);
+ const tabWidth = Math.trunc(viewWidth / tabs.length) - 2;
const onTabPress = (index: number) => {
setActiveTab(index);
@@ -28,27 +38,41 @@ export function Tabs({ tabs, onTabChange }: TabsProps) {
const markPosition = animatedPosition.current.interpolate({
inputRange: [0, tabs.length - 1],
- outputRange: [0, 100 * (tabs.length - 1)]
+ outputRange: [0, tabWidth * (tabs.length - 1)]
});
+ const onLayout = (event: LayoutChangeEvent) => {
+ const { width } = event.nativeEvent.layout;
+ setViewWidth(width);
+ };
+
return (
-
+
{tabs.map((option, index) => {
const isActive = index === activeTab;
+ const isString = typeof option === 'string';
return (
- onTabPress(index)} key={option.label} style={styles.tabItem}>
- {option.icon && (
+ onTabPress(index)}
+ key={isString ? option : option.label}
+ style={[styles.tabItem, { width: tabWidth }]}
+ >
+ {!isString && option.icon && (
)}
- {option.label}
+ {isString ? option : option.label}
);
diff --git a/packages/ui/src/composites/wui-tabs/styles.ts b/packages/ui/src/composites/wui-tabs/styles.ts
index 7d1dca5de..6a81b4fb3 100644
--- a/packages/ui/src/composites/wui-tabs/styles.ts
+++ b/packages/ui/src/composites/wui-tabs/styles.ts
@@ -4,6 +4,7 @@ import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
export default StyleSheet.create({
container: {
height: 34,
+ width: '100%',
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: Spacing['3xs'],
@@ -13,7 +14,6 @@ export default StyleSheet.create({
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
- width: 100,
paddingVertical: Spacing['2xs']
},
tabIcon: {
@@ -22,7 +22,6 @@ export default StyleSheet.create({
activeMark: {
position: 'absolute',
height: 28,
- width: 100,
borderWidth: 1,
borderRadius: BorderRadius['3xl'],
margin: Spacing['3xs']
diff --git a/packages/ui/src/utils/TypesUtil.ts b/packages/ui/src/utils/TypesUtil.ts
index 10a14ff0c..5bfe456ee 100644
--- a/packages/ui/src/utils/TypesUtil.ts
+++ b/packages/ui/src/utils/TypesUtil.ts
@@ -91,6 +91,7 @@ export type ColorType =
| 'error-100'
| 'fg-100'
| 'fg-150'
+ | 'fg-175'
| 'fg-200'
| 'fg-250'
| 'fg-275'
@@ -112,6 +113,7 @@ export type IconType =
| 'allWallets'
| 'apple'
| 'arrowBottom'
+ | 'arrowBottomCircle'
| 'arrowLeft'
| 'arrowRight'
| 'arrowTop'
@@ -146,6 +148,7 @@ export type IconType =
| 'networkPlaceholder'
| 'nftPlaceholder'
| 'off'
+ | 'paperplane'
| 'qrCode'
| 'refresh'
| 'search'
@@ -193,7 +196,7 @@ export type CardSelectType = 'wallet' | 'network';
export type TabOptionType = {
icon: IconType;
- label: string;
+ label?: string;
};
export type SpacingType =
From 74d0a6d225fb4a0671560d170bc46a4121bda0bb Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 6 Aug 2024 15:20:12 -0300
Subject: [PATCH 002/114] chore: new account screen ui
---
.../w3m-account-wallet-features/index.tsx | 8 +--
.../w3m-account-wallet-features/styles.ts | 9 +++
.../views/w3m-account-settings-view/index.tsx | 5 ++
.../views/w3m-account-settings-view/styles.ts | 7 ++
.../src/views/w3m-account-view/index.tsx | 34 ++++++++-
.../src/views/w3m-account-view/styles.ts | 4 ++
.../partials/w3m-connecting-siwe/styles.ts | 7 +-
.../composites/wui-account-button/styles.ts | 8 +--
.../src/composites/wui-account-pill/index.tsx | 72 +++++++++++++++++++
.../src/composites/wui-account-pill/styles.ts | 18 +++++
.../ui/src/composites/wui-avatar/styles.ts | 3 +-
packages/ui/src/composites/wui-chip/styles.ts | 2 +-
.../ui/src/composites/wui-list-item/styles.ts | 4 +-
.../composites/wui-network-button/index.tsx | 4 +-
.../composites/wui-network-button/styles.ts | 6 +-
.../ui/src/composites/wui-snackbar/styles.ts | 3 +-
packages/ui/src/index.ts | 1 +
packages/ui/src/utils/ThemeUtil.ts | 3 +-
18 files changed, 174 insertions(+), 24 deletions(-)
create mode 100644 packages/ui/src/composites/wui-account-pill/index.tsx
create mode 100644 packages/ui/src/composites/wui-account-pill/styles.ts
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index 1cb73c0e9..d4679e1af 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -33,7 +33,7 @@ export function AccountWalletFeatures() {
background
backgroundColor="accent-glass-010"
pressedColor="accent-glass-020"
- style={[styles.action, { marginRight: 8 }]}
+ style={[styles.action, styles.actionLeft]}
/>
{activeTab === 0 && }
{activeTab === 1 && }
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
index 80388b3c2..75c000fb4 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
@@ -17,5 +17,14 @@ export default StyleSheet.create({
action: {
flex: 1,
height: 52
+ },
+ actionLeft: {
+ marginRight: 8
+ },
+ actionRight: {
+ marginLeft: 8
+ },
+ tabContainer: {
+ minHeight: 300
}
});
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/index.tsx b/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
index a486e61ea..30c24a0f7 100644
--- a/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
@@ -36,10 +36,12 @@ export function AccountSettingsView() {
const [disconnecting, setDisconnecting] = useState(false);
const { caipNetwork } = useSnapshot(NetworkController.state);
const { connectedConnector } = useSnapshot(ConnectorController.state);
+ const { history } = useSnapshot(RouterController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
const showCopy = OptionsController.isClipboardAvailable();
const isEmail = connectedConnector === 'EMAIL';
const { padding } = useCustomDimensions();
+ const showBack = history.length > 1;
async function onDisconnect() {
try {
@@ -113,6 +115,9 @@ export function AccountSettingsView() {
return (
<>
+ {showBack && (
+
+ )}
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/styles.ts b/packages/scaffold/src/views/w3m-account-settings-view/styles.ts
index 9aadd0d31..44e6bdea2 100644
--- a/packages/scaffold/src/views/w3m-account-settings-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-account-settings-view/styles.ts
@@ -2,6 +2,13 @@ import { Spacing } from '@web3modal/ui-react-native';
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
+ backIcon: {
+ alignSelf: 'flex-end',
+ position: 'absolute',
+ zIndex: 1,
+ top: Spacing.l,
+ left: Spacing.xl
+ },
closeIcon: {
alignSelf: 'flex-end',
position: 'absolute',
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index 498c5bfd4..9f6ba644a 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -1,11 +1,21 @@
import { useSnapshot } from 'valtio';
-import { FlexView, Icon, IconLink, NetworkButton, useTheme } from '@web3modal/ui-react-native';
import {
+ FlexView,
+ Icon,
+ IconLink,
+ NetworkButton,
+ AccountPill,
+ useTheme
+} from '@web3modal/ui-react-native';
+import {
+ AccountController,
ApiController,
AssetUtil,
ModalController,
NetworkController,
- RouterController
+ OptionsController,
+ RouterController,
+ SnackController
} from '@web3modal/core-react-native';
import { AccountWalletFeatures } from '../../partials/w3m-account-wallet-features';
import styles from './styles';
@@ -13,6 +23,18 @@ import styles from './styles';
export function AccountView() {
const Theme = useTheme();
const { caipNetwork } = useSnapshot(NetworkController.state);
+ const { address, profileName, profileImage } = useSnapshot(AccountController.state);
+
+ const onCopyAddress = (value: string) => {
+ if (value) {
+ OptionsController.copyToClipboard(value);
+ SnackController.showSuccess('Address copied');
+ }
+ };
+
+ const onProfilePress = () => {
+ RouterController.push('AccountSettings');
+ };
const onNetworkPress = () => {
RouterController.push('Networks');
@@ -31,6 +53,14 @@ export function AccountView() {
+
>
diff --git a/packages/scaffold/src/views/w3m-account-view/styles.ts b/packages/scaffold/src/views/w3m-account-view/styles.ts
index f373bdaa8..24d8dc03b 100644
--- a/packages/scaffold/src/views/w3m-account-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-account-view/styles.ts
@@ -15,5 +15,9 @@ export default StyleSheet.create({
zIndex: 1,
top: Spacing.l,
right: Spacing.xl
+ },
+ accountPill: {
+ alignSelf: 'center',
+ marginBottom: Spacing.s
}
});
diff --git a/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/styles.ts b/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/styles.ts
index d7391e1d6..863407547 100644
--- a/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/styles.ts
+++ b/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/styles.ts
@@ -1,10 +1,11 @@
+import { BorderRadius } from '@web3modal/ui-react-native';
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
dappIcon: {
height: 64,
width: 64,
- borderRadius: 100
+ borderRadius: BorderRadius.full
},
iconBorder: {
width: 74,
@@ -13,7 +14,7 @@ export default StyleSheet.create({
justifyContent: 'center'
},
dappBorder: {
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
zIndex: 2
},
walletBorder: {
@@ -22,6 +23,6 @@ export default StyleSheet.create({
height: 72
},
walletAvatar: {
- borderRadius: 100
+ borderRadius: BorderRadius.full
}
});
diff --git a/packages/ui/src/composites/wui-account-button/styles.ts b/packages/ui/src/composites/wui-account-button/styles.ts
index 61f2f0cf1..1eda1c32b 100644
--- a/packages/ui/src/composites/wui-account-button/styles.ts
+++ b/packages/ui/src/composites/wui-account-button/styles.ts
@@ -1,11 +1,11 @@
import { StyleSheet } from 'react-native';
-import { Spacing } from '../../utils/ThemeUtil';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
export default StyleSheet.create({
container: {
flexDirection: 'row',
height: 40,
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
borderWidth: 1,
justifyContent: 'center',
alignItems: 'center',
@@ -14,7 +14,7 @@ export default StyleSheet.create({
image: {
height: 24,
width: 24,
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
borderWidth: 2
},
avatarPlaceholder: {
@@ -35,7 +35,7 @@ export default StyleSheet.create({
alignItems: 'center',
paddingLeft: Spacing['3xs'],
paddingRight: Spacing.xs,
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
borderWidth: 1
},
address: {
diff --git a/packages/ui/src/composites/wui-account-pill/index.tsx b/packages/ui/src/composites/wui-account-pill/index.tsx
new file mode 100644
index 000000000..de157c6f1
--- /dev/null
+++ b/packages/ui/src/composites/wui-account-pill/index.tsx
@@ -0,0 +1,72 @@
+import { Animated, Pressable, type StyleProp, type ViewStyle } from 'react-native';
+import { Avatar } from '../wui-avatar';
+import { UiUtil } from '../../utils/UiUtil';
+import { IconLink } from '../wui-icon-link';
+import { Text } from '../../components/wui-text';
+import useAnimatedValue from '../../hooks/useAnimatedValue';
+import { useTheme } from '../../hooks/useTheme';
+import styles from './styles';
+
+export interface AccountPillProps {
+ onPress: () => void;
+ onCopy: (address: string) => void;
+ address?: string;
+ profileName?: string;
+ profileImage?: string;
+ style?: StyleProp;
+}
+
+const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
+
+export function AccountPill({
+ onPress,
+ onCopy,
+ address,
+ profileName,
+ profileImage,
+ style
+}: AccountPillProps) {
+ const Theme = useTheme();
+
+ const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
+ Theme['gray-glass-005'],
+ Theme['gray-glass-010']
+ );
+
+ const backgroundColor = animatedValue;
+ const borderColor = Theme['gray-glass-005'];
+
+ const handleCopyAddress = () => {
+ if (address) {
+ onCopy(address);
+ }
+ };
+
+ return (
+
+
+
+ {profileName
+ ? UiUtil.getTruncateString({
+ string: profileName,
+ charsStart: 20,
+ charsEnd: 0,
+ truncate: 'end'
+ })
+ : UiUtil.getTruncateString({
+ string: address ?? '',
+ charsStart: 3,
+ charsEnd: 3,
+ truncate: 'middle'
+ })}
+
+
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-account-pill/styles.ts b/packages/ui/src/composites/wui-account-pill/styles.ts
new file mode 100644
index 000000000..e1a3df8d5
--- /dev/null
+++ b/packages/ui/src/composites/wui-account-pill/styles.ts
@@ -0,0 +1,18 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
+
+export default StyleSheet.create({
+ container: {
+ height: 44,
+ width: 160,
+ paddingLeft: Spacing.xs,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderRadius: BorderRadius.full,
+ borderWidth: 1
+ },
+ text: {
+ marginLeft: Spacing['2xs']
+ }
+});
diff --git a/packages/ui/src/composites/wui-avatar/styles.ts b/packages/ui/src/composites/wui-avatar/styles.ts
index b16828ba5..d3da925f9 100644
--- a/packages/ui/src/composites/wui-avatar/styles.ts
+++ b/packages/ui/src/composites/wui-avatar/styles.ts
@@ -1,7 +1,8 @@
import { StyleSheet } from 'react-native';
+import { BorderRadius } from '../../utils/ThemeUtil';
export default StyleSheet.create({
image: {
- borderRadius: 100
+ borderRadius: BorderRadius.full
}
});
diff --git a/packages/ui/src/composites/wui-chip/styles.ts b/packages/ui/src/composites/wui-chip/styles.ts
index 5aad88507..1d7552b2e 100644
--- a/packages/ui/src/composites/wui-chip/styles.ts
+++ b/packages/ui/src/composites/wui-chip/styles.ts
@@ -68,7 +68,7 @@ export default StyleSheet.create({
borderWidth: 1
},
image: {
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
borderWidth: 1
},
smImage: {
diff --git a/packages/ui/src/composites/wui-list-item/styles.ts b/packages/ui/src/composites/wui-list-item/styles.ts
index 4e12fe622..5c9e20768 100644
--- a/packages/ui/src/composites/wui-list-item/styles.ts
+++ b/packages/ui/src/composites/wui-list-item/styles.ts
@@ -18,7 +18,7 @@ export default StyleSheet.create({
imageContainer: {
width: 36,
height: 36,
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
borderWidth: 2,
alignItems: 'center',
justifyContent: 'center'
@@ -26,7 +26,7 @@ export default StyleSheet.create({
image: {
width: 32,
height: 32,
- borderRadius: 100
+ borderRadius: BorderRadius.full
},
disabledImage: {
opacity: 0.4
diff --git a/packages/ui/src/composites/wui-network-button/index.tsx b/packages/ui/src/composites/wui-network-button/index.tsx
index b85600782..b5c37a01a 100644
--- a/packages/ui/src/composites/wui-network-button/index.tsx
+++ b/packages/ui/src/composites/wui-network-button/index.tsx
@@ -3,10 +3,10 @@ import { Image } from '../../components/wui-image';
import { Text } from '../../components/wui-text';
import { useTheme } from '../../hooks/useTheme';
import { IconBox } from '../wui-icon-box';
+import { LoadingSpinner } from '../../components/wui-loading-spinner';
+import useAnimatedValue from '../../hooks/useAnimatedValue';
import styles from './styles';
-import useAnimatedValue from '../../hooks/useAnimatedValue';
-import { LoadingSpinner } from '../../components/wui-loading-spinner';
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
diff --git a/packages/ui/src/composites/wui-network-button/styles.ts b/packages/ui/src/composites/wui-network-button/styles.ts
index cdc38c9b9..199f2d29b 100644
--- a/packages/ui/src/composites/wui-network-button/styles.ts
+++ b/packages/ui/src/composites/wui-network-button/styles.ts
@@ -1,5 +1,5 @@
import { StyleSheet } from 'react-native';
-import { Spacing } from '../../utils/ThemeUtil';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
export default StyleSheet.create({
container: {
@@ -8,7 +8,7 @@ export default StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
paddingHorizontal: Spacing['2xs']
},
children: {
@@ -20,7 +20,7 @@ export default StyleSheet.create({
image: {
height: 24,
width: 24,
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
borderWidth: 2,
paddingLeft: Spacing['4xs']
},
diff --git a/packages/ui/src/composites/wui-snackbar/styles.ts b/packages/ui/src/composites/wui-snackbar/styles.ts
index 1ef657b09..23c1b9bae 100644
--- a/packages/ui/src/composites/wui-snackbar/styles.ts
+++ b/packages/ui/src/composites/wui-snackbar/styles.ts
@@ -1,11 +1,12 @@
import { StyleSheet } from 'react-native';
+import { BorderRadius } from '../../utils/ThemeUtil';
export default StyleSheet.create({
container: {
height: 40,
flexDirection: 'row',
paddingHorizontal: 8,
- borderRadius: 100,
+ borderRadius: BorderRadius.full,
borderWidth: 1,
alignItems: 'center'
},
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 00c9a3ccf..e36caeebb 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -9,6 +9,7 @@ export { Visual, type VisualProps } from './components/wui-visual';
export { Shimmer, type ShimmerProps } from './components/wui-shimmer';
export { AccountButton, type AccountButtonProps } from './composites/wui-account-button';
+export { AccountPill, type AccountPillProps } from './composites/wui-account-pill';
export { ActionEntry, type ActionEntryProps } from './composites/wui-action-entry';
export { Avatar, type AvatarProps } from './composites/wui-avatar';
export { Button, type ButtonProps } from './composites/wui-button';
diff --git a/packages/ui/src/utils/ThemeUtil.ts b/packages/ui/src/utils/ThemeUtil.ts
index 5fa3e4fb4..9c3fbcd7b 100644
--- a/packages/ui/src/utils/ThemeUtil.ts
+++ b/packages/ui/src/utils/ThemeUtil.ts
@@ -155,7 +155,8 @@ export const BorderRadius = {
's': 20,
'm': 28,
'l': 36,
- '3xl': 80
+ '3xl': 80,
+ 'full': 100
};
export const IconSize = {
From 072c32698a4621368a651e1244fe31564c3cf4dc Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 6 Aug 2024 16:32:57 -0300
Subject: [PATCH 003/114] chore: show balance in account screen
---
packages/common/src/index.ts | 1 +
packages/common/src/utils/TypeUtil.ts | 15 ++++++++
.../controllers/AccountController.test.ts | 9 +++--
.../core/src/controllers/AccountController.ts | 36 ++++++++++++++++++-
.../controllers/BlockchainApiController.ts | 19 ++++++++++
packages/core/src/utils/CoreHelperUtil.ts | 18 +++++++++-
packages/core/src/utils/TypeUtil.ts | 6 ++++
.../w3m-account-wallet-features/index.tsx | 18 +++++-----
.../src/views/w3m-account-view/index.tsx | 5 +++
.../src/composites/wui-account-pill/index.tsx | 6 ++--
.../src/composites/wui-account-pill/styles.ts | 3 +-
.../ui/src/composites/wui-balance/index.tsx | 25 +++++++++++++
packages/ui/src/index.ts | 1 +
13 files changed, 145 insertions(+), 17 deletions(-)
create mode 100644 packages/common/src/utils/TypeUtil.ts
create mode 100644 packages/ui/src/composites/wui-balance/index.tsx
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index f27beb61e..96562da67 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -1,2 +1,3 @@
export { ConstantsUtil } from './utils/ConstantsUtil';
export { NetworkUtil } from './utils/NetworkUtil';
+export * from './utils/TypeUtil';
diff --git a/packages/common/src/utils/TypeUtil.ts b/packages/common/src/utils/TypeUtil.ts
new file mode 100644
index 000000000..ce2a40aa0
--- /dev/null
+++ b/packages/common/src/utils/TypeUtil.ts
@@ -0,0 +1,15 @@
+export interface Balance {
+ name: string;
+ symbol: string;
+ chainId: string;
+ address?: string;
+ value?: number;
+ price: number;
+ quantity: BalanceQuantity;
+ iconUrl: string;
+}
+
+type BalanceQuantity = {
+ decimals: string;
+ numeric: string;
+};
diff --git a/packages/core/src/__tests__/controllers/AccountController.test.ts b/packages/core/src/__tests__/controllers/AccountController.test.ts
index c309f4755..2398d562a 100644
--- a/packages/core/src/__tests__/controllers/AccountController.test.ts
+++ b/packages/core/src/__tests__/controllers/AccountController.test.ts
@@ -7,10 +7,15 @@ const balanceSymbol = 'ETH';
const profileName = 'john.eth';
const profileImage = 'https://ipfs.com/0x123.png';
+const initialState = {
+ isConnected: false,
+ tokenBalance: []
+};
+
// -- Tests --------------------------------------------------------------------
describe('AccountController', () => {
it('should have valid default state', () => {
- expect(AccountController.state).toEqual({ isConnected: false });
+ expect(AccountController.state).toEqual(initialState);
});
it('should update state correctly on setIsConnected()', () => {
@@ -42,6 +47,6 @@ describe('AccountController', () => {
it('should update state correctly on resetAccount()', () => {
AccountController.resetAccount();
- expect(AccountController.state).toEqual({ isConnected: false });
+ expect(AccountController.state).toEqual(initialState);
});
});
diff --git a/packages/core/src/controllers/AccountController.ts b/packages/core/src/controllers/AccountController.ts
index 2284a2810..bdbcc67c5 100644
--- a/packages/core/src/controllers/AccountController.ts
+++ b/packages/core/src/controllers/AccountController.ts
@@ -3,6 +3,10 @@ import { subscribeKey as subKey } from 'valtio/utils';
import { CoreHelperUtil } from '../utils/CoreHelperUtil';
import type { CaipAddress, ConnectedWalletInfo } from '../utils/TypeUtil';
+import type { Balance } from '@web3modal/common-react-native';
+import { NetworkController } from './NetworkController';
+import { BlockchainApiController } from './BlockchainApiController';
+import { SnackController } from './SnackController';
// -- Types --------------------------------------------- //
export interface AccountControllerState {
@@ -11,6 +15,7 @@ export interface AccountControllerState {
address?: string;
balance?: string;
balanceSymbol?: string;
+ tokenBalance?: Balance[];
profileName?: string;
profileImage?: string;
addressExplorerUrl?: string;
@@ -21,7 +26,8 @@ type StateKey = keyof AccountControllerState;
// -- State --------------------------------------------- //
const state = proxy({
- isConnected: false
+ isConnected: false,
+ tokenBalance: []
});
// -- Controller ---------------------------------------- //
@@ -50,6 +56,10 @@ export const AccountController = {
state.balanceSymbol = balanceSymbol;
},
+ setTokenBalance(tokenBalance: AccountControllerState['tokenBalance']) {
+ state.tokenBalance = tokenBalance;
+ },
+
setProfileName(profileName: AccountControllerState['profileName']) {
state.profileName = profileName;
},
@@ -66,6 +76,29 @@ export const AccountController = {
state.addressExplorerUrl = explorerUrl;
},
+ async fetchTokenBalance() {
+ const chainId = NetworkController.state.caipNetwork?.id;
+ const address = AccountController.state.address;
+
+ try {
+ if (address && chainId) {
+ const response = await BlockchainApiController.getBalance(address, chainId);
+
+ if (!response) {
+ throw new Error('Failed to fetch token balance');
+ }
+
+ const filteredBalances = response.balances.filter(
+ balance => balance.quantity.decimals !== '0'
+ );
+
+ this.setTokenBalance(filteredBalances);
+ }
+ } catch (error) {
+ SnackController.showError('Failed to fetch token balance');
+ }
+ },
+
resetAccount() {
state.isConnected = false;
state.caipAddress = undefined;
@@ -75,5 +108,6 @@ export const AccountController = {
state.profileName = undefined;
state.profileImage = undefined;
state.addressExplorerUrl = undefined;
+ state.tokenBalance = [];
}
};
diff --git a/packages/core/src/controllers/BlockchainApiController.ts b/packages/core/src/controllers/BlockchainApiController.ts
index 3a1165062..6c480489e 100644
--- a/packages/core/src/controllers/BlockchainApiController.ts
+++ b/packages/core/src/controllers/BlockchainApiController.ts
@@ -3,6 +3,7 @@ import { proxy } from 'valtio';
import { CoreHelperUtil } from '../utils/CoreHelperUtil';
import { FetchUtil } from '../utils/FetchUtil';
import type {
+ BlockchainApiBalanceResponse,
BlockchainApiIdentityRequest,
BlockchainApiIdentityResponse
} from '../utils/TypeUtil';
@@ -36,6 +37,24 @@ export const BlockchainApiController = {
});
},
+ async getBalance(address: string, chainId?: string, forceUpdate?: string) {
+ const { sdkType, sdkVersion } = OptionsController.state;
+
+ return state.api.get({
+ path: `/v1/account/${address}/balance`,
+ headers: {
+ 'x-sdk-type': sdkType,
+ 'x-sdk-version': sdkVersion
+ },
+ params: {
+ currency: 'usd',
+ projectId: OptionsController.state.projectId,
+ chainId,
+ forceUpdate
+ }
+ });
+ },
+
setClientId(clientId: string | null) {
state.clientId = clientId;
state.api = new FetchUtil({ baseUrl, clientId });
diff --git a/packages/core/src/utils/CoreHelperUtil.ts b/packages/core/src/utils/CoreHelperUtil.ts
index 781e93942..d1f8feae9 100644
--- a/packages/core/src/utils/CoreHelperUtil.ts
+++ b/packages/core/src/utils/CoreHelperUtil.ts
@@ -1,7 +1,7 @@
/* eslint-disable no-bitwise */
import { Linking, Platform } from 'react-native';
-import { ConstantsUtil as CommonConstants } from '@web3modal/common-react-native';
+import { ConstantsUtil as CommonConstants, type Balance } from '@web3modal/common-react-native';
import { ConstantsUtil } from './ConstantsUtil';
import type { CaipAddress, DataWallet, LinkingRecord } from './TypeUtil';
@@ -223,5 +223,21 @@ export const CoreHelperUtil = {
.catch(reason => ({ status: 'rejected', reason }))
)
);
+ },
+
+ calculateAndFormatBalance(array?: Balance[]) {
+ if (!array || !array.length) {
+ return { dollars: '0', pennies: '00' };
+ }
+
+ let sum = 0;
+ for (const item of array) {
+ sum += item.value ?? 0;
+ }
+
+ const roundedNumber = sum.toFixed(2);
+ const [dollars, pennies] = roundedNumber.split('.');
+
+ return { dollars, pennies };
}
};
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 0cd000e4d..c751e8769 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -1,3 +1,5 @@
+import type { Balance } from '@web3modal/common-react-native';
+
export type CaipAddress = `${string}:${string}:${string}`;
export type CaipNetworkId = `${string}:${string}`;
@@ -113,6 +115,10 @@ export interface BlockchainApiIdentityResponse {
name: string;
}
+export interface BlockchainApiBalanceResponse {
+ balances: Balance[];
+}
+
// -- OptionsController Types ---------------------------------------------------
export interface Token {
address: string;
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index d4679e1af..1e8a63b3a 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -1,10 +1,13 @@
-import { View } from 'react-native';
-import { FlexView, IconLink, Tabs, Text } from '@web3modal/ui-react-native';
-import styles from './styles';
import { useState } from 'react';
+import { useSnapshot } from 'valtio';
+import { View } from 'react-native';
+import { Balance, FlexView, IconLink, Tabs } from '@web3modal/ui-react-native';
+import { AccountController, CoreHelperUtil } from '@web3modal/core-react-native';
+import type { Balance as BalanceType } from '@web3modal/common-react-native';
import { AccountNfts } from '../w3m-account-nfts';
import { AccountActivity } from '../w3m-account-activity';
import { AccountTokens } from '../w3m-account-tokens';
+import styles from './styles';
export interface AccountWalletFeaturesProps {
value: string;
@@ -12,6 +15,8 @@ export interface AccountWalletFeaturesProps {
export function AccountWalletFeatures() {
const [activeTab, setActiveTab] = useState(0);
+ const { tokenBalance } = useSnapshot(AccountController.state);
+ const balance = CoreHelperUtil.calculateAndFormatBalance(tokenBalance as BalanceType[]);
const onTabChange = (index: number) => {
setActiveTab(index);
@@ -19,12 +24,7 @@ export function AccountWalletFeatures() {
return (
-
- $4798
-
- .75
-
-
+
{
+ AccountController.fetchTokenBalance();
+ }, []);
+
return (
<>
diff --git a/packages/ui/src/composites/wui-account-pill/styles.ts b/packages/ui/src/composites/wui-account-pill/styles.ts
index e1a3df8d5..75d118b60 100644
--- a/packages/ui/src/composites/wui-account-pill/styles.ts
+++ b/packages/ui/src/composites/wui-account-pill/styles.ts
@@ -4,7 +4,8 @@ import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
export default StyleSheet.create({
container: {
height: 44,
- width: 160,
+ minWidth: 160,
+ maxWidth: 260,
paddingLeft: Spacing.xs,
flexDirection: 'row',
alignItems: 'center',
diff --git a/packages/ui/src/composites/wui-balance/index.tsx b/packages/ui/src/composites/wui-balance/index.tsx
new file mode 100644
index 000000000..1f4a9a5ef
--- /dev/null
+++ b/packages/ui/src/composites/wui-balance/index.tsx
@@ -0,0 +1,25 @@
+import { StyleSheet } from 'react-native';
+import { Text } from '../../components/wui-text';
+
+export interface BalanceProps {
+ integer?: string;
+ decimal?: string;
+}
+
+export function Balance({ integer = '0', decimal = '00' }: BalanceProps) {
+ return (
+
+ {`$${integer}`}
+
+ {`.${decimal}`}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ text: {
+ fontSize: 40,
+ fontWeight: '500'
+ }
+});
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index e36caeebb..36589043c 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -12,6 +12,7 @@ export { AccountButton, type AccountButtonProps } from './composites/wui-account
export { AccountPill, type AccountPillProps } from './composites/wui-account-pill';
export { ActionEntry, type ActionEntryProps } from './composites/wui-action-entry';
export { Avatar, type AvatarProps } from './composites/wui-avatar';
+export { Balance, type BalanceProps } from './composites/wui-balance';
export { Button, type ButtonProps } from './composites/wui-button';
export {
CardSelectLoader,
From b012080c8622f06b2357372fb781ad3f55da4a74 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 6 Aug 2024 17:24:39 -0300
Subject: [PATCH 004/114] chore: added receive funds button in token tab
---
.../stories/composites/ListItem.stories.tsx | 12 -------
.../composites/NetworkButton.stories.tsx | 12 +------
.../w3m-account-placeholder/index.tsx | 5 ++-
.../src/partials/w3m-account-tokens/index.tsx | 19 ++++++++----
.../w3m-account-wallet-features/index.tsx | 7 +----
.../views/w3m-account-settings-view/index.tsx | 31 +++++++------------
.../ui/src/composites/wui-list-item/index.tsx | 23 +++++++-------
packages/ui/src/utils/TypesUtil.ts | 10 +++++-
8 files changed, 51 insertions(+), 68 deletions(-)
diff --git a/apps/gallery/stories/composites/ListItem.stories.tsx b/apps/gallery/stories/composites/ListItem.stories.tsx
index 9177d919c..8b53f2e77 100644
--- a/apps/gallery/stories/composites/ListItem.stories.tsx
+++ b/apps/gallery/stories/composites/ListItem.stories.tsx
@@ -10,18 +10,10 @@ const meta: Meta = {
imageSrc: {
control: { type: 'text' }
},
- variant: {
- options: ['image', 'icon'],
- control: { type: 'select' }
- },
icon: {
options: iconOptions,
control: { type: 'select' }
},
- iconVariant: {
- options: ['blue', 'overlay'],
- control: { type: 'select' }
- },
disabled: {
control: { type: 'boolean' }
},
@@ -33,10 +25,8 @@ const meta: Meta = {
}
},
args: {
- variant: 'image',
imageSrc: networkImageSrc,
icon: 'swapHorizontal',
- iconVariant: 'blue',
disabled: false,
chevron: true,
loading: false
@@ -50,10 +40,8 @@ export const Default: Story = {
render: (args: any) => (
= {
component: NetworkButton,
argTypes: {
- variant: {
- options: ['fill', 'shade'],
- control: { type: 'select' }
- },
disabled: {
control: { type: 'boolean' }
},
@@ -21,7 +17,6 @@ const meta: Meta = {
}
},
args: {
- variant: 'fill',
disabled: false,
children: 'Ethereum',
imageSrc: networkImageSrc
@@ -33,12 +28,7 @@ type Story = StoryObj;
export const Default: Story = {
render: args => (
- {}}
- >
+ {}}>
{args.children}
)
diff --git a/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx b/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
index 8c0974c9c..0c6eb5b17 100644
--- a/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
@@ -9,7 +9,7 @@ interface Props {
export function AccountPlaceholder({ icon, title, description }: Props) {
return (
-
+
{title}
@@ -22,6 +22,9 @@ export function AccountPlaceholder({ icon, title, description }: Props) {
}
const styles = StyleSheet.create({
+ container: {
+ flex: 1
+ },
title: {
marginTop: Spacing.xl,
marginBottom: Spacing.xs
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index 9ed0ec60c..940d4c757 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,11 +1,18 @@
-import { AccountPlaceholder } from '../w3m-account-placeholder';
+import { useSnapshot } from 'valtio';
+import { AccountController } from '@web3modal/core-react-native';
+import { FlexView, ListItem, Text } from '@web3modal/ui-react-native';
export function AccountTokens() {
return (
-
+
+
+
+ Receive funds
+
+
+ Transfer tokens on your wallet
+
+
+
);
}
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index 1e8a63b3a..7419c01a4 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -46,12 +46,7 @@ export function AccountWalletFeatures() {
/>
-
+
{activeTab === 0 && }
{activeTab === 1 && }
{activeTab === 2 && }
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/index.tsx b/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
index 30c24a0f7..560aed996 100644
--- a/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
@@ -62,6 +62,13 @@ export function AccountSettingsView() {
}
}
+ const getUserEmail = () => {
+ const provider = ConnectorController.getEmailConnector()?.provider as W3mFrameProvider;
+ if (!provider) return '';
+
+ return provider.getEmail();
+ };
+
const onExplorerPress = () => {
if (addressExplorerUrl) {
Linking.openURL(addressExplorerUrl);
@@ -89,11 +96,8 @@ export function AccountSettingsView() {
RouterController.push('UpgradeEmailWallet');
};
- const getUserEmail = () => {
- const provider = ConnectorController.getEmailConnector()?.provider as W3mFrameProvider;
- if (!provider) return '';
-
- return provider.getEmail();
+ const onEmailPress = () => {
+ RouterController.push('UpdateEmailWallet', { email: getUserEmail() });
};
const addressExplorerTemplate = () => {
@@ -158,25 +162,15 @@ export function AccountSettingsView() {
{isEmail && (
<>
-
- RouterController.push('UpdateEmailWallet', { email: getUserEmail() })
- }
- chevron
- testID="button-email"
- >
+
{getUserEmail()}
>
)}
Disconnect
diff --git a/packages/ui/src/composites/wui-list-item/index.tsx b/packages/ui/src/composites/wui-list-item/index.tsx
index 98791b650..ddc177ac5 100644
--- a/packages/ui/src/composites/wui-list-item/index.tsx
+++ b/packages/ui/src/composites/wui-list-item/index.tsx
@@ -5,7 +5,7 @@ import { Image } from '../../components/wui-image';
import { LoadingSpinner } from '../../components/wui-loading-spinner';
import useAnimatedValue from '../../hooks/useAnimatedValue';
import { useTheme } from '../../hooks/useTheme';
-import type { IconType } from '../../utils/TypesUtil';
+import type { ColorType, IconType } from '../../utils/TypesUtil';
import { IconBox } from '../wui-icon-box';
import styles from './styles';
@@ -13,8 +13,9 @@ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
export interface ListItemProps {
icon?: IconType;
- iconVariant?: 'blue' | 'overlay';
- variant?: 'image' | 'icon';
+ iconColor?: ColorType;
+ iconBackgroundColor?: ColorType;
+ iconBorderColor?: ColorType;
imageSrc?: string;
imageHeaders?: Record;
chevron?: boolean;
@@ -29,10 +30,11 @@ export interface ListItemProps {
export function ListItem({
children,
icon,
- variant,
imageSrc,
imageHeaders,
- iconVariant = 'blue',
+ iconColor = 'fg-200',
+ iconBackgroundColor,
+ iconBorderColor = 'gray-glass-005',
chevron,
loading,
disabled,
@@ -47,7 +49,7 @@ export function ListItem({
);
function visualTemplate() {
- if (variant === 'image' && imageSrc) {
+ if (imageSrc) {
return (
);
- } else if (variant === 'icon' && icon) {
- const iconColor = iconVariant === 'blue' ? 'accent-100' : 'fg-200';
- const borderColor = iconVariant === 'blue' ? 'accent-glass-005' : 'gray-glass-005';
-
+ } else if (icon) {
return (
-
+
);
diff --git a/packages/ui/src/utils/TypesUtil.ts b/packages/ui/src/utils/TypesUtil.ts
index 5bfe456ee..3399506f4 100644
--- a/packages/ui/src/utils/TypesUtil.ts
+++ b/packages/ui/src/utils/TypesUtil.ts
@@ -97,9 +97,17 @@ export type ColorType =
| 'fg-275'
| 'fg-300'
| 'gray-glass-020'
+ | 'gray-glass-010'
+ | 'gray-glass-005'
| 'inverse-000'
| 'inverse-100'
- | 'success-100';
+ | 'success-100'
+ | 'teal-100'
+ | 'magenta-100'
+ | 'indigo-100'
+ | 'orange-100'
+ | 'purple-100'
+ | 'yellow-100';
export type SizeType = 'xl' | 'lg' | 'md' | 'sm' | 'xs' | 'xxs';
From 71b6d6f52333ee04927eea99984a66f81434ca93 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 7 Aug 2024 10:51:27 -0300
Subject: [PATCH 005/114] chore: show wallet screen if its email login
---
packages/core/src/controllers/ModalController.ts | 4 +++-
packages/scaffold/src/partials/w3m-account-tokens/index.tsx | 2 --
packages/ui/src/composites/wui-snackbar/index.tsx | 1 +
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/packages/core/src/controllers/ModalController.ts b/packages/core/src/controllers/ModalController.ts
index 3da4daf4c..763079f0d 100644
--- a/packages/core/src/controllers/ModalController.ts
+++ b/packages/core/src/controllers/ModalController.ts
@@ -5,6 +5,7 @@ import { RouterController } from './RouterController';
import { PublicStateController } from './PublicStateController';
import { EventsController } from './EventsController';
import { ApiController } from './ApiController';
+import { ConnectorController } from './ConnectorController';
// -- Types --------------------------------------------- //
export interface ModalControllerState {
@@ -34,7 +35,8 @@ export const ModalController = {
if (options?.view) {
RouterController.reset(options.view);
} else if (AccountController.state.isConnected) {
- RouterController.reset('Account');
+ const isWallet = ConnectorController.state.connectedConnector === 'EMAIL';
+ RouterController.reset(isWallet ? 'Account' : 'AccountSettings');
} else {
RouterController.reset('Connect');
}
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index 940d4c757..57254abeb 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,5 +1,3 @@
-import { useSnapshot } from 'valtio';
-import { AccountController } from '@web3modal/core-react-native';
import { FlexView, ListItem, Text } from '@web3modal/ui-react-native';
export function AccountTokens() {
diff --git a/packages/ui/src/composites/wui-snackbar/index.tsx b/packages/ui/src/composites/wui-snackbar/index.tsx
index de00e6546..299e79e5f 100644
--- a/packages/ui/src/composites/wui-snackbar/index.tsx
+++ b/packages/ui/src/composites/wui-snackbar/index.tsx
@@ -17,6 +17,7 @@ export function Snackbar({ message, iconColor, icon, style }: SnackbarProps) {
return (
Date: Wed, 7 Aug 2024 13:05:40 -0300
Subject: [PATCH 006/114] chore: updated account default view, show wallet view
for email login
---
.../core/src/controllers/ModalController.ts | 2 +-
.../core/src/controllers/RouterController.ts | 2 +-
packages/scaffold/src/index.ts | 2 +-
.../scaffold/src/modal/w3m-router/index.tsx | 6 +--
.../src/partials/w3m-account-tokens/index.tsx | 8 +++-
.../w3m-account-wallet-features/index.tsx | 9 ++++-
.../src/partials/w3m-header/index.tsx | 2 +-
.../components/upgrade-wallet-button.tsx | 0
.../index.tsx | 40 +++++++++----------
.../styles.ts | 0
.../src/views/w3m-account-view/index.tsx | 2 +-
11 files changed, 41 insertions(+), 32 deletions(-)
rename packages/scaffold/src/views/{w3m-account-settings-view => w3m-account-default-view}/components/upgrade-wallet-button.tsx (100%)
rename packages/scaffold/src/views/{w3m-account-settings-view => w3m-account-default-view}/index.tsx (91%)
rename packages/scaffold/src/views/{w3m-account-settings-view => w3m-account-default-view}/styles.ts (100%)
diff --git a/packages/core/src/controllers/ModalController.ts b/packages/core/src/controllers/ModalController.ts
index 763079f0d..5bbc51021 100644
--- a/packages/core/src/controllers/ModalController.ts
+++ b/packages/core/src/controllers/ModalController.ts
@@ -36,7 +36,7 @@ export const ModalController = {
RouterController.reset(options.view);
} else if (AccountController.state.isConnected) {
const isWallet = ConnectorController.state.connectedConnector === 'EMAIL';
- RouterController.reset(isWallet ? 'Account' : 'AccountSettings');
+ RouterController.reset(isWallet ? 'Account' : 'AccountDefault');
} else {
RouterController.reset('Connect');
}
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index 88962e0a5..271bc8cc6 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -5,7 +5,7 @@ import type { WcWallet, CaipNetwork, Connector } from '../utils/TypeUtil';
export interface RouterControllerState {
view:
| 'Account'
- | 'AccountSettings'
+ | 'AccountDefault'
| 'Connect'
| 'ConnectingWalletConnect'
| 'ConnectingExternal'
diff --git a/packages/scaffold/src/index.ts b/packages/scaffold/src/index.ts
index 907b9dc96..e26590664 100644
--- a/packages/scaffold/src/index.ts
+++ b/packages/scaffold/src/index.ts
@@ -5,7 +5,7 @@ export * from './modal/w3m-network-button';
export * from './modal/w3m-modal';
export * from './modal/w3m-router';
-export * from './views/w3m-account-settings-view';
+export * from './views/w3m-account-default-view';
export * from './views/w3m-all-wallets-view';
export * from './views/w3m-connect-view';
export * from './views/w3m-connecting-view';
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index 37f58f0c8..d0dee6a05 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -8,7 +8,7 @@ import { AllWalletsView } from '../../views/w3m-all-wallets-view';
import { ConnectingView } from '../../views/w3m-connecting-view';
import { WhatIsAWalletView } from '../../views/w3m-what-is-a-wallet-view';
import { GetWalletView } from '../../views/w3m-get-wallet-view';
-import { AccountSettingsView } from '../../views/w3m-account-settings-view';
+import { AccountDefaultView } from '../../views/w3m-account-default-view';
import { NetworksView } from '../../views/w3m-networks-view';
import { WhatIsNetworkView } from '../../views/w3m-what-is-a-network-view';
import { NetworkSwitchView } from '../../views/w3m-network-switch-view';
@@ -51,8 +51,8 @@ export function Web3Router() {
return NetworkSwitchView;
case 'Account':
return AccountView;
- case 'AccountSettings':
- return AccountSettingsView;
+ case 'AccountDefault':
+ return AccountDefaultView;
case 'EmailVerifyDevice':
return EmailVerifyDeviceView;
case 'EmailVerifyOtp':
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index 57254abeb..046a1ec63 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,8 +1,14 @@
+import { SnackController } from '@web3modal/core-react-native';
import { FlexView, ListItem, Text } from '@web3modal/ui-react-native';
export function AccountTokens() {
+ // TODO: Implement this feature
+ const onMissingPress = () => {
+ SnackController.showError('Feature not implemented');
+ };
+
return (
-
+
Receive funds
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index 7419c01a4..b7b6f147f 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -2,7 +2,7 @@ import { useState } from 'react';
import { useSnapshot } from 'valtio';
import { View } from 'react-native';
import { Balance, FlexView, IconLink, Tabs } from '@web3modal/ui-react-native';
-import { AccountController, CoreHelperUtil } from '@web3modal/core-react-native';
+import { AccountController, CoreHelperUtil, SnackController } from '@web3modal/core-react-native';
import type { Balance as BalanceType } from '@web3modal/common-react-native';
import { AccountNfts } from '../w3m-account-nfts';
import { AccountActivity } from '../w3m-account-activity';
@@ -22,6 +22,11 @@ export function AccountWalletFeatures() {
setActiveTab(index);
};
+ // TODO: Implement this features
+ const onMissingPress = () => {
+ SnackController.showError('Feature not implemented');
+ };
+
return (
@@ -34,6 +39,7 @@ export function AccountWalletFeatures() {
backgroundColor="accent-glass-010"
pressedColor="accent-glass-020"
style={[styles.action, styles.actionLeft]}
+ onPress={onMissingPress}
/>
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index c4cc1a9a5..82277e295 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -18,7 +18,7 @@ export function Header() {
return {
Connect: 'Connect wallet',
Account: undefined,
- AccountSettings: undefined,
+ AccountDefault: undefined,
ConnectingWalletConnect: walletName ?? 'WalletConnect',
ConnectingExternal: connectorName ?? 'Connect wallet',
ConnectingSiwe: 'Sign In',
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/components/upgrade-wallet-button.tsx b/packages/scaffold/src/views/w3m-account-default-view/components/upgrade-wallet-button.tsx
similarity index 100%
rename from packages/scaffold/src/views/w3m-account-settings-view/components/upgrade-wallet-button.tsx
rename to packages/scaffold/src/views/w3m-account-default-view/components/upgrade-wallet-button.tsx
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/index.tsx b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
similarity index 91%
rename from packages/scaffold/src/views/w3m-account-settings-view/index.tsx
rename to packages/scaffold/src/views/w3m-account-default-view/index.tsx
index 560aed996..5402251ed 100644
--- a/packages/scaffold/src/views/w3m-account-settings-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
@@ -30,7 +30,7 @@ import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import { UpgradeWalletButton } from './components/upgrade-wallet-button';
import styles from './styles';
-export function AccountSettingsView() {
+export function AccountDefaultView() {
const { address, profileName, profileImage, balance, balanceSymbol, addressExplorerUrl } =
useSnapshot(AccountController.state);
const [disconnecting, setDisconnecting] = useState(false);
@@ -40,8 +40,10 @@ export function AccountSettingsView() {
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
const showCopy = OptionsController.isClipboardAvailable();
const isEmail = connectedConnector === 'EMAIL';
- const { padding } = useCustomDimensions();
+ const showBalance = balance && !isEmail;
+ const showExplorer = addressExplorerUrl && !isEmail;
const showBack = history.length > 1;
+ const { padding } = useCustomDimensions();
async function onDisconnect() {
try {
@@ -100,23 +102,6 @@ export function AccountSettingsView() {
RouterController.push('UpdateEmailWallet', { email: getUserEmail() });
};
- const addressExplorerTemplate = () => {
- if (!addressExplorerUrl) return null;
-
- return (
-
- );
- };
-
return (
<>
{showBack && (
@@ -146,18 +131,29 @@ export function AccountSettingsView() {
)}
- {balance && (
+ {showBalance && (
{CoreHelperUtil.formatBalance(balance, balanceSymbol)}
)}
- {addressExplorerTemplate()}
+ {showExplorer && (
+
+ )}
{isEmail && (
<>
diff --git a/packages/scaffold/src/views/w3m-account-settings-view/styles.ts b/packages/scaffold/src/views/w3m-account-default-view/styles.ts
similarity index 100%
rename from packages/scaffold/src/views/w3m-account-settings-view/styles.ts
rename to packages/scaffold/src/views/w3m-account-default-view/styles.ts
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index 86d0934a4..a787b7659 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -34,7 +34,7 @@ export function AccountView() {
};
const onProfilePress = () => {
- RouterController.push('AccountSettings');
+ RouterController.push('AccountDefault');
};
const onNetworkPress = () => {
From a6fad43e6ae2a268acf9500232988c40ae9b9307 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 7 Aug 2024 14:27:42 -0300
Subject: [PATCH 007/114] chore: added changeset
---
.changeset/stupid-guests-turn.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 .changeset/stupid-guests-turn.md
diff --git a/.changeset/stupid-guests-turn.md b/.changeset/stupid-guests-turn.md
new file mode 100644
index 000000000..302af6e20
--- /dev/null
+++ b/.changeset/stupid-guests-turn.md
@@ -0,0 +1,18 @@
+---
+'@web3modal/scaffold-react-native': minor
+'@web3modal/common-react-native': minor
+'@web3modal/email-react-native': minor
+'@web3modal/core-react-native': minor
+'@web3modal/siwe-react-native': minor
+'@web3modal/ui-react-native': minor
+'@web3modal/coinbase-ethers-react-native': minor
+'@web3modal/coinbase-wagmi-react-native': minor
+'@web3modal/email-ethers-react-native': minor
+'@web3modal/email-wagmi-react-native': minor
+'@web3modal/ethers-react-native': minor
+'@web3modal/ethers5-react-native': minor
+'@web3modal/scaffold-utils-react-native': minor
+'@web3modal/wagmi-react-native': minor
+---
+
+feat: implemented wallet features for universal wallets
From 08853cf74a38360569d18b52cb99621ab8b20181 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 7 Aug 2024 17:58:07 -0300
Subject: [PATCH 008/114] chore: limit width of platform tab in connecting view
---
.../partials/w3m-connecting-header/index.tsx | 37 +++++++++++++------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-connecting-header/index.tsx b/packages/scaffold/src/partials/w3m-connecting-header/index.tsx
index 02fc1c59f..2d010293d 100644
--- a/packages/scaffold/src/partials/w3m-connecting-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-connecting-header/index.tsx
@@ -1,22 +1,31 @@
import type { Platform } from '@web3modal/core-react-native';
-import { FlexView, Tabs } from '@web3modal/ui-react-native';
+import { FlexView, Tabs, type IconType } from '@web3modal/ui-react-native';
+import { StyleSheet } from 'react-native';
export interface ConnectingHeaderProps {
platforms: Platform[];
onSelectPlatform: (platform: Platform) => void;
}
+interface Tab {
+ label: string;
+ icon: IconType;
+ platform: Platform;
+}
+
export function ConnectingHeader({ platforms, onSelectPlatform }: ConnectingHeaderProps) {
const generateTabs = () => {
- const tabs = platforms.map(platform => {
- if (platform === 'mobile') {
- return { label: 'Mobile', icon: 'mobile', platform: 'mobile' } as const;
- } else if (platform === 'web') {
- return { label: 'Web', icon: 'browser', platform: 'web' } as const;
- } else {
- return { label: 'QR Code', icon: 'qrCode', platform: 'qrcode' } as const;
- }
- });
+ const tabs = platforms
+ .map(platform => {
+ if (platform === 'mobile') {
+ return { label: 'Mobile', icon: 'mobile', platform: 'mobile' } as const;
+ } else if (platform === 'web') {
+ return { label: 'Web', icon: 'browser', platform: 'web' } as const;
+ } else {
+ return undefined;
+ }
+ })
+ .filter(Boolean) as Tab[];
return tabs;
};
@@ -32,7 +41,13 @@ export function ConnectingHeader({ platforms, onSelectPlatform }: ConnectingHead
return (
-
+
);
}
+
+const styles = StyleSheet.create({
+ tab: {
+ maxWidth: '50%'
+ }
+});
From 0b3d8c056c1e8a566a9c5fc5c59c501edd7ef476 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 8 Aug 2024 16:25:29 -0300
Subject: [PATCH 009/114] feat: wip receive screen
---
.../stories/composites/Chip.stories.tsx | 7 +--
apps/gallery/utils/PresetUtils.ts | 2 -
.../core/src/controllers/OptionsController.ts | 2 +-
.../core/src/controllers/RouterController.ts | 3 +-
.../scaffold/src/modal/w3m-router/index.tsx | 3 +
.../src/partials/w3m-account-tokens/index.tsx | 9 ++-
.../w3m-account-wallet-features/index.tsx | 13 ++++-
.../src/partials/w3m-header/index.tsx | 3 +-
.../src/views/w3m-account-view/index.tsx | 2 +-
.../w3m-upgrade-email-wallet-view/index.tsx | 11 +++-
.../views/w3m-wallet-receive-view/index.tsx | 55 +++++++++++++++++++
.../views/w3m-wallet-receive-view/styles.ts | 8 +++
.../src/composites/wui-account-pill/index.tsx | 2 +-
packages/ui/src/composites/wui-chip/index.tsx | 16 +++---
.../ui/src/composites/wui-qr-code/index.tsx | 23 ++++----
packages/ui/src/utils/UiUtil.ts | 18 ++++++
16 files changed, 136 insertions(+), 41 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-wallet-receive-view/styles.ts
diff --git a/apps/gallery/stories/composites/Chip.stories.tsx b/apps/gallery/stories/composites/Chip.stories.tsx
index ae1768fd7..6cdcfe045 100644
--- a/apps/gallery/stories/composites/Chip.stories.tsx
+++ b/apps/gallery/stories/composites/Chip.stories.tsx
@@ -5,7 +5,6 @@ import { Chip } from '@web3modal/ui-react-native';
import {
chipOptions,
externalLabel,
- externalLink,
iconOptions,
walletImagesOptions
} from '../../utils/PresetUtils';
@@ -24,9 +23,6 @@ const meta: Meta = {
disabled: {
control: { type: 'boolean' }
},
- link: {
- control: { type: 'text' }
- },
label: {
control: { type: 'text' }
},
@@ -43,7 +39,6 @@ const meta: Meta = {
size: 'md',
disabled: false,
icon: 'disconnect',
- link: externalLink,
label: externalLabel,
imageSrc: walletImagesOptions[3]
}
@@ -58,7 +53,7 @@ export const Default: Story = {
variant={args.variant}
size={args.size}
disabled={args.disabled}
- link={args.link}
+ onPress={() => {}}
label={args.label}
imageSrc={args.imageSrc}
icon={args.icon}
diff --git a/apps/gallery/utils/PresetUtils.ts b/apps/gallery/utils/PresetUtils.ts
index 22328477b..8cddbeea7 100644
--- a/apps/gallery/utils/PresetUtils.ts
+++ b/apps/gallery/utils/PresetUtils.ts
@@ -32,8 +32,6 @@ export const avatarImageSrc =
export const wcUri =
'wc:139520827546986d057472f8bbd7ef0484409458034b61cca59d908563773c7a@2?relay-protocol=irn&symKey=43b5fad11bf07bc8a0aa12231435a4ad3e72e2d1fa257cf191a90ec5b62cb0a';
-export const externalLink = 'https://www.fireblocks.com';
-
export const externalLabel = 'www.fireblocks.com';
export const colorOptions: ColorType[] = [
diff --git a/packages/core/src/controllers/OptionsController.ts b/packages/core/src/controllers/OptionsController.ts
index 018867c9d..e590dee3a 100644
--- a/packages/core/src/controllers/OptionsController.ts
+++ b/packages/core/src/controllers/OptionsController.ts
@@ -83,7 +83,7 @@ export const OptionsController = {
copyToClipboard(value: string) {
const client = state._clipboardClient;
if (client) {
- client.setString(value);
+ client?.setString(value);
}
}
};
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index 271bc8cc6..8bbd2531a 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -21,7 +21,8 @@ export interface RouterControllerState {
| 'UpdateEmailPrimaryOtp'
| 'UpdateEmailSecondaryOtp'
| 'UpgradeEmailWallet'
- | 'ConnectingSiwe';
+ | 'ConnectingSiwe'
+ | 'WalletReceive';
history: RouterControllerState['view'][];
data?: {
connector?: Connector;
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index d0dee6a05..8c8759f84 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -21,6 +21,7 @@ import { UpdateEmailPrimaryOtpView } from '../../views/w3m-update-email-primary-
import { UpdateEmailSecondaryOtpView } from '../../views/w3m-update-email-secondary-otp-view';
import { UpgradeEmailWalletView } from '../../views/w3m-upgrade-email-wallet-view';
import { AccountView } from '../../views/w3m-account-view';
+import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
export function Web3Router() {
const { view } = useSnapshot(RouterController.state);
@@ -67,6 +68,8 @@ export function Web3Router() {
return UpgradeEmailWalletView;
case 'ConnectingSiwe':
return ConnectingSiweView;
+ case 'WalletReceive':
+ return WalletReceiveView;
default:
return ConnectView;
}
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index 046a1ec63..6ed3f7af8 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,14 +1,13 @@
-import { SnackController } from '@web3modal/core-react-native';
+import { RouterController } from '@web3modal/core-react-native';
import { FlexView, ListItem, Text } from '@web3modal/ui-react-native';
export function AccountTokens() {
- // TODO: Implement this feature
- const onMissingPress = () => {
- SnackController.showError('Feature not implemented');
+ const onReceivePress = () => {
+ RouterController.push('WalletReceive');
};
return (
-
+
Receive funds
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index b7b6f147f..991beb004 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -2,7 +2,12 @@ import { useState } from 'react';
import { useSnapshot } from 'valtio';
import { View } from 'react-native';
import { Balance, FlexView, IconLink, Tabs } from '@web3modal/ui-react-native';
-import { AccountController, CoreHelperUtil, SnackController } from '@web3modal/core-react-native';
+import {
+ AccountController,
+ CoreHelperUtil,
+ RouterController,
+ SnackController
+} from '@web3modal/core-react-native';
import type { Balance as BalanceType } from '@web3modal/common-react-native';
import { AccountNfts } from '../w3m-account-nfts';
import { AccountActivity } from '../w3m-account-activity';
@@ -27,6 +32,10 @@ export function AccountWalletFeatures() {
SnackController.showError('Feature not implemented');
};
+ const onReceivePress = () => {
+ RouterController.push('WalletReceive');
+ };
+
return (
@@ -39,7 +48,7 @@ export function AccountWalletFeatures() {
backgroundColor="accent-glass-010"
pressedColor="accent-glass-020"
style={[styles.action, styles.actionLeft]}
- onPress={onMissingPress}
+ onPress={onReceivePress}
/>
{
- if (value) {
+ if (OptionsController.isClipboardAvailable() && value) {
OptionsController.copyToClipboard(value);
SnackController.showSuccess('Address copied');
}
diff --git a/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx b/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
index cf425e014..e79f32e05 100644
--- a/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { StyleSheet } from 'react-native';
+import { Linking, StyleSheet } from 'react-native';
import { Chip, FlexView, Spacing, Text } from '@web3modal/ui-react-native';
import { ConnectorController, type W3mFrameProvider } from '@web3modal/core-react-native';
@@ -7,6 +7,13 @@ export function UpgradeEmailWalletView() {
const { connectors } = useSnapshot(ConnectorController.state);
const emailProvider = connectors.find(c => c.type === 'EMAIL')?.provider as W3mFrameProvider;
+ const onLinkPress = () => {
+ const link = emailProvider.getSecureSiteDashboardURL();
+ Linking.canOpenURL(link).then(supported => {
+ if (supported) Linking.openURL(link);
+ });
+ };
+
return (
Follow the instructions on
@@ -14,7 +21,7 @@ export function UpgradeEmailWalletView() {
label="secure.walletconnect.com"
icon="externalLink"
imageSrc={emailProvider.getSecureSiteIconURL()}
- link={emailProvider.getSecureSiteDashboardURL()}
+ onPress={onLinkPress}
style={styles.chip}
/>
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
new file mode 100644
index 000000000..e2560122f
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
@@ -0,0 +1,55 @@
+import { useSnapshot } from 'valtio';
+import { StyleSheet } from 'react-native';
+import { Chip, FlexView, QrCode, Spacing, Text, UiUtil } from '@web3modal/ui-react-native';
+import {
+ AccountController,
+ AssetUtil,
+ NetworkController,
+ OptionsController,
+ SnackController
+} from '@web3modal/core-react-native';
+
+export function WalletReceiveView() {
+ const { address, profileName } = useSnapshot(AccountController.state);
+ const { caipNetwork } = useSnapshot(NetworkController.state);
+ const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+ const canCopy = OptionsController.isClipboardAvailable();
+
+ const label = UiUtil.getTruncateString({
+ string: profileName ?? address ?? '',
+ charsStart: profileName ? 30 : 4,
+ charsEnd: profileName ? 0 : 4,
+ truncate: profileName ? 'end' : 'middle'
+ });
+
+ const onCopyAddress = () => {
+ if (canCopy && address) {
+ OptionsController.copyToClipboard(profileName ?? address);
+ SnackController.showSuccess('Address copied');
+ }
+ };
+
+ if (!address) return;
+
+ return (
+
+
+
+
+ {canCopy ? 'Copy your address or scan this QR code' : 'Scan this QR code'}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ qrContainer: {
+ marginVertical: Spacing.xl
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-receive-view/styles.ts
new file mode 100644
index 000000000..c866ab3d8
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/styles.ts
@@ -0,0 +1,8 @@
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ container: {
+ justifyContent: 'center',
+ alignItems: 'center'
+ }
+});
diff --git a/packages/ui/src/composites/wui-account-pill/index.tsx b/packages/ui/src/composites/wui-account-pill/index.tsx
index bd66cd9cf..07f76d56e 100644
--- a/packages/ui/src/composites/wui-account-pill/index.tsx
+++ b/packages/ui/src/composites/wui-account-pill/index.tsx
@@ -55,7 +55,7 @@ export function AccountPill({
{profileName
? UiUtil.getTruncateString({
string: profileName,
- charsStart: 18,
+ charsStart: 17,
charsEnd: 0,
truncate: 'end'
})
diff --git a/packages/ui/src/composites/wui-chip/index.tsx b/packages/ui/src/composites/wui-chip/index.tsx
index 76b381c0b..ed3764545 100644
--- a/packages/ui/src/composites/wui-chip/index.tsx
+++ b/packages/ui/src/composites/wui-chip/index.tsx
@@ -1,5 +1,5 @@
import { useRef, useState } from 'react';
-import { Animated, Linking, Pressable, type StyleProp, type ViewStyle } from 'react-native';
+import { Animated, Pressable, type StyleProp, type ViewStyle } from 'react-native';
import type { ChipType, ColorType, IconType, SizeType } from '../../utils/TypesUtil';
import { useTheme } from '../../hooks/useTheme';
import { Text } from '../../components/wui-text';
@@ -10,7 +10,6 @@ import styles, { getThemedChipStyle, getThemedTextColor } from './styles';
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
export interface ChipProps {
- link: string;
label?: string;
imageSrc?: string;
icon?: IconType;
@@ -18,10 +17,11 @@ export interface ChipProps {
size?: Exclude;
disabled?: boolean;
style?: StyleProp;
+ onPress?: () => void;
}
export function Chip({
- link,
+ onPress,
imageSrc,
icon,
variant = 'fill',
@@ -38,10 +38,8 @@ export function Chip({
const themedTextColor = getThemedTextColor(variant, disabled, pressed);
const iconSize = size === 'md' ? 'sm' : 'xs';
- const onPress = () => {
- Linking.canOpenURL(link).then(supported => {
- if (supported) Linking.openURL(link);
- });
+ const handlePress = () => {
+ onPress?.();
};
const onPressIn = () => {
@@ -78,7 +76,7 @@ export function Chip({
style={[styles.container, styles[`${size}Chip`], { borderColor, backgroundColor }, style]}
onPressIn={onPressIn}
onPressOut={onPressOut}
- onPress={onPress}
+ onPress={handlePress}
>
{imageSrc && (
- {label || link}
+ {label}
{icon && (
;
}
-export function QrCode({ size, uri, imageSrc, testID }: QrCodeProps) {
+export function QrCode({ size, uri, imageSrc, testID, arenaClear, style }: QrCodeProps) {
const Theme = LightTheme;
const containerPadding = Spacing.l;
const qrSize = size - containerPadding * 2;
const dots = useMemo(
- () => (uri ? QRCodeUtil.generate(uri, qrSize, qrSize / 4) : []),
- [uri, qrSize]
+ () => (uri ? QRCodeUtil.generate(uri, qrSize, arenaClear ? 0 : qrSize / 4) : []),
+ [uri, qrSize, arenaClear]
);
- const shimmerTemplate = () => {
- return ;
- };
-
const logoTemplate = () => {
+ if (arenaClear) {
+ return null;
+ }
+
if (imageSrc) {
return (
@@ -66,6 +69,6 @@ export function QrCode({ size, uri, imageSrc, testID }: QrCodeProps) {
{logoTemplate()}
) : (
- shimmerTemplate()
+
);
}
diff --git a/packages/ui/src/utils/UiUtil.ts b/packages/ui/src/utils/UiUtil.ts
index e4678f6b2..3077dfbfb 100644
--- a/packages/ui/src/utils/UiUtil.ts
+++ b/packages/ui/src/utils/UiUtil.ts
@@ -66,6 +66,24 @@ export const UiUtil = {
)}`;
},
+ getTruncateAddress(address: string, profileName?: string) {
+ if (profileName) {
+ return this.getTruncateString({
+ string: profileName,
+ charsStart: 20,
+ charsEnd: 0,
+ truncate: 'end'
+ });
+ }
+
+ return this.getTruncateString({
+ string: address ?? '',
+ charsStart: 4,
+ charsEnd: 4,
+ truncate: 'middle'
+ });
+ },
+
getWalletName(name: string, short = true) {
return short ? name.split(' ')[0] : name;
}
From 632466814072d96d30e6f4fc3f44329968e40553 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 8 Aug 2024 18:36:17 -0300
Subject: [PATCH 010/114] chore: receive screen
---
.../core/src/controllers/NetworkController.ts | 6 +++
.../views/w3m-wallet-receive-view/index.tsx | 22 ++++++++-
.../wui-compatible-network/index.tsx | 46 +++++++++++++++++++
.../ui/src/composites/wui-list-item/index.tsx | 4 +-
.../ui/src/composites/wui-list-item/styles.ts | 3 +-
.../composites/wui-network-image/index.tsx | 38 +++++++++++----
.../composites/wui-network-image/styles.ts | 3 ++
packages/ui/src/index.ts | 4 ++
packages/ui/src/utils/UiUtil.ts | 18 --------
9 files changed, 113 insertions(+), 31 deletions(-)
create mode 100644 packages/ui/src/composites/wui-compatible-network/index.tsx
diff --git a/packages/core/src/controllers/NetworkController.ts b/packages/core/src/controllers/NetworkController.ts
index f917efa7b..1468cba9f 100644
--- a/packages/core/src/controllers/NetworkController.ts
+++ b/packages/core/src/controllers/NetworkController.ts
@@ -63,6 +63,12 @@ export const NetworkController = {
state.approvedCaipNetworkIds = data.approvedCaipNetworkIds;
},
+ getApprovedCaipNetworks() {
+ return state.approvedCaipNetworkIds
+ ?.map(id => state.requestedCaipNetworks?.find(network => network.id === id))
+ .filter(Boolean) as CaipNetwork[];
+ },
+
async switchActiveNetwork(network: NetworkControllerState['caipNetwork']) {
await this._getClient().switchCaipNetwork(network);
state.caipNetwork = network;
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
index e2560122f..86651810d 100644
--- a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
@@ -1,8 +1,17 @@
import { useSnapshot } from 'valtio';
import { StyleSheet } from 'react-native';
-import { Chip, FlexView, QrCode, Spacing, Text, UiUtil } from '@web3modal/ui-react-native';
+import {
+ Chip,
+ CompatibleNetwork,
+ FlexView,
+ QrCode,
+ Spacing,
+ Text,
+ UiUtil
+} from '@web3modal/ui-react-native';
import {
AccountController,
+ ApiController,
AssetUtil,
NetworkController,
OptionsController,
@@ -14,6 +23,11 @@ export function WalletReceiveView() {
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
const canCopy = OptionsController.isClipboardAvailable();
+ const slicedNetworks =
+ NetworkController.getApprovedCaipNetworks()
+ .filter(network => network?.imageId)
+ ?.slice(0, 5) || [];
+ const imagesArray = slicedNetworks.map(AssetUtil.getNetworkImage).filter(Boolean) as string[];
const label = UiUtil.getTruncateString({
string: profileName ?? address ?? '',
@@ -44,6 +58,12 @@ export function WalletReceiveView() {
{canCopy ? 'Copy your address or scan this QR code' : 'Scan this QR code'}
+ {}}
+ networkImages={imagesArray}
+ imageHeaders={ApiController._getApiHeaders()}
+ />
);
}
diff --git a/packages/ui/src/composites/wui-compatible-network/index.tsx b/packages/ui/src/composites/wui-compatible-network/index.tsx
new file mode 100644
index 000000000..80de42dc5
--- /dev/null
+++ b/packages/ui/src/composites/wui-compatible-network/index.tsx
@@ -0,0 +1,46 @@
+import { Text } from '../../components/wui-text';
+import { NetworkImage } from '../wui-network-image';
+import { FlexView } from '../../layout/wui-flex';
+import { ListItem } from '../wui-list-item';
+import { StyleSheet } from 'react-native';
+
+export interface CompatibleNetworkProps {
+ text: string;
+ onPress: () => void;
+ networkImages: string[];
+ imageHeaders: Record;
+}
+
+export function CompatibleNetwork({
+ text,
+ onPress,
+ networkImages,
+ imageHeaders
+}: CompatibleNetworkProps) {
+ return (
+
+
+ {text}
+
+
+ {networkImages?.map((image, index) => (
+
+ ))}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ height: 48
+ },
+ contentContainer: {
+ flexDirection: 'row'
+ }
+});
diff --git a/packages/ui/src/composites/wui-list-item/index.tsx b/packages/ui/src/composites/wui-list-item/index.tsx
index ddc177ac5..5f9c66818 100644
--- a/packages/ui/src/composites/wui-list-item/index.tsx
+++ b/packages/ui/src/composites/wui-list-item/index.tsx
@@ -24,6 +24,7 @@ export interface ListItemProps {
onPress?: () => void;
children?: ReactNode;
style?: StyleProp;
+ contentStyle?: StyleProp;
testID?: string;
}
@@ -40,6 +41,7 @@ export function ListItem({
disabled,
onPress,
style,
+ contentStyle,
testID
}: ListItemProps) {
const Theme = useTheme();
@@ -100,7 +102,7 @@ export function ListItem({
testID={testID}
>
{visualTemplate()}
- {children}
+ {children}
{rightTemplate()}
);
diff --git a/packages/ui/src/composites/wui-list-item/styles.ts b/packages/ui/src/composites/wui-list-item/styles.ts
index 5c9e20768..f7c9d79a7 100644
--- a/packages/ui/src/composites/wui-list-item/styles.ts
+++ b/packages/ui/src/composites/wui-list-item/styles.ts
@@ -13,7 +13,8 @@ export default StyleSheet.create({
content: {
flexDirection: 'row',
flexGrow: 1,
- paddingHorizontal: Spacing.s
+ paddingHorizontal: Spacing.s,
+ alignItems: 'center'
},
imageContainer: {
width: 36,
diff --git a/packages/ui/src/composites/wui-network-image/index.tsx b/packages/ui/src/composites/wui-network-image/index.tsx
index 4dd561ecf..68af27ec4 100644
--- a/packages/ui/src/composites/wui-network-image/index.tsx
+++ b/packages/ui/src/composites/wui-network-image/index.tsx
@@ -1,37 +1,55 @@
import { Path, Svg, Image, Defs, Pattern } from 'react-native-svg';
import { useTheme } from '../../hooks/useTheme';
import type { SizeType } from '../../utils/TypesUtil';
-import { PathLg, PathNormal } from './styles';
+import { PathLg, PathNormal, PathSmall } from './styles';
+import type { StyleProp, ViewStyle } from 'react-native';
export interface NetworkImageProps {
imageSrc?: string;
imageHeaders?: Record;
selected?: boolean;
- size?: Exclude;
+ size?: Exclude;
disabled?: boolean;
+ style?: StyleProp;
}
+const sizeToPath = {
+ lg: PathLg,
+ md: PathNormal,
+ sm: PathSmall
+};
+
+const sizeToHeight = {
+ lg: 96,
+ md: 56,
+ sm: 20
+};
+
export function NetworkImage({
imageSrc,
imageHeaders,
disabled,
selected,
- size = 'md'
+ size = 'md',
+ style
}: NetworkImageProps) {
const Theme = useTheme();
- const isLg = size === 'lg';
- const svgWidth = isLg ? 96 : 56;
- const svgHeight = isLg ? 96 : 56;
const svgStroke = selected ? Theme['accent-100'] : Theme['gray-glass-010'];
const opacity = disabled ? 0.5 : 1;
return (
-
);
@@ -71,5 +72,8 @@ export function WalletReceiveView() {
const styles = StyleSheet.create({
qrContainer: {
marginVertical: Spacing.xl
+ },
+ networksButton: {
+ marginTop: Spacing.l
}
});
diff --git a/packages/ui/src/composites/wui-compatible-network/index.tsx b/packages/ui/src/composites/wui-compatible-network/index.tsx
index 80de42dc5..6ff7436d4 100644
--- a/packages/ui/src/composites/wui-compatible-network/index.tsx
+++ b/packages/ui/src/composites/wui-compatible-network/index.tsx
@@ -2,25 +2,33 @@ import { Text } from '../../components/wui-text';
import { NetworkImage } from '../wui-network-image';
import { FlexView } from '../../layout/wui-flex';
import { ListItem } from '../wui-list-item';
-import { StyleSheet } from 'react-native';
+import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
+import { useTheme } from '../../hooks/useTheme';
export interface CompatibleNetworkProps {
text: string;
onPress: () => void;
networkImages: string[];
imageHeaders: Record;
+ style?: StyleProp;
}
+const offset = [20, 15, 10, 5, 0];
+const zIndex = [5, 4, 3, 2, 1];
+
export function CompatibleNetwork({
text,
onPress,
networkImages,
- imageHeaders
+ imageHeaders,
+ style
}: CompatibleNetworkProps) {
+ const Theme = useTheme();
+
return (
@@ -29,7 +37,15 @@ export function CompatibleNetwork({
{networkImages?.map((image, index) => (
-
+
))}
@@ -41,6 +57,8 @@ const styles = StyleSheet.create({
height: 48
},
contentContainer: {
- flexDirection: 'row'
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ paddingRight: 0
}
});
diff --git a/packages/ui/src/composites/wui-network-image/index.tsx b/packages/ui/src/composites/wui-network-image/index.tsx
index 68af27ec4..9324caff9 100644
--- a/packages/ui/src/composites/wui-network-image/index.tsx
+++ b/packages/ui/src/composites/wui-network-image/index.tsx
@@ -11,6 +11,8 @@ export interface NetworkImageProps {
size?: Exclude;
disabled?: boolean;
style?: StyleProp;
+ borderColor?: string;
+ borderWidth?: number;
}
const sizeToPath = {
@@ -31,7 +33,9 @@ export function NetworkImage({
disabled,
selected,
size = 'md',
- style
+ style,
+ borderColor,
+ borderWidth = 1
}: NetworkImageProps) {
const Theme = useTheme();
const svgStroke = selected ? Theme['accent-100'] : Theme['gray-glass-010'];
@@ -41,8 +45,8 @@ export function NetworkImage({
From 422d4978c9ab732a5ce8deaee93bd7ae1d6a112e Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 9 Aug 2024 14:33:59 -0300
Subject: [PATCH 012/114] chore: wrapped new views in scrollview + landscape
---
.../src/views/w3m-account-view/index.tsx | 8 +++-
.../views/w3m-wallet-receive-view/index.tsx | 46 ++++++++++---------
2 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index c43cbc48e..faedff7c6 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -20,9 +20,12 @@ import {
} from '@web3modal/core-react-native';
import { AccountWalletFeatures } from '../../partials/w3m-account-wallet-features';
import styles from './styles';
+import { ScrollView } from 'react-native';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
export function AccountView() {
const Theme = useTheme();
+ const { padding } = useCustomDimensions();
const { caipNetwork } = useSnapshot(NetworkController.state);
const { address, profileName, profileImage } = useSnapshot(AccountController.state);
@@ -46,7 +49,7 @@ export function AccountView() {
}, []);
return (
- <>
+
+
- >
+
);
}
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
index ceb3096ff..222f9f3e7 100644
--- a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { StyleSheet } from 'react-native';
+import { ScrollView, StyleSheet } from 'react-native';
import {
Chip,
CompatibleNetwork,
@@ -17,11 +17,13 @@ import {
OptionsController,
SnackController
} from '@web3modal/core-react-native';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
export function WalletReceiveView() {
const { address, profileName } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+ const { padding } = useCustomDimensions();
const canCopy = OptionsController.isClipboardAvailable();
const slicedNetworks =
NetworkController.getApprovedCaipNetworks()
@@ -46,26 +48,28 @@ export function WalletReceiveView() {
if (!address) return;
return (
-
-
-
-
- {canCopy ? 'Copy your address or scan this QR code' : 'Scan this QR code'}
-
- {}}
- networkImages={imagesArray}
- imageHeaders={ApiController._getApiHeaders()}
- style={styles.networksButton}
- />
-
+
+
+
+
+
+ {canCopy ? 'Copy your address or scan this QR code' : 'Scan this QR code'}
+
+ {}}
+ networkImages={imagesArray}
+ imageHeaders={ApiController._getApiHeaders()}
+ style={styles.networksButton}
+ />
+
+
);
}
From 5322428db4fa1b93352c91d825a3059356b29571 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 9 Aug 2024 15:40:11 -0300
Subject: [PATCH 013/114] chore: added network view + network image placeholder
---
.../core/src/controllers/RouterController.ts | 3 +-
.../scaffold/src/modal/w3m-router/index.tsx | 3 ++
.../src/partials/w3m-header/index.tsx | 3 +-
.../index.tsx | 40 ++++++++++++++
.../styles.ts | 8 +++
.../views/w3m-wallet-receive-view/index.tsx | 7 ++-
.../ui/src/composites/wui-banner/index.tsx | 28 ++++++++++
.../ui/src/composites/wui-banner/styles.ts | 15 ++++++
.../wui-compatible-network/index.tsx | 2 +-
.../composites/wui-network-image/index.tsx | 52 ++++++++++++-------
.../composites/wui-network-image/styles.ts | 3 ++
packages/ui/src/index.ts | 1 +
12 files changed, 142 insertions(+), 23 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-wallet-compatible-networks-view/styles.ts
create mode 100644 packages/ui/src/composites/wui-banner/index.tsx
create mode 100644 packages/ui/src/composites/wui-banner/styles.ts
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index 8bbd2531a..b48c85f3b 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -22,7 +22,8 @@ export interface RouterControllerState {
| 'UpdateEmailSecondaryOtp'
| 'UpgradeEmailWallet'
| 'ConnectingSiwe'
- | 'WalletReceive';
+ | 'WalletReceive'
+ | 'WalletCompatibleNetworks';
history: RouterControllerState['view'][];
data?: {
connector?: Connector;
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index 8c8759f84..e0b800691 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -22,6 +22,7 @@ import { UpdateEmailSecondaryOtpView } from '../../views/w3m-update-email-second
import { UpgradeEmailWalletView } from '../../views/w3m-upgrade-email-wallet-view';
import { AccountView } from '../../views/w3m-account-view';
import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
+import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-networks-view';
export function Web3Router() {
const { view } = useSnapshot(RouterController.state);
@@ -70,6 +71,8 @@ export function Web3Router() {
return ConnectingSiweView;
case 'WalletReceive':
return WalletReceiveView;
+ case 'WalletCompatibleNetworks':
+ return WalletCompatibleNetworks;
default:
return ConnectView;
}
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index ea7c5d211..bab98729e 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -34,7 +34,8 @@ export function Header() {
UpdateEmailPrimaryOtp: 'Confirm current email',
UpdateEmailSecondaryOtp: 'Confirm new email',
UpgradeEmailWallet: 'Upgrade wallet',
- WalletReceive: 'Receive'
+ WalletReceive: 'Receive',
+ WalletCompatibleNetworks: 'Compatible networks'
};
};
diff --git a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
new file mode 100644
index 000000000..1748bad00
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
@@ -0,0 +1,40 @@
+import { ScrollView } from 'react-native';
+import { FlexView, Text, Banner, NetworkImage } from '@web3modal/ui-react-native';
+import { ApiController, AssetUtil, NetworkController } from '@web3modal/core-react-native';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import styles from './styles';
+
+export function WalletCompatibleNetworks() {
+ const { padding } = useCustomDimensions();
+ const approvedNetworks = NetworkController.getApprovedCaipNetworks();
+ const imageHeaders = ApiController._getApiHeaders();
+
+ return (
+
+
+
+ {approvedNetworks.map(network => (
+
+
+
+ {network.name}
+
+
+ ))}
+
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/styles.ts
new file mode 100644
index 000000000..e4423cecd
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/styles.ts
@@ -0,0 +1,8 @@
+import { Spacing } from '@web3modal/ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ image: {
+ marginRight: Spacing.s
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
index 222f9f3e7..874a727b4 100644
--- a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
@@ -15,6 +15,7 @@ import {
AssetUtil,
NetworkController,
OptionsController,
+ RouterController,
SnackController
} from '@web3modal/core-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
@@ -38,6 +39,10 @@ export function WalletReceiveView() {
truncate: profileName ? 'end' : 'middle'
});
+ const onNetworkPress = () => {
+ RouterController.push('WalletCompatibleNetworks');
+ };
+
const onCopyAddress = () => {
if (canCopy && address) {
OptionsController.copyToClipboard(profileName ?? address);
@@ -63,7 +68,7 @@ export function WalletReceiveView() {
{}}
+ onPress={onNetworkPress}
networkImages={imagesArray}
imageHeaders={ApiController._getApiHeaders()}
style={styles.networksButton}
diff --git a/packages/ui/src/composites/wui-banner/index.tsx b/packages/ui/src/composites/wui-banner/index.tsx
new file mode 100644
index 000000000..dfeb02bd3
--- /dev/null
+++ b/packages/ui/src/composites/wui-banner/index.tsx
@@ -0,0 +1,28 @@
+import type { IconType } from '../../utils/TypesUtil';
+import { FlexView } from '../../layout/wui-flex';
+import { IconBox } from '../wui-icon-box';
+import { Text } from '../../components/wui-text';
+import { useTheme } from '../../hooks/useTheme';
+import styles from './styles';
+
+export interface BannerProps {
+ icon: IconType;
+ text: string;
+}
+
+export function Banner({ icon, text }: BannerProps) {
+ const Theme = useTheme();
+
+ return (
+
+
+
+ {text}
+
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-banner/styles.ts b/packages/ui/src/composites/wui-banner/styles.ts
new file mode 100644
index 000000000..9504601ba
--- /dev/null
+++ b/packages/ui/src/composites/wui-banner/styles.ts
@@ -0,0 +1,15 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
+
+export default StyleSheet.create({
+ container: {
+ padding: Spacing.s,
+ borderRadius: BorderRadius.s
+ },
+ icon: {
+ marginRight: Spacing.xs
+ },
+ text: {
+ flex: 1
+ }
+});
diff --git a/packages/ui/src/composites/wui-compatible-network/index.tsx b/packages/ui/src/composites/wui-compatible-network/index.tsx
index 6ff7436d4..943ee852b 100644
--- a/packages/ui/src/composites/wui-compatible-network/index.tsx
+++ b/packages/ui/src/composites/wui-compatible-network/index.tsx
@@ -38,7 +38,7 @@ export function CompatibleNetwork({
{networkImages?.map((image, index) => (
;
selected?: boolean;
- size?: Exclude;
+ size?: Exclude;
disabled?: boolean;
style?: StyleProp;
borderColor?: string;
@@ -18,13 +20,15 @@ export interface NetworkImageProps {
const sizeToPath = {
lg: PathLg,
md: PathNormal,
- sm: PathSmall
+ sm: PathSmall,
+ xs: PathXS
};
const sizeToHeight = {
lg: 96,
md: 56,
- sm: 20
+ sm: 40,
+ xs: 20
};
export function NetworkImage({
@@ -50,22 +54,32 @@ export function NetworkImage({
style={style}
>
-
-
+
+ {imageSrc ? (
+
+ ) : (
+
+
+
+ )}
-
+ {!imageSrc && }
+
);
}
diff --git a/packages/ui/src/composites/wui-network-image/styles.ts b/packages/ui/src/composites/wui-network-image/styles.ts
index 837967d06..dbd445cae 100644
--- a/packages/ui/src/composites/wui-network-image/styles.ts
+++ b/packages/ui/src/composites/wui-network-image/styles.ts
@@ -5,4 +5,7 @@ export const PathNormal =
'M24.0002 2.34328C26.4754 0.914219 29.525 0.914219 32.0002 2.34328L48.2489 11.7245C50.7241 13.1535 52.2489 15.7946 52.2489 18.6527V37.4151C52.2489 40.2732 50.7241 42.9142 48.2489 44.3433L32.0002 53.7245C29.525 55.1535 26.4754 55.1535 24.0002 53.7245L7.75146 44.3433C5.27625 42.9142 3.75146 40.2732 3.75146 37.4151V18.6527C3.75146 15.7946 5.27626 13.1535 7.75146 11.7245L24.0002 2.34328Z';
export const PathSmall =
+ 'M17.1428 1.67377C18.9108 0.653013 21.0891 0.653014 22.8571 1.67377L34.4633 8.37463C36.2313 9.39539 37.3205 11.2818 37.3205 13.3233V26.7251C37.3205 28.7666 36.2313 30.653 34.4633 31.6738L22.8571 38.3746C21.0891 39.3954 18.9108 39.3954 17.1428 38.3746L5.53659 31.6738C3.76858 30.653 2.67944 28.7666 2.67944 26.7251V13.3233C2.67944 11.2818 3.76858 9.39539 5.53659 8.37463L17.1428 1.67377Z';
+
+export const PathXS =
'M8.57153 0.836886C9.45553 0.326507 10.5447 0.326507 11.4287 0.836886L17.2318 4.18731C18.1158 4.69769 18.6604 5.64091 18.6604 6.66167V13.3625C18.6604 14.3833 18.1158 15.3265 17.2318 15.8369L11.4287 19.1873C10.5447 19.6977 9.45553 19.6977 8.57153 19.1873L2.76841 15.8369C1.88441 15.3265 1.33984 14.3833 1.33984 13.3625V6.66167C1.33984 5.64091 1.88441 4.69769 2.76841 4.18731L8.57153 0.836886Z';
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index f78370045..1f601734b 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -13,6 +13,7 @@ export { AccountPill, type AccountPillProps } from './composites/wui-account-pil
export { ActionEntry, type ActionEntryProps } from './composites/wui-action-entry';
export { Avatar, type AvatarProps } from './composites/wui-avatar';
export { Balance, type BalanceProps } from './composites/wui-balance';
+export { Banner, type BannerProps } from './composites/wui-banner';
export { Button, type ButtonProps } from './composites/wui-button';
export {
CardSelectLoader,
From 0d2f1110c4dc9dbc0b39ea3330d5280f53a3254a Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 9 Aug 2024 16:22:52 -0300
Subject: [PATCH 014/114] chore: code improvements
---
packages/ui/src/composites/wui-compatible-network/index.tsx | 2 +-
packages/ui/src/composites/wui-qr-code/index.tsx | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/packages/ui/src/composites/wui-compatible-network/index.tsx b/packages/ui/src/composites/wui-compatible-network/index.tsx
index 943ee852b..af94c9358 100644
--- a/packages/ui/src/composites/wui-compatible-network/index.tsx
+++ b/packages/ui/src/composites/wui-compatible-network/index.tsx
@@ -39,7 +39,7 @@ export function CompatibleNetwork({
{networkImages?.map((image, index) => (
(uri ? QRCodeUtil.generate(uri, qrSize, arenaClear ? 0 : qrSize / 4) : []),
- [uri, qrSize, arenaClear]
+ () => (uri ? QRCodeUtil.generate(uri, qrSize, logoSize) : []),
+ [uri, qrSize, logoSize]
);
const logoTemplate = () => {
From 367a3b1cd65abd79cc8c689d6ebcfe6eadd8fe51 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 9 Aug 2024 16:25:52 -0300
Subject: [PATCH 015/114] chore: code improvements
---
packages/core/src/utils/CoreHelperUtil.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/core/src/utils/CoreHelperUtil.ts b/packages/core/src/utils/CoreHelperUtil.ts
index d1f8feae9..50fc280a0 100644
--- a/packages/core/src/utils/CoreHelperUtil.ts
+++ b/packages/core/src/utils/CoreHelperUtil.ts
@@ -226,7 +226,7 @@ export const CoreHelperUtil = {
},
calculateAndFormatBalance(array?: Balance[]) {
- if (!array || !array.length) {
+ if (!array?.length) {
return { dollars: '0', pennies: '00' };
}
From 0b60343231d7d6d84ae045c32a5c3eae76edd182 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 12 Aug 2024 16:28:57 -0300
Subject: [PATCH 016/114] chore: added token list
---
.../src/partials/w3m-account-tokens/index.tsx | 44 ++++++++++----
.../w3m-account-wallet-features/index.tsx | 2 +-
.../w3m-account-wallet-features/styles.ts | 6 +-
.../index.tsx | 5 +-
.../src/composites/wui-list-token/index.tsx | 57 +++++++++++++++++++
.../src/composites/wui-list-token/styles.ts | 10 ++++
packages/ui/src/index.ts | 1 +
packages/ui/src/utils/UiUtil.ts | 18 ++++++
8 files changed, 124 insertions(+), 19 deletions(-)
create mode 100644 packages/ui/src/composites/wui-list-token/index.tsx
create mode 100644 packages/ui/src/composites/wui-list-token/styles.ts
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index 6ed3f7af8..a7d80606e 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,21 +1,41 @@
-import { RouterController } from '@web3modal/core-react-native';
-import { FlexView, ListItem, Text } from '@web3modal/ui-react-native';
+import { useSnapshot } from 'valtio';
+import { AccountController, RouterController } from '@web3modal/core-react-native';
+import { FlexView, ListItem, Text, ListToken } from '@web3modal/ui-react-native';
+import { ScrollView } from 'react-native';
export function AccountTokens() {
+ const { tokenBalance } = useSnapshot(AccountController.state);
const onReceivePress = () => {
RouterController.push('WalletReceive');
};
+ if (!tokenBalance?.length) {
+ return (
+
+
+
+ Receive funds
+
+
+ Transfer tokens on your wallet
+
+
+
+ );
+ }
+
return (
-
-
-
- Receive funds
-
-
- Transfer tokens on your wallet
-
-
-
+
+ {tokenBalance.map(token => (
+
+ ))}
+
);
}
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index 991beb004..f44c262dd 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -62,7 +62,7 @@ export function AccountWalletFeatures() {
/>
-
+
{activeTab === 0 && }
{activeTab === 1 && }
{activeTab === 2 && }
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
index 75c000fb4..ef4af69cc 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
@@ -3,7 +3,8 @@ import { StyleSheet } from 'react-native';
export default StyleSheet.create({
container: {
- alignItems: 'center'
+ alignItems: 'center',
+ height: 400
},
balanceText: {
fontSize: 40,
@@ -25,6 +26,7 @@ export default StyleSheet.create({
marginLeft: 8
},
tabContainer: {
- minHeight: 300
+ flex: 1,
+ width: '100%'
}
});
diff --git a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
index 1748bad00..9f5d03282 100644
--- a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
@@ -12,10 +12,7 @@ export function WalletCompatibleNetworks() {
return (
-
+
{approvedNetworks.map(network => (
+
+ {imageSrc ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
+ {name}
+
+
+ {UiUtil.formatNumberToLocalString(amount, 4)} {currency}
+
+
+
+
+ ${value.toFixed(2)}
+
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-list-token/styles.ts b/packages/ui/src/composites/wui-list-token/styles.ts
new file mode 100644
index 000000000..21d4971bb
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-token/styles.ts
@@ -0,0 +1,10 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius, WalletImageSize } from '../../utils/ThemeUtil';
+
+export default StyleSheet.create({
+ image: {
+ height: WalletImageSize.sm,
+ width: WalletImageSize.sm,
+ borderRadius: BorderRadius.full
+ }
+});
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 1f601734b..3817986f2 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -40,6 +40,7 @@ export { InputNumeric, type InputNumericProps } from './composites/wui-input-num
export { InputText, type InputTextProps } from './composites/wui-input-text';
export { Link, type LinkProps } from './composites/wui-link';
export { ListItem, type ListItemProps } from './composites/wui-list-item';
+export { ListToken, type ListTokenProps } from './composites/wui-list-token';
export { ListWallet, type ListWalletProps } from './composites/wui-list-wallet';
export { Logo, type LogoProps } from './composites/wui-logo';
export { LogoSelect, type LogoSelectProps } from './composites/wui-logo-select';
diff --git a/packages/ui/src/utils/UiUtil.ts b/packages/ui/src/utils/UiUtil.ts
index e4678f6b2..bca68b003 100644
--- a/packages/ui/src/utils/UiUtil.ts
+++ b/packages/ui/src/utils/UiUtil.ts
@@ -68,5 +68,23 @@ export const UiUtil = {
getWalletName(name: string, short = true) {
return short ? name.split(' ')[0] : name;
+ },
+
+ formatNumberToLocalString(value: string | number | undefined, decimals = 2) {
+ if (value === undefined) {
+ return '0.00';
+ }
+
+ if (typeof value === 'number') {
+ return value.toLocaleString('en-US', {
+ maximumFractionDigits: decimals,
+ minimumFractionDigits: decimals
+ });
+ }
+
+ return parseFloat(value).toLocaleString('en-US', {
+ maximumFractionDigits: decimals,
+ minimumFractionDigits: decimals
+ });
}
};
From 49516f6b813840155eeba89632ad454aaf349a5d Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 12 Aug 2024 16:50:59 -0300
Subject: [PATCH 017/114] chore: changed list token types
---
packages/ui/src/composites/wui-list-token/index.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/ui/src/composites/wui-list-token/index.tsx b/packages/ui/src/composites/wui-list-token/index.tsx
index e0f6655a8..433b2fc42 100644
--- a/packages/ui/src/composites/wui-list-token/index.tsx
+++ b/packages/ui/src/composites/wui-list-token/index.tsx
@@ -9,8 +9,8 @@ import styles from './styles';
export interface ListTokenProps {
imageSrc: string;
name: string;
- value: number;
- amount: number;
+ value?: number;
+ amount?: string;
currency: string;
}
@@ -50,7 +50,7 @@ export function ListToken({ imageSrc, name, value, amount, currency }: ListToken
- ${value.toFixed(2)}
+ ${value?.toFixed(2) || '0.00'}
);
From 494ce0c5816b5160729b80c013b5087a1e3ba907 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 12 Aug 2024 17:06:33 -0300
Subject: [PATCH 018/114] chore: code style
---
packages/ui/src/composites/wui-list-token/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/ui/src/composites/wui-list-token/index.tsx b/packages/ui/src/composites/wui-list-token/index.tsx
index 433b2fc42..e13b71794 100644
--- a/packages/ui/src/composites/wui-list-token/index.tsx
+++ b/packages/ui/src/composites/wui-list-token/index.tsx
@@ -50,7 +50,7 @@ export function ListToken({ imageSrc, name, value, amount, currency }: ListToken
- ${value?.toFixed(2) || '0.00'}
+ ${value?.toFixed(2) ?? '0.00'}
);
From 851fce9bb9a8c4bdd78cc5cccf5414bff54b682b Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 13 Aug 2024 13:10:03 -0300
Subject: [PATCH 019/114] chore: added network icon in token item
---
.../src/partials/w3m-account-tokens/index.tsx | 13 +++++++++++--
.../ui/src/composites/wui-list-token/index.tsx | 18 ++++++++++++++++--
.../ui/src/composites/wui-list-token/styles.ts | 14 ++++++++++++++
3 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index a7d80606e..9b90ba3c5 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,10 +1,18 @@
+import { ScrollView } from 'react-native';
import { useSnapshot } from 'valtio';
-import { AccountController, RouterController } from '@web3modal/core-react-native';
+import {
+ AccountController,
+ AssetUtil,
+ NetworkController,
+ RouterController
+} from '@web3modal/core-react-native';
import { FlexView, ListItem, Text, ListToken } from '@web3modal/ui-react-native';
-import { ScrollView } from 'react-native';
export function AccountTokens() {
const { tokenBalance } = useSnapshot(AccountController.state);
+ const { caipNetwork } = useSnapshot(NetworkController.state);
+ const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+
const onReceivePress = () => {
RouterController.push('WalletReceive');
};
@@ -31,6 +39,7 @@ export function AccountTokens() {
key={token.name}
name={token.name}
imageSrc={token.iconUrl}
+ networkSrc={networkImage}
value={token.value}
amount={token.quantity.numeric}
currency={token.symbol}
diff --git a/packages/ui/src/composites/wui-list-token/index.tsx b/packages/ui/src/composites/wui-list-token/index.tsx
index e13b71794..43acad2cf 100644
--- a/packages/ui/src/composites/wui-list-token/index.tsx
+++ b/packages/ui/src/composites/wui-list-token/index.tsx
@@ -8,13 +8,14 @@ import styles from './styles';
export interface ListTokenProps {
imageSrc: string;
+ networkSrc?: string;
name: string;
value?: number;
amount?: string;
currency: string;
}
-export function ListToken({ imageSrc, name, value, amount, currency }: ListTokenProps) {
+export function ListToken({ imageSrc, networkSrc, name, value, amount, currency }: ListTokenProps) {
const Theme = useTheme();
return (
@@ -39,7 +40,20 @@ export function ListToken({ imageSrc, name, value, amount, currency }: ListToken
)}
-
+
+ {networkSrc ? (
+
+ ) : (
+
+ )}
+
{name}
diff --git a/packages/ui/src/composites/wui-list-token/styles.ts b/packages/ui/src/composites/wui-list-token/styles.ts
index 21d4971bb..73afea33a 100644
--- a/packages/ui/src/composites/wui-list-token/styles.ts
+++ b/packages/ui/src/composites/wui-list-token/styles.ts
@@ -6,5 +6,19 @@ export default StyleSheet.create({
height: WalletImageSize.sm,
width: WalletImageSize.sm,
borderRadius: BorderRadius.full
+ },
+ networkImageContainer: {
+ position: 'absolute',
+ bottom: -2,
+ left: 24,
+ borderWidth: 2,
+ borderRadius: BorderRadius.full,
+ width: 18,
+ height: 18
+ },
+ networkImage: {
+ width: 14,
+ height: 14,
+ borderRadius: BorderRadius.full
}
});
From a7fb6224edf13f60321c2fd9b62df05611a6c5c2 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 15 Aug 2024 17:11:50 -0300
Subject: [PATCH 020/114] chore: wip transaction list
---
packages/common/package.json | 3 +
packages/common/src/index.ts | 1 +
packages/common/src/utils/DateUtil.ts | 47 +++++
packages/common/src/utils/TypeUtil.ts | 72 ++++++++
.../controllers/BlockchainApiController.ts | 24 ++-
.../src/controllers/TransactionsController.ts | 133 ++++++++++++++
packages/core/src/index.ts | 64 ++++---
packages/core/src/utils/FetchUtil.ts | 4 +
packages/core/src/utils/TypeUtil.ts | 53 +++++-
.../scaffold/src/modal/w3m-modal/index.tsx | 6 +-
.../partials/w3m-account-activity/index.tsx | 91 ++++++++-
.../partials/w3m-account-activity/styles.ts | 14 ++
.../partials/w3m-account-activity/utils.ts | 25 +++
.../composites/wui-list-transaction/index.tsx | 65 +++++++
.../composites/wui-list-transaction/styles.ts | 10 +
.../composites/wui-list-transaction/utils.ts | 68 +++++++
.../wui-transaction-visual/index.tsx | 78 ++++++++
.../wui-transaction-visual/styles.ts | 36 ++++
packages/ui/src/index.ts | 2 +
packages/ui/src/utils/TransactionUtil.ts | 173 ++++++++++++++++++
packages/ui/src/utils/TypesUtil.ts | 19 ++
yarn.lock | 9 +
22 files changed, 959 insertions(+), 38 deletions(-)
create mode 100644 packages/common/src/utils/DateUtil.ts
create mode 100644 packages/core/src/controllers/TransactionsController.ts
create mode 100644 packages/scaffold/src/partials/w3m-account-activity/styles.ts
create mode 100644 packages/scaffold/src/partials/w3m-account-activity/utils.ts
create mode 100644 packages/ui/src/composites/wui-list-transaction/index.tsx
create mode 100644 packages/ui/src/composites/wui-list-transaction/styles.ts
create mode 100644 packages/ui/src/composites/wui-list-transaction/utils.ts
create mode 100644 packages/ui/src/composites/wui-transaction-visual/index.tsx
create mode 100644 packages/ui/src/composites/wui-transaction-visual/styles.ts
create mode 100644 packages/ui/src/utils/TransactionUtil.ts
diff --git a/packages/common/package.json b/packages/common/package.json
index 9bbfadde8..67e8fcddd 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -11,6 +11,9 @@
"test": "jest --passWithNoTests",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
},
+ "dependencies": {
+ "dayjs": "1.11.10"
+ },
"files": [
"src",
"lib"
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 96562da67..b3cd9d033 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -1,3 +1,4 @@
export { ConstantsUtil } from './utils/ConstantsUtil';
export { NetworkUtil } from './utils/NetworkUtil';
+export { DateUtil } from './utils/DateUtil';
export * from './utils/TypeUtil';
diff --git a/packages/common/src/utils/DateUtil.ts b/packages/common/src/utils/DateUtil.ts
new file mode 100644
index 000000000..e6c09dcd3
--- /dev/null
+++ b/packages/common/src/utils/DateUtil.ts
@@ -0,0 +1,47 @@
+import dayjs from 'dayjs';
+import englishLocale from 'dayjs/locale/en.js';
+import relativeTime from 'dayjs/plugin/relativeTime.js';
+import updateLocale from 'dayjs/plugin/updateLocale.js';
+
+dayjs.extend(relativeTime);
+dayjs.extend(updateLocale);
+
+const localeObject = {
+ ...englishLocale,
+ name: 'en-web3-modal',
+ relativeTime: {
+ future: 'in %s',
+ past: '%s ago',
+ s: '%d sec',
+ m: '1 min',
+ mm: '%d min',
+ h: '1 hr',
+ hh: '%d hrs',
+ d: '1 d',
+ dd: '%d d',
+ M: '1 mo',
+ MM: '%d mo',
+ y: '1 yr',
+ yy: '%d yr'
+ }
+};
+
+dayjs.locale('en-appkit', localeObject);
+
+export const DateUtil = {
+ getYear(date: string = new Date().toISOString()) {
+ return dayjs(date).year();
+ },
+
+ getRelativeDateFromNow(date: string | number) {
+ return dayjs(date).locale('en-appkit').fromNow(true);
+ },
+
+ formatDate(date: string | number, format = 'DD MMM') {
+ return dayjs(date).format(format);
+ },
+
+ getMonth(month: number) {
+ return dayjs().month(month).format('MMMM');
+ }
+};
diff --git a/packages/common/src/utils/TypeUtil.ts b/packages/common/src/utils/TypeUtil.ts
index ce2a40aa0..b5f83c35c 100644
--- a/packages/common/src/utils/TypeUtil.ts
+++ b/packages/common/src/utils/TypeUtil.ts
@@ -13,3 +13,75 @@ type BalanceQuantity = {
decimals: string;
numeric: string;
};
+
+export type TransactionStatus = 'confirmed' | 'failed' | 'pending';
+export type TransactionDirection = 'in' | 'out' | 'self';
+export type TransactionImage = {
+ type: 'FUNGIBLE' | 'NFT' | undefined;
+ url: string | undefined;
+};
+
+export interface Transaction {
+ id: string;
+ metadata: TransactionMetadata;
+ transfers: TransactionTransfer[];
+}
+
+export interface TransactionMetadata {
+ application: {
+ iconUrl: string | null;
+ name: string | null;
+ };
+ operationType: string;
+ hash: string;
+ minedAt: string;
+ sentFrom: string;
+ sentTo: string;
+ status: TransactionStatus;
+ nonce: number;
+ chain?: string;
+}
+
+export interface TransactionTransfer {
+ fungible_info?: {
+ name?: string;
+ symbol?: string;
+ icon?: {
+ url: string;
+ };
+ };
+ nft_info?: TransactionNftInfo;
+ direction: TransactionDirection;
+ quantity: TransactionQuantity;
+ value?: number;
+ price?: number;
+}
+
+export interface TransactionNftInfo {
+ name?: string;
+ content?: TransactionContent;
+ flags: TransactionNftInfoFlags;
+}
+
+export interface TransactionNftInfoFlags {
+ is_spam: boolean;
+}
+
+export interface TransactionContent {
+ preview?: TransactionPreview;
+ detail?: TransactionDetail;
+}
+
+export interface TransactionPreview {
+ url: string;
+ content_type?: null;
+}
+
+export interface TransactionDetail {
+ url: string;
+ content_type?: null;
+}
+
+export interface TransactionQuantity {
+ numeric: string;
+}
diff --git a/packages/core/src/controllers/BlockchainApiController.ts b/packages/core/src/controllers/BlockchainApiController.ts
index 6c480489e..e64373df4 100644
--- a/packages/core/src/controllers/BlockchainApiController.ts
+++ b/packages/core/src/controllers/BlockchainApiController.ts
@@ -5,7 +5,9 @@ import { FetchUtil } from '../utils/FetchUtil';
import type {
BlockchainApiBalanceResponse,
BlockchainApiIdentityRequest,
- BlockchainApiIdentityResponse
+ BlockchainApiIdentityResponse,
+ BlockchainApiTransactionsRequest,
+ BlockchainApiTransactionsResponse
} from '../utils/TypeUtil';
import { OptionsController } from './OptionsController';
@@ -37,6 +39,26 @@ export const BlockchainApiController = {
});
},
+ fetchTransactions({
+ account,
+ projectId,
+ cursor,
+ onramp,
+ signal,
+ cache
+ }: BlockchainApiTransactionsRequest) {
+ return state.api.get({
+ path: `/v1/account/${account}/history`,
+ params: {
+ projectId,
+ cursor,
+ onramp
+ },
+ signal,
+ cache
+ });
+ },
+
async getBalance(address: string, chainId?: string, forceUpdate?: string) {
const { sdkType, sdkVersion } = OptionsController.state;
diff --git a/packages/core/src/controllers/TransactionsController.ts b/packages/core/src/controllers/TransactionsController.ts
new file mode 100644
index 000000000..bca626573
--- /dev/null
+++ b/packages/core/src/controllers/TransactionsController.ts
@@ -0,0 +1,133 @@
+import type { Transaction } from '@web3modal/common-react-native';
+import { proxy, subscribe as sub } from 'valtio/vanilla';
+import { OptionsController } from './OptionsController';
+import { EventsController } from './EventsController';
+import { SnackController } from './SnackController';
+import { NetworkController } from './NetworkController';
+import { BlockchainApiController } from './BlockchainApiController';
+
+// -- Types --------------------------------------------- //
+type TransactionByMonthMap = Record;
+type TransactionByYearMap = Record;
+
+export interface TransactionsControllerState {
+ transactions: Transaction[];
+ loading: boolean;
+ empty: boolean;
+ next: string | undefined;
+}
+
+// -- State --------------------------------------------- //
+const state = proxy({
+ transactions: [],
+ loading: false,
+ empty: false,
+ next: undefined
+});
+
+// -- Controller ---------------------------------------- //
+export const TransactionsController = {
+ state,
+
+ subscribe(callback: (newState: TransactionsControllerState) => void) {
+ return sub(state, () => callback(state));
+ },
+
+ async fetchTransactions(accountAddress?: string) {
+ const { projectId } = OptionsController.state;
+
+ if (!projectId || !accountAddress) {
+ throw new Error("Transactions can't be fetched without a projectId and an accountAddress");
+ }
+
+ state.loading = true;
+
+ try {
+ const response = await BlockchainApiController.fetchTransactions({
+ account: accountAddress,
+ projectId,
+ cursor: state.next
+ });
+
+ const nonSpamTransactions = this.filterSpamTransactions(response?.data ?? []);
+ const filteredTransactions = [...state.transactions, ...nonSpamTransactions];
+
+ state.loading = false;
+
+ state.transactions = filteredTransactions;
+
+ state.empty = nonSpamTransactions.length === 0;
+ state.next = response?.next ? response.next : undefined;
+ } catch (error) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'ERROR_FETCH_TRANSACTIONS',
+ properties: {
+ address: accountAddress,
+ projectId,
+ cursor: state.next,
+ isSmartAccount: false
+ }
+ });
+ SnackController.showError('Failed to fetch transactions');
+ state.loading = false;
+ state.empty = true;
+ state.next = undefined;
+ }
+ },
+
+ getTransactionsByYearAndMonth(transactions: Transaction[]) {
+ const grouped: TransactionByYearMap = {};
+ let filteredTransactions = this.filterByConnectedChain(transactions);
+
+ filteredTransactions.forEach(transaction => {
+ const year = new Date(transaction.metadata.minedAt).getFullYear();
+ const month = new Date(transaction.metadata.minedAt).getMonth();
+
+ const yearTransactions = grouped[year] ?? {};
+ const monthTransactions = yearTransactions[month] ?? [];
+
+ // If there's a transaction with the same id, remove the old one
+ const newMonthTransactions = monthTransactions.filter(tx => tx.id !== transaction.id);
+
+ grouped[year] = {
+ ...yearTransactions,
+ [month]: [...newMonthTransactions, transaction].sort(
+ (a, b) => new Date(b.metadata.minedAt).getTime() - new Date(a.metadata.minedAt).getTime()
+ )
+ };
+ });
+
+ return grouped;
+ },
+
+ filterSpamTransactions(transactions: Transaction[]) {
+ return transactions.filter(transaction => {
+ const isAllSpam = transaction.transfers.every(
+ transfer => transfer.nft_info?.flags.is_spam === true
+ );
+
+ return !isAllSpam;
+ });
+ },
+
+ filterByConnectedChain(transactions: Transaction[]) {
+ const chainId = NetworkController.state.caipNetwork?.id;
+ const filteredTransactions = transactions.filter(
+ transaction => transaction.metadata.chain === chainId
+ );
+
+ return filteredTransactions;
+ },
+
+ clearCursor() {
+ state.next = undefined;
+ },
+
+ resetTransactions() {
+ state.transactions = [];
+ state.loading = false;
+ state.empty = false;
+ state.next = undefined;
+ }
+};
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 26ce21523..0d9b5eb55 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -1,50 +1,54 @@
// -- Controllers -------------------------------------------------------------
-export { ModalController } from './controllers/ModalController';
-export type { ModalControllerArguments, ModalControllerState } from './controllers/ModalController';
+export {
+ ModalController,
+ type ModalControllerArguments,
+ type ModalControllerState
+} from './controllers/ModalController';
-export { RouterController } from './controllers/RouterController';
-export type { RouterControllerState } from './controllers/RouterController';
+export { RouterController, type RouterControllerState } from './controllers/RouterController';
-export { AccountController } from './controllers/AccountController';
-export type { AccountControllerState } from './controllers/AccountController';
+export { AccountController, type AccountControllerState } from './controllers/AccountController';
-export { NetworkController } from './controllers/NetworkController';
-export type {
- NetworkControllerClient,
- NetworkControllerState
+export {
+ NetworkController,
+ type NetworkControllerClient,
+ type NetworkControllerState
} from './controllers/NetworkController';
-export { ConnectionController } from './controllers/ConnectionController';
-export type {
- ConnectionControllerClient,
- ConnectionControllerState
+export {
+ ConnectionController,
+ type ConnectionControllerClient,
+ type ConnectionControllerState
} from './controllers/ConnectionController';
-export { ConnectorController } from './controllers/ConnectorController';
-export type { ConnectorControllerState } from './controllers/ConnectorController';
+export {
+ ConnectorController,
+ type ConnectorControllerState
+} from './controllers/ConnectorController';
-export { SnackController } from './controllers/SnackController';
-export type { SnackControllerState } from './controllers/SnackController';
+export { SnackController, type SnackControllerState } from './controllers/SnackController';
-export { ApiController } from './controllers/ApiController';
-export type { ApiControllerState } from './controllers/ApiController';
+export { ApiController, type ApiControllerState } from './controllers/ApiController';
-export { AssetController } from './controllers/AssetController';
-export type { AssetControllerState } from './controllers/AssetController';
+export { AssetController, type AssetControllerState } from './controllers/AssetController';
-export { ThemeController } from './controllers/ThemeController';
-export type { ThemeControllerState } from './controllers/ThemeController';
+export { ThemeController, type ThemeControllerState } from './controllers/ThemeController';
-export { OptionsController } from './controllers/OptionsController';
-export type { OptionsControllerState } from './controllers/OptionsController';
+export { OptionsController, type OptionsControllerState } from './controllers/OptionsController';
-export { PublicStateController } from './controllers/PublicStateController';
-export type { PublicStateControllerState } from './controllers/PublicStateController';
+export {
+ PublicStateController,
+ type PublicStateControllerState
+} from './controllers/PublicStateController';
export { BlockchainApiController } from './controllers/BlockchainApiController';
-export { EventsController } from './controllers/EventsController';
-export type { EventsControllerState } from './controllers/EventsController';
+export { EventsController, type EventsControllerState } from './controllers/EventsController';
+
+export {
+ TransactionsController,
+ type TransactionsControllerState
+} from './controllers/TransactionsController';
// -- Utils -------------------------------------------------------------------
export { AssetUtil } from './utils/AssetUtil';
diff --git a/packages/core/src/utils/FetchUtil.ts b/packages/core/src/utils/FetchUtil.ts
index 99c0df370..b4d6d8057 100644
--- a/packages/core/src/utils/FetchUtil.ts
+++ b/packages/core/src/utils/FetchUtil.ts
@@ -1,3 +1,5 @@
+import type { RequestCache } from './TypeUtil';
+
// -- Types ----------------------------------------------------------------------
interface Options {
baseUrl: string;
@@ -8,6 +10,8 @@ interface RequestArguments {
path: string;
headers?: HeadersInit_;
params?: Record;
+ cache?: RequestCache;
+ signal?: AbortSignal;
}
interface PostArguments extends RequestArguments {
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index c751e8769..e8721aedb 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -1,4 +1,4 @@
-import type { Balance } from '@web3modal/common-react-native';
+import type { Balance, Transaction } from '@web3modal/common-react-native';
export type CaipAddress = `${string}:${string}:${string}`;
@@ -99,6 +99,16 @@ export interface ApiGetAnalyticsConfigResponse {
isAnalyticsEnabled: boolean;
}
+export type RequestCache =
+ | 'default'
+ | 'force-cache'
+ | 'no-cache'
+ | 'no-store'
+ | 'only-if-cached'
+ | 'reload';
+
+// -- ThemeController Types ---------------------------------------------------
+
export type ThemeMode = 'dark' | 'light';
export interface ThemeVariables {
@@ -119,6 +129,20 @@ export interface BlockchainApiBalanceResponse {
balances: Balance[];
}
+export interface BlockchainApiTransactionsRequest {
+ account: string;
+ projectId: string;
+ cursor?: string;
+ onramp?: 'coinbase';
+ signal?: AbortSignal;
+ cache?: RequestCache;
+}
+
+export interface BlockchainApiTransactionsResponse {
+ data: Transaction[];
+ next: string | null;
+}
+
// -- OptionsController Types ---------------------------------------------------
export interface Token {
address: string;
@@ -283,6 +307,33 @@ export type Event =
| {
type: 'track';
event: 'SIWE_AUTH_ERROR';
+ }
+ | {
+ type: 'track';
+ event: 'CLICK_TRANSACTIONS';
+ properties: {
+ isSmartAccount: boolean;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'ERROR_FETCH_TRANSACTIONS';
+ properties: {
+ address: string;
+ projectId: string;
+ cursor: string | undefined;
+ isSmartAccount: boolean;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'LOAD_MORE_TRANSACTIONS';
+ properties: {
+ address: string | undefined;
+ projectId: string;
+ cursor: string | undefined;
+ isSmartAccount: boolean;
+ };
};
// -- Email Types ------------------------------------------------
diff --git a/packages/scaffold/src/modal/w3m-modal/index.tsx b/packages/scaffold/src/modal/w3m-modal/index.tsx
index 716bb25a3..32e4b0b99 100644
--- a/packages/scaffold/src/modal/w3m-modal/index.tsx
+++ b/packages/scaffold/src/modal/w3m-modal/index.tsx
@@ -13,6 +13,7 @@ import {
ModalController,
OptionsController,
RouterController,
+ TransactionsController,
type CaipAddress,
type W3mFrameProvider
} from '@web3modal/core-react-native';
@@ -67,8 +68,11 @@ export function Web3Modal() {
return;
}
+ const newAddress = CoreHelperUtil.getPlainAddress(address);
+ TransactionsController.resetTransactions();
+ TransactionsController.fetchTransactions(newAddress);
+
if (isSiweEnabled) {
- const newAddress = CoreHelperUtil.getPlainAddress(address);
const newNetworkId = CoreHelperUtil.getNetworkId(address);
const { SIWEController } = await import('@web3modal/siwe-react-native');
const { signOutOnAccountChange, signOutOnNetworkChange } =
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index 9b91cf4b7..7c165fa6c 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -1,11 +1,92 @@
+import { useMemo } from 'react';
+import { useSnapshot } from 'valtio';
+import { ScrollView, View } from 'react-native';
+import { ListTransaction, LoadingSpinner, Text, TransactionUtil } from '@web3modal/ui-react-native';
+import { type Transaction, type TransactionImage } from '@web3modal/common-react-native';
+import { AssetUtil, NetworkController, TransactionsController } from '@web3modal/core-react-native';
import { AccountPlaceholder } from '../w3m-account-placeholder';
+import { getTransactionListItemProps } from './utils';
+import styles from './styles';
export function AccountActivity() {
+ const { loading, transactions } = useSnapshot(TransactionsController.state);
+ const { caipNetwork } = useSnapshot(NetworkController.state);
+ const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+
+ const transactionsByYear = useMemo(() => {
+ return TransactionsController.getTransactionsByYearAndMonth(transactions as Transaction[]);
+ }, [transactions]);
+
+ if (loading) {
+ return ;
+ }
+
+ if (!Object.keys(transactionsByYear).length) {
+ return (
+
+ );
+ }
+
return (
-
+
+ {Object.keys(transactionsByYear)
+ .reverse()
+ .map(year => (
+
+ {Object.keys(transactionsByYear[year] || {})
+ .reverse()
+ .map(month => (
+
+
+ {TransactionUtil.getTransactionGroupTitle(year, month)}
+
+ {transactionsByYear[year]?.[month]?.map((transaction: Transaction) => {
+ const { date, type, descriptions, status, images, isAllNFT, transfers } =
+ getTransactionListItemProps(transaction);
+ const hasMultipleTransfers = transfers?.length > 2;
+
+ if (hasMultipleTransfers) {
+ return transfers.map((transfer, index) => {
+ const description = TransactionUtil.getTransferDescription(transfer);
+
+ return (
+
+ );
+ });
+ }
+
+ return (
+
+ );
+ })}
+
+ ))}
+
+ ))}
+
);
}
diff --git a/packages/scaffold/src/partials/w3m-account-activity/styles.ts b/packages/scaffold/src/partials/w3m-account-activity/styles.ts
new file mode 100644
index 000000000..90c4759fe
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-activity/styles.ts
@@ -0,0 +1,14 @@
+import { Spacing } from '@web3modal/ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ container: {
+ padding: Spacing.xs
+ },
+ separatorText: {
+ marginVertical: Spacing.xs
+ },
+ transactionItem: {
+ marginVertical: Spacing.xs
+ }
+});
diff --git a/packages/scaffold/src/partials/w3m-account-activity/utils.ts b/packages/scaffold/src/partials/w3m-account-activity/utils.ts
new file mode 100644
index 000000000..a0fc06396
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-account-activity/utils.ts
@@ -0,0 +1,25 @@
+import { DateUtil, type Transaction } from '@web3modal/common-react-native';
+import { TransactionUtil } from '@web3modal/ui-react-native';
+import type { TransactionType } from '@web3modal/ui-react-native/lib/typescript/utils/TypesUtil';
+
+export function getTransactionListItemProps(transaction: Transaction) {
+ const date = DateUtil.formatDate(transaction?.metadata?.minedAt);
+ const descriptions = TransactionUtil.getTransactionDescriptions(transaction);
+
+ const transfers = transaction?.transfers;
+ const transfer = transaction?.transfers?.[0];
+ const isAllNFT =
+ Boolean(transfer) && transaction?.transfers?.every(item => Boolean(item.nft_info));
+ const images = TransactionUtil.getTransactionImages(transfers);
+
+ return {
+ date,
+ direction: transfer?.direction,
+ descriptions,
+ isAllNFT,
+ images,
+ status: transaction.metadata?.status,
+ transfers,
+ type: transaction.metadata?.operationType as TransactionType
+ };
+}
diff --git a/packages/ui/src/composites/wui-list-transaction/index.tsx b/packages/ui/src/composites/wui-list-transaction/index.tsx
new file mode 100644
index 000000000..dbaa4197f
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-transaction/index.tsx
@@ -0,0 +1,65 @@
+import { type TransactionImage, type TransactionStatus } from '@web3modal/common-react-native';
+
+import type { TransactionType } from '../../utils/TypesUtil';
+import { Text } from '../../components/wui-text';
+import { FlexView } from '../../layout/wui-flex';
+import { IconBox } from '../wui-icon-box';
+import { TransactionVisual } from '../wui-transaction-visual';
+import { getIcon, getTypeLabel } from './utils';
+import styles from './styles';
+import type { StyleProp, ViewStyle } from 'react-native';
+
+export interface ListTransactionProps {
+ date: string;
+ status?: TransactionStatus;
+ type?: TransactionType;
+ nature?: 'nft' | 'token' | 'fiat';
+ descriptions?: string[];
+ images?: TransactionImage[];
+ networkSrc?: string;
+ style?: StyleProp;
+ isAllNFT?: boolean;
+}
+
+export function ListTransaction({
+ date,
+ type,
+ descriptions,
+ images,
+ networkSrc,
+ style,
+ isAllNFT
+}: ListTransactionProps) {
+ const joinSymbol = type === 'trade' ? ' → ' : ' - ';
+
+ return (
+
+
+
+
+
+ {type && (
+
+ )}
+
+ {getTypeLabel(type)}
+
+
+
+ {descriptions?.join(joinSymbol)}
+
+
+
+
+ {date}
+
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-list-transaction/styles.ts b/packages/ui/src/composites/wui-list-transaction/styles.ts
new file mode 100644
index 000000000..5554145c6
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-transaction/styles.ts
@@ -0,0 +1,10 @@
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ middleContainer: {
+ flex: 1
+ },
+ date: {
+ textTransform: 'uppercase'
+ }
+});
diff --git a/packages/ui/src/composites/wui-list-transaction/utils.ts b/packages/ui/src/composites/wui-list-transaction/utils.ts
new file mode 100644
index 000000000..d9fe336b0
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-transaction/utils.ts
@@ -0,0 +1,68 @@
+import type { IconType, TransactionType } from '../../utils/TypesUtil';
+
+export const getIcon = (type: TransactionType): IconType => {
+ switch (type) {
+ case 'approve':
+ case 'execute':
+ return 'checkmark';
+ case 'repay':
+ case 'send':
+ case 'stake':
+ case 'withdraw':
+ return 'arrowTop';
+ case 'burn':
+ case 'cancel':
+ return 'close';
+ case 'trade':
+ return 'swapHorizontal';
+ case 'deploy':
+ return 'arrowRight';
+ default:
+ return 'arrowBottom';
+ }
+};
+
+export const getTypeLabel = (type?: TransactionType) => {
+ if (!type) {
+ return 'Unknown';
+ }
+
+ switch (type) {
+ case 'approve':
+ return 'Approved';
+ case 'bought':
+ return 'Bought';
+ case 'borrow':
+ return 'Borrowed';
+ case 'burn':
+ return 'Burnt';
+ case 'cancel':
+ return 'Canceled';
+ case 'claim':
+ return 'Claimed';
+ case 'deploy':
+ return 'Deployed';
+ case 'deposit':
+ return 'Deposited';
+ case 'execute':
+ return 'Executed';
+ case 'mint':
+ return 'Minted';
+ case 'receive':
+ return 'Received';
+ case 'repay':
+ return 'Repaid';
+ case 'send':
+ return 'Sent';
+ case 'stake':
+ return 'Staked';
+ case 'trade':
+ return 'Swapped';
+ case 'unstake':
+ return 'Unstaked';
+ case 'withdraw':
+ return 'Withdrawn';
+ default:
+ return 'Unknown';
+ }
+};
diff --git a/packages/ui/src/composites/wui-transaction-visual/index.tsx b/packages/ui/src/composites/wui-transaction-visual/index.tsx
new file mode 100644
index 000000000..46a5761a0
--- /dev/null
+++ b/packages/ui/src/composites/wui-transaction-visual/index.tsx
@@ -0,0 +1,78 @@
+import type { TransactionImage } from '@web3modal/common-react-native';
+
+import { FlexView } from '../../layout/wui-flex';
+import { Icon } from '../../components/wui-icon';
+import { Image } from '../../components/wui-image';
+import { useTheme } from '../../hooks/useTheme';
+import styles from './styles';
+
+export interface TransactionVisualProps {
+ images?: TransactionImage[];
+ networkSrc?: string;
+ isAllNFT?: boolean;
+}
+
+export function TransactionVisual({ images, networkSrc, isAllNFT }: TransactionVisualProps) {
+ const Theme = useTheme();
+ const backgroundColor = Theme['bg-200'];
+ const isFirstNFT = Boolean(images?.[0]?.type === 'NFT');
+ const filteredImages = images?.filter(image => image.url);
+ const [firstImage, secondImage] = filteredImages ?? [];
+ const hasOneImage = filteredImages?.length === 1;
+ const hasTwoImages = filteredImages && filteredImages?.length > 1;
+
+ return (
+
+ {!filteredImages?.length && (
+
+
+
+ )}
+ {hasOneImage && firstImage?.url && (
+
+ )}
+ {hasTwoImages && firstImage?.url && secondImage?.url && (
+
+
+
+
+
+
+
+
+ )}
+
+ {networkSrc ? (
+
+ ) : (
+
+ )}
+
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-transaction-visual/styles.ts b/packages/ui/src/composites/wui-transaction-visual/styles.ts
new file mode 100644
index 000000000..4bc04db84
--- /dev/null
+++ b/packages/ui/src/composites/wui-transaction-visual/styles.ts
@@ -0,0 +1,36 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
+
+export default StyleSheet.create({
+ image: {
+ height: 40,
+ width: 40,
+ borderRadius: BorderRadius.full,
+ marginRight: Spacing.s
+ },
+ imageNft: {
+ borderRadius: BorderRadius.xxs
+ },
+ halfContainer: {
+ overflow: 'hidden',
+ width: 20,
+ marginRight: 2
+ },
+ halfRight: {
+ left: -20
+ },
+ networkImageContainer: {
+ position: 'absolute',
+ bottom: -2,
+ left: 24,
+ borderWidth: 2,
+ borderRadius: BorderRadius.full,
+ width: 18,
+ height: 18
+ },
+ networkImage: {
+ width: 14,
+ height: 14,
+ borderRadius: BorderRadius.full
+ }
+});
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 3817986f2..5b8df3e18 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -41,6 +41,7 @@ export { InputText, type InputTextProps } from './composites/wui-input-text';
export { Link, type LinkProps } from './composites/wui-link';
export { ListItem, type ListItemProps } from './composites/wui-list-item';
export { ListToken, type ListTokenProps } from './composites/wui-list-token';
+export { ListTransaction, type ListTransactionProps } from './composites/wui-list-transaction';
export { ListWallet, type ListWalletProps } from './composites/wui-list-wallet';
export { Logo, type LogoProps } from './composites/wui-logo';
export { LogoSelect, type LogoSelectProps } from './composites/wui-logo-select';
@@ -74,6 +75,7 @@ export type {
VisualType
} from './utils/TypesUtil';
export { UiUtil } from './utils/UiUtil';
+export { TransactionUtil } from './utils/TransactionUtil';
export { Spacing, BorderRadius } from './utils/ThemeUtil';
export { useTheme } from './hooks/useTheme';
diff --git a/packages/ui/src/utils/TransactionUtil.ts b/packages/ui/src/utils/TransactionUtil.ts
new file mode 100644
index 000000000..4e30cfb32
--- /dev/null
+++ b/packages/ui/src/utils/TransactionUtil.ts
@@ -0,0 +1,173 @@
+import { DateUtil } from '@web3modal/common-react-native';
+import type {
+ TransactionTransfer,
+ Transaction,
+ TransactionImage
+} from '@web3modal/common-react-native';
+import type { TransactionType } from './TypesUtil';
+import { UiUtil } from './UiUtil';
+
+// -- Helpers --------------------------------------------- //
+const FLOAT_FIXED_VALUE = 2;
+const SMALL_FLOAT_FIXED_VALUE = 4;
+const plusTypes: TransactionType[] = ['receive', 'deposit', 'borrow', 'claim'];
+const minusTypes: TransactionType[] = ['withdraw', 'repay', 'burn'];
+
+export const TransactionUtil = {
+ getTransactionGroupTitle(year: string, month: string) {
+ const currentYear = DateUtil.getYear().toString();
+ const monthName = DateUtil.getMonth(parseInt(month));
+ const isCurrentYear = year === currentYear;
+ const groupTitle = isCurrentYear ? monthName : `${monthName} ${year}`;
+
+ return groupTitle;
+ },
+
+ getTransactionImages(transfers: TransactionTransfer[]): TransactionImage[] {
+ const [transfer, secondTransfer] = transfers;
+ const isAllNFT = Boolean(transfer) && transfers?.every(item => Boolean(item.nft_info));
+ const haveMultipleTransfers = transfers?.length > 1;
+ const haveTwoTransfers = transfers?.length === 2;
+
+ if (haveTwoTransfers && !isAllNFT) {
+ return [this.getTransactionImage(transfer), this.getTransactionImage(secondTransfer)];
+ }
+
+ if (haveMultipleTransfers) {
+ return transfers.map(item => this.getTransactionImage(item));
+ }
+
+ return [this.getTransactionImage(transfer)];
+ },
+
+ getTransactionImage(transfer?: TransactionTransfer): TransactionImage {
+ return {
+ type: TransactionUtil.getTransactionTransferTokenType(transfer),
+ url: TransactionUtil.getTransactionImageURL(transfer)
+ };
+ },
+
+ getTransactionImageURL(transfer: TransactionTransfer | undefined) {
+ let imageURL;
+ const isNFT = Boolean(transfer?.nft_info);
+ const isFungible = Boolean(transfer?.fungible_info);
+
+ if (transfer && isNFT) {
+ imageURL = transfer?.nft_info?.content?.preview?.url;
+ } else if (transfer && isFungible) {
+ imageURL = transfer?.fungible_info?.icon?.url;
+ }
+
+ return imageURL;
+ },
+
+ getTransactionTransferTokenType(transfer?: TransactionTransfer): 'FUNGIBLE' | 'NFT' | undefined {
+ if (transfer?.fungible_info) {
+ return 'FUNGIBLE';
+ } else if (transfer?.nft_info) {
+ return 'NFT';
+ }
+
+ return undefined;
+ },
+
+ getTransactionDescriptions(transaction: Transaction) {
+ const type = transaction?.metadata?.operationType as TransactionType;
+
+ const transfers = transaction?.transfers;
+ const haveTransfer = transaction?.transfers?.length > 0;
+ const haveMultipleTransfers = transaction?.transfers?.length > 1;
+ const isSendOrReceive = type === 'send' || type === 'receive';
+ const isFungible =
+ haveTransfer && transfers?.every(transfer => Boolean(transfer?.fungible_info));
+ const [firstTransfer, secondTransfer] = transfers;
+
+ let firstDescription = this.getTransferDescription(firstTransfer);
+ let secondDescription = this.getTransferDescription(secondTransfer);
+
+ if (!haveTransfer) {
+ if (isSendOrReceive && isFungible) {
+ firstDescription = UiUtil.getTruncateString({
+ string: transaction?.metadata.sentFrom,
+ charsStart: 4,
+ charsEnd: 6,
+ truncate: 'middle'
+ });
+ secondDescription = UiUtil.getTruncateString({
+ string: transaction?.metadata.sentTo,
+ charsStart: 4,
+ charsEnd: 6,
+ truncate: 'middle'
+ });
+
+ return [firstDescription, secondDescription];
+ }
+
+ return [transaction.metadata.status];
+ }
+
+ if (haveMultipleTransfers) {
+ return transfers.map(item => this.getTransferDescription(item));
+ }
+
+ let prefix = '';
+ if (plusTypes.includes(type)) {
+ prefix = '+';
+ } else if (minusTypes.includes(type)) {
+ prefix = '-';
+ }
+
+ firstDescription = prefix.concat(firstDescription);
+
+ if (isSendOrReceive) {
+ const isSend = type === 'send';
+ const address = UiUtil.getTruncateString({
+ string: isSend ? transaction.metadata.sentTo : transaction.metadata.sentFrom,
+ charsStart: 4,
+ charsEnd: 4,
+ truncate: 'middle'
+ });
+ const arrow = isSend ? '→' : '←';
+ firstDescription = firstDescription.concat(` ${arrow} ${address}`);
+ }
+
+ return [firstDescription];
+ },
+
+ getTransferDescription(transfer?: TransactionTransfer) {
+ let description = '';
+
+ if (!transfer) {
+ return description;
+ }
+
+ if (transfer?.nft_info) {
+ description = transfer?.nft_info?.name || '-';
+ } else if (transfer?.fungible_info) {
+ description = this.getFungibleTransferDescription(transfer) || '-';
+ }
+
+ return description;
+ },
+
+ getFungibleTransferDescription(transfer?: TransactionTransfer) {
+ if (!transfer) {
+ return null;
+ }
+
+ const quantity = this.getQuantityFixedValue(transfer?.quantity.numeric);
+ const description = [quantity, transfer?.fungible_info?.symbol].join(' ').trim();
+
+ return description;
+ },
+
+ getQuantityFixedValue(value: string | undefined) {
+ if (!value) {
+ return null;
+ }
+
+ const parsedValue = parseFloat(value);
+
+ return parsedValue.toFixed(parsedValue > 1 ? FLOAT_FIXED_VALUE : SMALL_FLOAT_FIXED_VALUE);
+ }
+};
diff --git a/packages/ui/src/utils/TypesUtil.ts b/packages/ui/src/utils/TypesUtil.ts
index 3399506f4..294a97883 100644
--- a/packages/ui/src/utils/TypesUtil.ts
+++ b/packages/ui/src/utils/TypesUtil.ts
@@ -249,3 +249,22 @@ export type TruncateOptions = {
charsEnd: number;
truncate: TruncateType;
};
+
+export type TransactionType =
+ | 'approve'
+ | 'bought'
+ | 'borrow'
+ | 'burn'
+ | 'cancel'
+ | 'claim'
+ | 'deploy'
+ | 'deposit'
+ | 'execute'
+ | 'mint'
+ | 'receive'
+ | 'repay'
+ | 'send'
+ | 'stake'
+ | 'trade'
+ | 'unstake'
+ | 'withdraw';
diff --git a/yarn.lock b/yarn.lock
index 8a45a53c8..fc776e2d5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10699,6 +10699,8 @@ __metadata:
"@web3modal/common-react-native@npm:2.0.1, @web3modal/common-react-native@workspace:packages/common":
version: 0.0.0-use.local
resolution: "@web3modal/common-react-native@workspace:packages/common"
+ dependencies:
+ dayjs: "npm:1.11.10"
languageName: unknown
linkType: soft
@@ -13368,6 +13370,13 @@ __metadata:
languageName: node
linkType: hard
+"dayjs@npm:1.11.10":
+ version: 1.11.10
+ resolution: "dayjs@npm:1.11.10"
+ checksum: 4de9af50639d47df87f2e15fa36bb07e0f9ed1e9c52c6caa1482788ee9a384d668f1dbd00c54f82aaab163db07d61d2899384b8254da3a9184fc6deca080e2fe
+ languageName: node
+ linkType: hard
+
"dayjs@npm:^1.8.15":
version: 1.11.9
resolution: "dayjs@npm:1.11.9"
From ab3e662005e6eab4ce8062973cf729f9536d8228 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 20 Aug 2024 17:00:06 -0300
Subject: [PATCH 021/114] chore: added load more button
---
.../partials/w3m-account-activity/index.tsx | 41 ++++++++++++++++---
.../partials/w3m-account-activity/styles.ts | 14 +++++++
2 files changed, 49 insertions(+), 6 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index 7c165fa6c..fbc2d4145 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -1,24 +1,41 @@
import { useMemo } from 'react';
import { useSnapshot } from 'valtio';
import { ScrollView, View } from 'react-native';
-import { ListTransaction, LoadingSpinner, Text, TransactionUtil } from '@web3modal/ui-react-native';
+import {
+ FlexView,
+ Link,
+ ListTransaction,
+ LoadingSpinner,
+ Text,
+ TransactionUtil
+} from '@web3modal/ui-react-native';
import { type Transaction, type TransactionImage } from '@web3modal/common-react-native';
-import { AssetUtil, NetworkController, TransactionsController } from '@web3modal/core-react-native';
+import {
+ AccountController,
+ AssetUtil,
+ NetworkController,
+ TransactionsController
+} from '@web3modal/core-react-native';
import { AccountPlaceholder } from '../w3m-account-placeholder';
import { getTransactionListItemProps } from './utils';
import styles from './styles';
export function AccountActivity() {
- const { loading, transactions } = useSnapshot(TransactionsController.state);
+ const { loading, transactions, next } = useSnapshot(TransactionsController.state);
+ const { address } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+ const handleFetchMore = () => {
+ TransactionsController.fetchTransactions(address);
+ };
+
const transactionsByYear = useMemo(() => {
return TransactionsController.getTransactionsByYearAndMonth(transactions as Transaction[]);
}, [transactions]);
- if (loading) {
- return ;
+ if (loading && !transactions.length) {
+ return ;
}
if (!Object.keys(transactionsByYear).length) {
@@ -32,7 +49,11 @@ export function AccountActivity() {
}
return (
-
+
{Object.keys(transactionsByYear)
.reverse()
.map(year => (
@@ -87,6 +108,14 @@ export function AccountActivity() {
))}
))}
+
+ {next && !loading && (
+
+ Load more
+
+ )}
+ {loading && }
+
);
}
diff --git a/packages/scaffold/src/partials/w3m-account-activity/styles.ts b/packages/scaffold/src/partials/w3m-account-activity/styles.ts
index 90c4759fe..e7fe55f58 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/styles.ts
+++ b/packages/scaffold/src/partials/w3m-account-activity/styles.ts
@@ -5,10 +5,24 @@ export default StyleSheet.create({
container: {
padding: Spacing.xs
},
+ contentContainer: {
+ paddingBottom: Spacing.m
+ },
separatorText: {
marginVertical: Spacing.xs
},
transactionItem: {
marginVertical: Spacing.xs
+ },
+ footer: {
+ height: 40
+ },
+ loader: {
+ flex: 1
+ },
+ loadMoreButton: {
+ alignSelf: 'center',
+ width: 100,
+ marginVertical: Spacing.xs
}
});
From 3734e0445261af3d84e565e8cfb73aec431d1f02 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 20 Aug 2024 17:16:46 -0300
Subject: [PATCH 022/114] chore: added activity evts
---
.../src/partials/w3m-account-activity/index.tsx | 17 +++++++++++++++--
.../w3m-account-wallet-features/index.tsx | 14 ++++++++++++++
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index fbc2d4145..89195df2e 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -13,7 +13,9 @@ import { type Transaction, type TransactionImage } from '@web3modal/common-react
import {
AccountController,
AssetUtil,
+ EventsController,
NetworkController,
+ OptionsController,
TransactionsController
} from '@web3modal/core-react-native';
import { AccountPlaceholder } from '../w3m-account-placeholder';
@@ -24,10 +26,21 @@ export function AccountActivity() {
const { loading, transactions, next } = useSnapshot(TransactionsController.state);
const { address } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
+ const { projectId } = useSnapshot(OptionsController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
- const handleFetchMore = () => {
+ const handleLoadMore = () => {
TransactionsController.fetchTransactions(address);
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'LOAD_MORE_TRANSACTIONS',
+ properties: {
+ address: address,
+ projectId,
+ cursor: next,
+ isSmartAccount: false
+ }
+ });
};
const transactionsByYear = useMemo(() => {
@@ -110,7 +123,7 @@ export function AccountActivity() {
))}
{next && !loading && (
-
+
Load more
)}
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index f44c262dd..3258e855f 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -5,6 +5,7 @@ import { Balance, FlexView, IconLink, Tabs } from '@web3modal/ui-react-native';
import {
AccountController,
CoreHelperUtil,
+ EventsController,
RouterController,
SnackController
} from '@web3modal/core-react-native';
@@ -25,6 +26,19 @@ export function AccountWalletFeatures() {
const onTabChange = (index: number) => {
setActiveTab(index);
+ if (index === 2) {
+ onTransactionsPress();
+ }
+ };
+
+ const onTransactionsPress = () => {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'CLICK_TRANSACTIONS',
+ properties: {
+ isSmartAccount: false
+ }
+ });
};
// TODO: Implement this features
From 34afaffc194616d6a8c94a06bf1a1619f53f3632 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 20 Aug 2024 17:28:11 -0300
Subject: [PATCH 023/114] chore: change activity icon color using status
---
.../src/composites/wui-list-transaction/index.tsx | 8 ++++----
.../src/composites/wui-list-transaction/utils.ts | 15 +++++++++++++++
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/packages/ui/src/composites/wui-list-transaction/index.tsx b/packages/ui/src/composites/wui-list-transaction/index.tsx
index dbaa4197f..2f188135d 100644
--- a/packages/ui/src/composites/wui-list-transaction/index.tsx
+++ b/packages/ui/src/composites/wui-list-transaction/index.tsx
@@ -5,7 +5,7 @@ import { Text } from '../../components/wui-text';
import { FlexView } from '../../layout/wui-flex';
import { IconBox } from '../wui-icon-box';
import { TransactionVisual } from '../wui-transaction-visual';
-import { getIcon, getTypeLabel } from './utils';
+import { getIcon, getTypeLabel, getIconColor } from './utils';
import styles from './styles';
import type { StyleProp, ViewStyle } from 'react-native';
@@ -13,7 +13,6 @@ export interface ListTransactionProps {
date: string;
status?: TransactionStatus;
type?: TransactionType;
- nature?: 'nft' | 'token' | 'fiat';
descriptions?: string[];
images?: TransactionImage[];
networkSrc?: string;
@@ -28,7 +27,8 @@ export function ListTransaction({
images,
networkSrc,
style,
- isAllNFT
+ isAllNFT,
+ status
}: ListTransactionProps) {
const joinSymbol = type === 'trade' ? ' → ' : ' - ';
@@ -42,7 +42,7 @@ export function ListTransaction({
{
@@ -22,6 +23,20 @@ export const getIcon = (type: TransactionType): IconType => {
}
};
+//Utils
+export const getIconColor = (status?: TransactionStatus) => {
+ switch (status) {
+ case 'confirmed':
+ return 'success-100';
+ case 'failed':
+ return 'error-100';
+ case 'pending':
+ return 'fg-200';
+ default:
+ return 'fg-200';
+ }
+};
+
export const getTypeLabel = (type?: TransactionType) => {
if (!type) {
return 'Unknown';
From a3d252c41c46b17dfd3210f23d112bb640b0bb13 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 20 Aug 2024 17:32:49 -0300
Subject: [PATCH 024/114] chore: code style
---
packages/ui/src/utils/TransactionUtil.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/ui/src/utils/TransactionUtil.ts b/packages/ui/src/utils/TransactionUtil.ts
index 4e30cfb32..380492de3 100644
--- a/packages/ui/src/utils/TransactionUtil.ts
+++ b/packages/ui/src/utils/TransactionUtil.ts
@@ -144,7 +144,7 @@ export const TransactionUtil = {
if (transfer?.nft_info) {
description = transfer?.nft_info?.name || '-';
} else if (transfer?.fungible_info) {
- description = this.getFungibleTransferDescription(transfer) || '-';
+ description = this.getFungibleTransferDescription(transfer) ?? '-';
}
return description;
From df19896ea0f4cc2514872084fd5a76b7e9ada26b Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 22 Aug 2024 11:47:16 -0300
Subject: [PATCH 025/114] feat: added activity view for eoa
---
.../core/src/controllers/RouterController.ts | 21 ++++-----
.../scaffold/src/modal/w3m-router/index.tsx | 43 ++++++++++---------
.../partials/w3m-account-activity/index.tsx | 42 ++++++++++--------
.../src/partials/w3m-header/index.tsx | 21 ++++-----
.../views/w3m-account-default-view/index.tsx | 27 +++++++++++-
.../views/w3m-account-default-view/styles.ts | 4 +-
.../src/views/w3m-transactions-view/index.tsx | 16 +++++++
.../ui/src/composites/wui-list-item/index.tsx | 2 +-
packages/ui/src/utils/TypesUtil.ts | 4 ++
9 files changed, 118 insertions(+), 62 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-transactions-view/index.tsx
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index b48c85f3b..d574633bc 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -6,24 +6,25 @@ export interface RouterControllerState {
view:
| 'Account'
| 'AccountDefault'
+ | 'AllWallets'
| 'Connect'
- | 'ConnectingWalletConnect'
| 'ConnectingExternal'
- | 'Networks'
- | 'SwitchNetwork'
- | 'AllWallets'
- | 'WhatIsAWallet'
- | 'WhatIsANetwork'
- | 'GetWallet'
+ | 'ConnectingSiwe'
+ | 'ConnectingWalletConnect'
| 'EmailVerifyDevice'
| 'EmailVerifyOtp'
- | 'UpdateEmailWallet'
+ | 'GetWallet'
+ | 'Networks'
+ | 'SwitchNetwork'
+ | 'Transactions'
| 'UpdateEmailPrimaryOtp'
| 'UpdateEmailSecondaryOtp'
+ | 'UpdateEmailWallet'
| 'UpgradeEmailWallet'
- | 'ConnectingSiwe'
| 'WalletReceive'
- | 'WalletCompatibleNetworks';
+ | 'WalletCompatibleNetworks'
+ | 'WhatIsANetwork'
+ | 'WhatIsAWallet';
history: RouterControllerState['view'][];
data?: {
connector?: Connector;
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index e0b800691..68abd6932 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -23,6 +23,7 @@ import { UpgradeEmailWalletView } from '../../views/w3m-upgrade-email-wallet-vie
import { AccountView } from '../../views/w3m-account-view';
import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-networks-view';
+import { TransactionsView } from '../../views/w3m-transactions-view';
export function Web3Router() {
const { view } = useSnapshot(RouterController.state);
@@ -33,46 +34,48 @@ export function Web3Router() {
const ViewComponent = useMemo(() => {
switch (view) {
- case 'Connect':
- return ConnectView;
+ case 'Account':
+ return AccountView;
+ case 'AccountDefault':
+ return AccountDefaultView;
case 'AllWallets':
return AllWalletsView;
- case 'ConnectingWalletConnect':
- return ConnectingView;
+ case 'Connect':
+ return ConnectView;
case 'ConnectingExternal':
return ConnectingExternalView;
- case 'WhatIsAWallet':
- return WhatIsAWalletView;
- case 'WhatIsANetwork':
- return WhatIsNetworkView;
+ case 'ConnectingSiwe':
+ return ConnectingSiweView;
+ case 'ConnectingWalletConnect':
+ return ConnectingView;
+ case 'EmailVerifyDevice':
+ return EmailVerifyDeviceView;
+ case 'EmailVerifyOtp':
+ return EmailVerifyOtpView;
case 'GetWallet':
return GetWalletView;
case 'Networks':
return NetworksView;
case 'SwitchNetwork':
return NetworkSwitchView;
- case 'Account':
- return AccountView;
- case 'AccountDefault':
- return AccountDefaultView;
- case 'EmailVerifyDevice':
- return EmailVerifyDeviceView;
- case 'EmailVerifyOtp':
- return EmailVerifyOtpView;
- case 'UpdateEmailWallet':
- return UpdateEmailWalletView;
+ case 'Transactions':
+ return TransactionsView;
case 'UpdateEmailPrimaryOtp':
return UpdateEmailPrimaryOtpView;
case 'UpdateEmailSecondaryOtp':
return UpdateEmailSecondaryOtpView;
+ case 'UpdateEmailWallet':
+ return UpdateEmailWalletView;
case 'UpgradeEmailWallet':
return UpgradeEmailWalletView;
- case 'ConnectingSiwe':
- return ConnectingSiweView;
case 'WalletReceive':
return WalletReceiveView;
case 'WalletCompatibleNetworks':
return WalletCompatibleNetworks;
+ case 'WhatIsANetwork':
+ return WhatIsNetworkView;
+ case 'WhatIsAWallet':
+ return WhatIsAWalletView;
default:
return ConnectView;
}
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index 89195df2e..427617907 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { useSnapshot } from 'valtio';
-import { ScrollView, View } from 'react-native';
+import { ScrollView, View, type StyleProp, type ViewStyle } from 'react-native';
import {
FlexView,
Link,
@@ -22,7 +22,11 @@ import { AccountPlaceholder } from '../w3m-account-placeholder';
import { getTransactionListItemProps } from './utils';
import styles from './styles';
-export function AccountActivity() {
+interface Props {
+ style?: StyleProp;
+}
+
+export function AccountActivity({ style }: Props) {
const { loading, transactions, next } = useSnapshot(TransactionsController.state);
const { address } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
@@ -53,19 +57,21 @@ export function AccountActivity() {
if (!Object.keys(transactionsByYear).length) {
return (
-
+
+
+
);
}
return (
{Object.keys(transactionsByYear)
.reverse()
@@ -121,14 +127,16 @@ export function AccountActivity() {
))}
))}
-
- {next && !loading && (
-
- Load more
-
- )}
- {loading && }
-
+ {(next || loading) && (
+
+ {next && !loading && (
+
+ Load more
+
+ )}
+ {loading && }
+
+ )}
);
}
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index bab98729e..cf94f9fd3 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -16,26 +16,27 @@ export function Header() {
const networkName = RouterController.state.data?.network?.name;
return {
- Connect: 'Connect wallet',
Account: undefined,
AccountDefault: undefined,
- ConnectingWalletConnect: walletName ?? 'WalletConnect',
+ AllWallets: 'All wallets',
+ Connect: 'Connect wallet',
ConnectingExternal: connectorName ?? 'Connect wallet',
ConnectingSiwe: 'Sign In',
- Networks: 'Select network',
- SwitchNetwork: networkName ?? 'Switch network',
- AllWallets: 'All wallets',
- WhatIsANetwork: 'What is a network?',
- WhatIsAWallet: 'What is a wallet?',
- GetWallet: 'Get a wallet',
+ ConnectingWalletConnect: walletName ?? 'WalletConnect',
EmailVerifyDevice: ' ',
EmailVerifyOtp: 'Confirm email',
- UpdateEmailWallet: 'Edit email',
+ GetWallet: 'Get a wallet',
+ Networks: 'Select network',
+ SwitchNetwork: networkName ?? 'Switch network',
+ Transactions: 'Activity',
UpdateEmailPrimaryOtp: 'Confirm current email',
UpdateEmailSecondaryOtp: 'Confirm new email',
+ UpdateEmailWallet: 'Edit email',
UpgradeEmailWallet: 'Upgrade wallet',
+ WalletCompatibleNetworks: 'Compatible networks',
WalletReceive: 'Receive',
- WalletCompatibleNetworks: 'Compatible networks'
+ WhatIsANetwork: 'What is a network?',
+ WhatIsAWallet: 'What is a wallet?'
};
};
diff --git a/packages/scaffold/src/views/w3m-account-default-view/index.tsx b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
index 5402251ed..0852a562f 100644
--- a/packages/scaffold/src/views/w3m-account-default-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
@@ -84,6 +84,10 @@ export function AccountDefaultView() {
}
};
+ const onActivityPress = () => {
+ RouterController.push('Transactions');
+ };
+
const onNetworkPress = () => {
RouterController.push('Networks');
@@ -158,7 +162,13 @@ export function AccountDefaultView() {
{isEmail && (
<>
-
+
{getUserEmail()}
>
@@ -171,12 +181,25 @@ export function AccountDefaultView() {
imageHeaders={ApiController._getApiHeaders()}
onPress={onNetworkPress}
testID="button-network"
- style={styles.networkButton}
+ style={styles.actionButton}
>
{caipNetwork?.name}
+ {!isEmail && (
+
+ Activity
+
+ )}
;
+}
+
+const styles = StyleSheet.create({
+ container: {
+ minHeight: 200,
+ paddingHorizontal: Spacing.l,
+ marginVertical: Spacing.s,
+ marginBottom: Spacing.l
+ }
+});
diff --git a/packages/ui/src/composites/wui-list-item/index.tsx b/packages/ui/src/composites/wui-list-item/index.tsx
index 5f9c66818..9cbacb172 100644
--- a/packages/ui/src/composites/wui-list-item/index.tsx
+++ b/packages/ui/src/composites/wui-list-item/index.tsx
@@ -82,7 +82,7 @@ export function ListItem({
if (loading) {
return ;
} else if (chevron) {
- return ;
+ return ;
}
return null;
diff --git a/packages/ui/src/utils/TypesUtil.ts b/packages/ui/src/utils/TypesUtil.ts
index 294a97883..01a88675d 100644
--- a/packages/ui/src/utils/TypesUtil.ts
+++ b/packages/ui/src/utils/TypesUtil.ts
@@ -96,6 +96,10 @@ export type ColorType =
| 'fg-250'
| 'fg-275'
| 'fg-300'
+ | 'accent-glass-020'
+ | 'accent-glass-015'
+ | 'accent-glass-010'
+ | 'accent-glass-005'
| 'gray-glass-020'
| 'gray-glass-010'
| 'gray-glass-005'
From 6c4dfd076c22862828c0242c0bca9ca3008479c2 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 22 Aug 2024 12:37:53 -0300
Subject: [PATCH 026/114] chore: style improvements
---
.../partials/w3m-account-activity/index.tsx | 9 ++++++--
.../partials/w3m-account-activity/styles.ts | 6 ++---
.../src/partials/w3m-account-tokens/index.tsx | 10 ++++++---
.../w3m-account-wallet-features/index.tsx | 22 ++++++++++++-------
.../w3m-account-wallet-features/styles.ts | 8 ++++++-
.../src/views/w3m-account-view/index.tsx | 17 +++++++++-----
.../src/views/w3m-account-view/styles.ts | 8 +++++--
.../src/views/w3m-transactions-view/index.tsx | 1 -
8 files changed, 56 insertions(+), 25 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index 427617907..041e5bd84 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -52,12 +52,16 @@ export function AccountActivity({ style }: Props) {
}, [transactions]);
if (loading && !transactions.length) {
- return ;
+ return (
+
+
+
+ );
}
if (!Object.keys(transactionsByYear).length) {
return (
-
+
{Object.keys(transactionsByYear)
diff --git a/packages/scaffold/src/partials/w3m-account-activity/styles.ts b/packages/scaffold/src/partials/w3m-account-activity/styles.ts
index e7fe55f58..e80cb4e01 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/styles.ts
+++ b/packages/scaffold/src/partials/w3m-account-activity/styles.ts
@@ -3,7 +3,7 @@ import { StyleSheet } from 'react-native';
export default StyleSheet.create({
container: {
- padding: Spacing.xs
+ paddingHorizontal: Spacing.xs
},
contentContainer: {
paddingBottom: Spacing.m
@@ -17,8 +17,8 @@ export default StyleSheet.create({
footer: {
height: 40
},
- loader: {
- flex: 1
+ placeholder: {
+ minHeight: 200
},
loadMoreButton: {
alignSelf: 'center',
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index 9b90ba3c5..b6d18c85c 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,4 +1,4 @@
-import { ScrollView } from 'react-native';
+import { ScrollView, type StyleProp, type ViewStyle } from 'react-native';
import { useSnapshot } from 'valtio';
import {
AccountController,
@@ -8,7 +8,11 @@ import {
} from '@web3modal/core-react-native';
import { FlexView, ListItem, Text, ListToken } from '@web3modal/ui-react-native';
-export function AccountTokens() {
+interface Props {
+ style?: StyleProp;
+}
+
+export function AccountTokens({ style }: Props) {
const { tokenBalance } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
@@ -33,7 +37,7 @@ export function AccountTokens() {
}
return (
-
+
{tokenBalance.map(token => (
+
-
+
-
-
- {activeTab === 0 && }
+
+
+
+
+ {activeTab === 0 && }
{activeTab === 1 && }
- {activeTab === 2 && }
+ {activeTab === 2 && }
-
+
);
}
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
index ef4af69cc..868ffd6a5 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/styles.ts
@@ -3,7 +3,6 @@ import { StyleSheet } from 'react-native';
export default StyleSheet.create({
container: {
- alignItems: 'center',
height: 400
},
balanceText: {
@@ -25,8 +24,15 @@ export default StyleSheet.create({
actionRight: {
marginLeft: 8
},
+ tab: {
+ width: '100%',
+ paddingHorizontal: Spacing.s
+ },
tabContainer: {
flex: 1,
width: '100%'
+ },
+ tabContent: {
+ paddingHorizontal: Spacing.m
}
});
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index faedff7c6..395f4bc87 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -1,5 +1,6 @@
import { useSnapshot } from 'valtio';
import { useEffect } from 'react';
+import { ScrollView } from 'react-native';
import {
FlexView,
Icon,
@@ -19,9 +20,8 @@ import {
SnackController
} from '@web3modal/core-react-native';
import { AccountWalletFeatures } from '../../partials/w3m-account-wallet-features';
-import styles from './styles';
-import { ScrollView } from 'react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import styles from './styles';
export function AccountView() {
const Theme = useTheme();
@@ -49,7 +49,15 @@ export function AccountView() {
}, []);
return (
-
+
-
-
+
Date: Thu, 22 Aug 2024 12:40:36 -0300
Subject: [PATCH 027/114] chore: style changes
---
packages/scaffold/src/views/w3m-transactions-view/index.tsx | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/packages/scaffold/src/views/w3m-transactions-view/index.tsx b/packages/scaffold/src/views/w3m-transactions-view/index.tsx
index b66f0217e..629e8d784 100644
--- a/packages/scaffold/src/views/w3m-transactions-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-transactions-view/index.tsx
@@ -9,7 +9,6 @@ export function TransactionsView() {
const styles = StyleSheet.create({
container: {
paddingHorizontal: Spacing.l,
- marginVertical: Spacing.s,
- marginBottom: Spacing.l
+ marginTop: Spacing.s
}
});
From beccc6f78ba4112f0e06d762c74d7846f8563f1b Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 26 Aug 2024 16:16:45 -0300
Subject: [PATCH 028/114] chore: wip send view
---
packages/common/src/contracts/erc20.ts | 222 +++++++++++++++++
packages/common/src/index.ts | 1 +
.../src/controllers/ConnectionController.ts | 55 +++--
.../core/src/controllers/RouterController.ts | 5 +-
.../core/src/controllers/SendController.ts | 230 ++++++++++++++++++
packages/core/src/utils/TypeUtil.ts | 58 +++++
packages/ethers/src/client.ts | 70 +++++-
packages/ethers5/src/client.ts | 65 +++++
packages/scaffold/src/client.ts | 2 +
.../scaffold/src/modal/w3m-router/index.tsx | 7 +-
.../w3m-account-wallet-features/index.tsx | 20 +-
.../src/partials/w3m-header/index.tsx | 3 +
.../src/views/w3m-wallet-send-view/index.tsx | 10 +
.../src/views/w3m-wallet-send-view/styles.ts | 8 +
packages/wagmi/src/client.ts | 63 ++++-
packages/wagmi/src/utils/helpers.ts | 14 +-
16 files changed, 802 insertions(+), 31 deletions(-)
create mode 100644 packages/common/src/contracts/erc20.ts
create mode 100644 packages/core/src/controllers/SendController.ts
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
diff --git a/packages/common/src/contracts/erc20.ts b/packages/common/src/contracts/erc20.ts
new file mode 100644
index 000000000..8f735d820
--- /dev/null
+++ b/packages/common/src/contracts/erc20.ts
@@ -0,0 +1,222 @@
+export const erc20ABI = [
+ {
+ constant: true,
+ inputs: [],
+ name: 'name',
+ outputs: [
+ {
+ name: '',
+ type: 'string'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_spender',
+ type: 'address'
+ },
+ {
+ name: '_value',
+ type: 'uint256'
+ }
+ ],
+ name: 'approve',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_from',
+ type: 'address'
+ },
+ {
+ name: '_to',
+ type: 'address'
+ },
+ {
+ name: '_value',
+ type: 'uint256'
+ }
+ ],
+ name: 'transferFrom',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'decimals',
+ outputs: [
+ {
+ name: '',
+ type: 'uint8'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_owner',
+ type: 'address'
+ }
+ ],
+ name: 'balanceOf',
+ outputs: [
+ {
+ name: 'balance',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'symbol',
+ outputs: [
+ {
+ name: '',
+ type: 'string'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_to',
+ type: 'address'
+ },
+ {
+ name: '_value',
+ type: 'uint256'
+ }
+ ],
+ name: 'transfer',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_owner',
+ type: 'address'
+ },
+ {
+ name: '_spender',
+ type: 'address'
+ }
+ ],
+ name: 'allowance',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ payable: true,
+ stateMutability: 'payable',
+ type: 'fallback'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'owner',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'spender',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'value',
+ type: 'uint256'
+ }
+ ],
+ name: 'Approval',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'from',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'to',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'value',
+ type: 'uint256'
+ }
+ ],
+ name: 'Transfer',
+ type: 'event'
+ }
+];
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index b3cd9d033..67fc41c28 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -1,4 +1,5 @@
export { ConstantsUtil } from './utils/ConstantsUtil';
export { NetworkUtil } from './utils/NetworkUtil';
export { DateUtil } from './utils/DateUtil';
+export { erc20ABI } from './contracts/erc20';
export * from './utils/TypeUtil';
diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts
index f4dca322b..3cccff639 100644
--- a/packages/core/src/controllers/ConnectionController.ts
+++ b/packages/core/src/controllers/ConnectionController.ts
@@ -2,9 +2,15 @@ import { subscribeKey as subKey } from 'valtio/utils';
import { proxy, ref } from 'valtio';
import { CoreHelperUtil } from '../utils/CoreHelperUtil';
import { StorageUtil } from '../utils/StorageUtil';
-import type { Connector, WcWallet } from '../utils/TypeUtil';
+import type {
+ Connector,
+ SendTransactionArgs,
+ WcWallet,
+ WriteContractArgs
+} from '../utils/TypeUtil';
import { RouterController } from './RouterController';
import { ConnectorController } from './ConnectorController';
+import { TransactionsController } from './TransactionsController';
// -- Types --------------------------------------------- //
export interface ConnectExternalOptions {
@@ -18,6 +24,10 @@ export interface ConnectionControllerClient {
connectWalletConnect: (onUri: (uri: string) => void) => Promise;
connectExternal?: (options: ConnectExternalOptions) => Promise;
signMessage: (message: string) => Promise;
+ sendTransaction: (args: SendTransactionArgs) => Promise<`0x${string}` | null>;
+ parseUnits: (value: string, decimals: number) => bigint;
+ formatUnits: (value: bigint, decimals: number) => string;
+ writeContract: (args: WriteContractArgs) => Promise<`0x${string}` | null>;
disconnect: () => Promise;
}
@@ -85,19 +95,6 @@ export const ConnectionController = {
return this._getClient().signMessage(message);
},
- resetWcConnection() {
- state.wcUri = undefined;
- state.wcPairingExpiry = undefined;
- state.wcPromise = undefined;
- state.wcLinking = undefined;
- state.pressedWallet = undefined;
- state.connectedWalletImageUrl = undefined;
- ConnectorController.setConnectedConnector(undefined);
- StorageUtil.removeWalletConnectDeepLink();
- StorageUtil.removeConnectedWalletImageUrl();
- StorageUtil.removeConnectedConnector();
- },
-
setWcLinking(wcLinking: ConnectionControllerState['wcLinking']) {
state.wcLinking = wcLinking;
},
@@ -132,6 +129,36 @@ export const ConnectionController = {
}
},
+ parseUnits(value: string, decimals: number) {
+ return this._getClient().parseUnits(value, decimals);
+ },
+
+ formatUnits(value: bigint, decimals: number) {
+ return this._getClient().formatUnits(value, decimals);
+ },
+
+ async sendTransaction(args: SendTransactionArgs) {
+ return this._getClient().sendTransaction(args);
+ },
+
+ async writeContract(args: WriteContractArgs) {
+ return this._getClient().writeContract(args);
+ },
+
+ resetWcConnection() {
+ state.wcUri = undefined;
+ state.wcPairingExpiry = undefined;
+ state.wcPromise = undefined;
+ state.wcLinking = undefined;
+ state.pressedWallet = undefined;
+ state.connectedWalletImageUrl = undefined;
+ ConnectorController.setConnectedConnector(undefined);
+ TransactionsController.resetTransactions();
+ StorageUtil.removeWalletConnectDeepLink();
+ StorageUtil.removeConnectedWalletImageUrl();
+ StorageUtil.removeConnectedConnector();
+ },
+
async disconnect() {
await this._getClient().disconnect();
this.resetWcConnection();
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index d574633bc..d579dd33d 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -21,8 +21,11 @@ export interface RouterControllerState {
| 'UpdateEmailSecondaryOtp'
| 'UpdateEmailWallet'
| 'UpgradeEmailWallet'
- | 'WalletReceive'
| 'WalletCompatibleNetworks'
+ | 'WalletReceive'
+ | 'WalletSend'
+ | 'WalletSendPreview'
+ | 'WalletSendSelectToken'
| 'WhatIsANetwork'
| 'WhatIsAWallet';
history: RouterControllerState['view'][];
diff --git a/packages/core/src/controllers/SendController.ts b/packages/core/src/controllers/SendController.ts
new file mode 100644
index 000000000..ca80e703e
--- /dev/null
+++ b/packages/core/src/controllers/SendController.ts
@@ -0,0 +1,230 @@
+import { subscribeKey as subKey } from 'valtio/vanilla/utils';
+import { proxy, ref, subscribe as sub } from 'valtio/vanilla';
+import { type Balance } from '@web3modal/common-react-native';
+import { erc20ABI } from '@web3modal/common-react-native';
+// import { RouterController } from './RouterController';
+import { AccountController } from './AccountController';
+import { ConnectionController } from './ConnectionController';
+import { SnackController } from './SnackController';
+import { CoreHelperUtil } from '../utils/CoreHelperUtil';
+import { EventsController } from './EventsController';
+import { NetworkController } from './NetworkController';
+
+// -- Types --------------------------------------------- //
+
+export interface TxParams {
+ receiverAddress: string;
+ sendTokenAmount: number;
+ gasPrice: bigint;
+ decimals: string;
+}
+
+export interface ContractWriteParams {
+ receiverAddress: string;
+ tokenAddress: string;
+ sendTokenAmount: number;
+ decimals: string;
+}
+export interface SendControllerState {
+ token?: Balance;
+ sendTokenAmount?: number;
+ receiverAddress?: string;
+ receiverProfileName?: string;
+ receiverProfileImageUrl?: string;
+ gasPrice?: bigint;
+ gasPriceInUSD?: number;
+ loading: boolean;
+}
+
+type StateKey = keyof SendControllerState;
+
+// -- State --------------------------------------------- //
+const state = proxy({
+ loading: false
+});
+
+// -- Controller ---------------------------------------- //
+export const SendController = {
+ state,
+
+ subscribe(callback: (newState: SendControllerState) => void) {
+ return sub(state, () => callback(state));
+ },
+
+ subscribeKey(key: K, callback: (value: SendControllerState[K]) => void) {
+ return subKey(state, key, callback);
+ },
+
+ setToken(token: SendControllerState['token']) {
+ if (token) {
+ state.token = ref(token);
+ }
+ },
+
+ setTokenAmount(sendTokenAmount: SendControllerState['sendTokenAmount']) {
+ state.sendTokenAmount = sendTokenAmount;
+ },
+
+ setReceiverAddress(receiverAddress: SendControllerState['receiverAddress']) {
+ state.receiverAddress = receiverAddress;
+ },
+
+ setReceiverProfileImageUrl(
+ receiverProfileImageUrl: SendControllerState['receiverProfileImageUrl']
+ ) {
+ state.receiverProfileImageUrl = receiverProfileImageUrl;
+ },
+
+ setReceiverProfileName(receiverProfileName: SendControllerState['receiverProfileName']) {
+ state.receiverProfileName = receiverProfileName;
+ },
+
+ setGasPrice(gasPrice: SendControllerState['gasPrice']) {
+ state.gasPrice = gasPrice;
+ },
+
+ setGasPriceInUsd(gasPriceInUSD: SendControllerState['gasPriceInUSD']) {
+ state.gasPriceInUSD = gasPriceInUSD;
+ },
+
+ setLoading(loading: SendControllerState['loading']) {
+ state.loading = loading;
+ },
+
+ sendToken() {
+ if (this.state.token?.address && this.state.sendTokenAmount && this.state.receiverAddress) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SEND_INITIATED',
+ properties: {
+ isSmartAccount: false,
+ token: this.state.token.address,
+ amount: this.state.sendTokenAmount,
+ network: NetworkController.state.caipNetwork?.id || ''
+ }
+ });
+ this.sendERC20Token({
+ receiverAddress: this.state.receiverAddress,
+ tokenAddress: this.state.token.address,
+ sendTokenAmount: this.state.sendTokenAmount,
+ decimals: this.state.token.quantity.decimals
+ });
+ } else if (
+ this.state.receiverAddress &&
+ this.state.sendTokenAmount &&
+ this.state.gasPrice &&
+ this.state.token?.quantity.decimals
+ ) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SEND_INITIATED',
+ properties: {
+ isSmartAccount: false,
+ token: this.state.token?.symbol,
+ amount: this.state.sendTokenAmount,
+ network: NetworkController.state.caipNetwork?.id || ''
+ }
+ });
+ this.sendNativeToken({
+ receiverAddress: this.state.receiverAddress,
+ sendTokenAmount: this.state.sendTokenAmount,
+ gasPrice: this.state.gasPrice,
+ decimals: this.state.token.quantity.decimals
+ });
+ }
+ },
+
+ async sendNativeToken(params: TxParams) {
+ // RouterController.pushTransactionStack({
+ // view: 'Account',
+ // goBack: false
+ // });
+
+ const to = params.receiverAddress as `0x${string}`;
+ const address = AccountController.state.address as `0x${string}`;
+ const value = ConnectionController.parseUnits(
+ params.sendTokenAmount.toString(),
+ Number(params.decimals)
+ );
+ const data = '0x';
+
+ try {
+ await ConnectionController.sendTransaction({
+ to,
+ address,
+ data,
+ value,
+ gasPrice: params.gasPrice
+ });
+ SnackController.showSuccess('Transaction started');
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SEND_SUCCESS',
+ properties: {
+ isSmartAccount: false,
+ token: this.state.token?.symbol || '',
+ amount: params.sendTokenAmount,
+ network: NetworkController.state.caipNetwork?.id || ''
+ }
+ });
+ this.resetSend();
+ } catch (error) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SEND_ERROR',
+ properties: {
+ isSmartAccount: false,
+ token: this.state.token?.symbol || '',
+ amount: params.sendTokenAmount,
+ network: NetworkController.state.caipNetwork?.id || ''
+ }
+ });
+ SnackController.showError('Something went wrong');
+ }
+ },
+
+ async sendERC20Token(params: ContractWriteParams) {
+ // RouterController.pushTransactionStack({
+ // view: 'Account',
+ // goBack: false
+ // });
+
+ const amount = ConnectionController.parseUnits(
+ params.sendTokenAmount.toString(),
+ Number(params.decimals)
+ );
+
+ try {
+ if (
+ AccountController.state.address &&
+ params.sendTokenAmount &&
+ params.receiverAddress &&
+ params.tokenAddress
+ ) {
+ await ConnectionController.writeContract({
+ fromAddress: AccountController.state.address as `0x${string}`,
+ tokenAddress: CoreHelperUtil.getPlainAddress(
+ params.tokenAddress as `${string}:${string}:${string}`
+ ) as `0x${string}`,
+ receiverAddress: params.receiverAddress as `0x${string}`,
+ tokenAmount: amount,
+ method: 'transfer',
+ abi: erc20ABI
+ });
+ SnackController.showSuccess('Transaction started');
+ this.resetSend();
+ }
+ } catch (error) {
+ SnackController.showError('Something went wrong');
+ }
+ },
+
+ resetSend() {
+ state.token = undefined;
+ state.sendTokenAmount = undefined;
+ state.receiverAddress = undefined;
+ state.receiverProfileImageUrl = undefined;
+ state.receiverProfileName = undefined;
+ state.loading = false;
+ }
+};
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index e8721aedb..121da526e 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -334,8 +334,66 @@ export type Event =
cursor: string | undefined;
isSmartAccount: boolean;
};
+ }
+ | {
+ type: 'track';
+ event: 'OPEN_SEND';
+ properties: {
+ isSmartAccount: boolean;
+ network: string;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'SEND_INITIATED';
+ properties: {
+ isSmartAccount: boolean;
+ network: string;
+ token: string;
+ amount: number;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'SEND_SUCCESS';
+ properties: {
+ isSmartAccount: boolean;
+ network: string;
+ token: string;
+ amount: number;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'SEND_ERROR';
+ properties: {
+ isSmartAccount: boolean;
+ network: string;
+ token: string;
+ amount: number;
+ };
};
+// -- Send Controller Types -------------------------------------
+
+export interface SendTransactionArgs {
+ to: `0x${string}`;
+ data: `0x${string}`;
+ value: bigint;
+ gas?: bigint;
+ gasPrice: bigint;
+ address: `0x${string}`;
+}
+
+export interface WriteContractArgs {
+ receiverAddress: `0x${string}`;
+ tokenAmount: bigint;
+ tokenAddress: `0x${string}`;
+ fromAddress: `0x${string}`;
+ method: 'send' | 'transfer' | 'call';
+ abi: any;
+}
+
// -- Email Types ------------------------------------------------
/**
* Matches type defined for packages/email/src/W3mFrameProvider.ts
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 36ead8d20..1619bc6c4 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -1,10 +1,15 @@
import {
+ BrowserProvider,
+ Contract,
InfuraProvider,
JsonRpcProvider,
+ JsonRpcSigner,
formatEther,
+ formatUnits,
getAddress,
hexlify,
isHexString,
+ parseUnits,
toUtf8Bytes
} from 'ethers';
import {
@@ -16,8 +21,10 @@ import {
type LibraryOptions,
type NetworkControllerClient,
type PublicStateControllerState,
+ type SendTransactionArgs,
type Token,
- Web3ModalScaffold
+ Web3ModalScaffold,
+ type WriteContractArgs
} from '@web3modal/scaffold-react-native';
import { NetworkUtil } from '@web3modal/common-react-native';
import {
@@ -275,6 +282,67 @@ export class Web3Modal extends Web3ModalScaffold {
});
return signature as `0x${string}`;
+ },
+
+ parseUnits: (value: string, decimals: number) => parseUnits(value, decimals),
+
+ formatUnits: (value: bigint, decimals: number) => formatUnits(value, decimals),
+
+ sendTransaction: async (data: SendTransactionArgs) => {
+ const { chainId, provider, address } = EthersStoreUtil.state;
+
+ if (!provider) {
+ throw new Error('ethersClient:sendTransaction - provider is undefined');
+ }
+
+ if (!address) {
+ throw new Error('ethersClient:sendTransaction - address is undefined');
+ }
+
+ const txParams = {
+ to: data.to,
+ value: data.value,
+ gasLimit: data.gas,
+ gasPrice: data.gasPrice,
+ data: data.data,
+ type: 0
+ };
+
+ const browserProvider = new BrowserProvider(provider, chainId);
+ const signer = new JsonRpcSigner(browserProvider, address);
+ const txResponse = await signer.sendTransaction(txParams);
+ const txReceipt = await txResponse.wait();
+
+ return (txReceipt?.hash as `0x${string}`) || null;
+ },
+
+ writeContract: async (data: WriteContractArgs) => {
+ const { chainId, provider, address } = EthersStoreUtil.state;
+
+ if (!provider) {
+ throw new Error('ethersClient:writeContract - provider is undefined');
+ }
+
+ if (!address) {
+ throw new Error('ethersClient:writeContract - address is undefined');
+ }
+
+ const browserProvider = new BrowserProvider(provider, chainId);
+ const signer = new JsonRpcSigner(browserProvider, address);
+ const contract = new Contract(data.tokenAddress, data.abi, signer);
+
+ if (!contract || !data.method) {
+ throw new Error('Contract method is undefined');
+ }
+
+ const method = contract[data.method];
+ if (method) {
+ const tx = await method(data.receiverAddress, data.tokenAmount);
+
+ return tx;
+ }
+
+ throw new Error('Contract method is undefined');
}
};
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index c2ee1dbd7..670eddb4d 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -8,6 +8,7 @@ import {
type LibraryOptions,
type NetworkControllerClient,
type PublicStateControllerState,
+ type SendTransactionArgs,
type Token,
Web3ModalScaffold
} from '@web3modal/scaffold-react-native';
@@ -268,7 +269,71 @@ export class Web3Modal extends Web3ModalScaffold {
});
return signature as `0x${string}`;
+ },
+
+ parseUnits: (value: string, decimals: number) =>
+ ethers.utils.parseUnits(value, decimals).toBigInt(),
+
+ formatUnits: (value: bigint, decimals: number) => ethers.utils.formatUnits(value, decimals),
+
+ sendTransaction: async (data: SendTransactionArgs) => {
+ const provider = EthersStoreUtil.state.provider;
+ const address = EthersStoreUtil.state.address;
+
+ if (!provider) {
+ throw new Error('connectionControllerClient:sendTransaction - provider is undefined');
+ }
+
+ if (!address) {
+ throw new Error('connectionControllerClient:sendTransaction - address is undefined');
+ }
+
+ const txParams = {
+ to: data.to,
+ value: data.value,
+ gasLimit: data.gas,
+ gasPrice: data.gasPrice,
+ data: data.data,
+ type: 0
+ };
+
+ const browserProvider = new ethers.providers.Web3Provider(provider);
+ const signer = browserProvider.getSigner();
+
+ const txResponse = await signer.sendTransaction(txParams);
+ const txReceipt = await txResponse.wait();
+
+ return (txReceipt?.blockHash as `0x${string}`) || null;
}
+
+ // writeContract: async (data: WriteContractArgs) => {
+ // const { chainId, provider, address } = EthersStoreUtil.state;
+
+ // if (!provider) {
+ // throw new Error('ethersClient:writeContract - provider is undefined');
+ // }
+
+ // if (!address) {
+ // throw new Error('ethersClient:writeContract - address is undefined');
+ // }
+
+ // const browserProvider = new BrowserProvider(provider, chainId);
+ // const signer = new JsonRpcSigner(browserProvider, address);
+ // const contract = new Contract(data.tokenAddress, data.abi, signer);
+
+ // if (!contract || !data.method) {
+ // throw new Error('Contract method is undefined');
+ // }
+
+ // const method = contract[data.method];
+ // if (method) {
+ // const tx = await method(data.receiverAddress, data.tokenAmount);
+
+ // return tx;
+ // }
+
+ // throw new Error('Contract method is undefined');
+ // }
};
super({
diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts
index 6abe5c721..0b1832af6 100644
--- a/packages/scaffold/src/client.ts
+++ b/packages/scaffold/src/client.ts
@@ -142,6 +142,8 @@ export class Web3ModalScaffold {
AccountController.setCaipAddress(caipAddress);
};
+ protected getCaipAddress = () => AccountController.state.caipAddress;
+
protected setBalance: (typeof AccountController)['setBalance'] = (balance, balanceSymbol) => {
AccountController.setBalance(balance, balanceSymbol);
};
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index 68abd6932..7d2a6be9d 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -24,6 +24,7 @@ import { AccountView } from '../../views/w3m-account-view';
import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-networks-view';
import { TransactionsView } from '../../views/w3m-transactions-view';
+import { WalletSendView } from '../../views/w3m-wallet-send-view';
export function Web3Router() {
const { view } = useSnapshot(RouterController.state);
@@ -68,10 +69,12 @@ export function Web3Router() {
return UpdateEmailWalletView;
case 'UpgradeEmailWallet':
return UpgradeEmailWalletView;
- case 'WalletReceive':
- return WalletReceiveView;
case 'WalletCompatibleNetworks':
return WalletCompatibleNetworks;
+ case 'WalletReceive':
+ return WalletReceiveView;
+ case 'WalletSend':
+ return WalletSendView;
case 'WhatIsANetwork':
return WhatIsNetworkView;
case 'WhatIsAWallet':
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index b75fa7b8e..5a3e680a8 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -5,8 +5,8 @@ import {
AccountController,
CoreHelperUtil,
EventsController,
- RouterController,
- SnackController
+ NetworkController,
+ RouterController
} from '@web3modal/core-react-native';
import type { Balance as BalanceType } from '@web3modal/common-react-native';
import { AccountNfts } from '../w3m-account-nfts';
@@ -21,6 +21,7 @@ export interface AccountWalletFeaturesProps {
export function AccountWalletFeatures() {
const [activeTab, setActiveTab] = useState(0);
const { tokenBalance } = useSnapshot(AccountController.state);
+ const { caipNetwork } = useSnapshot(NetworkController.state);
const balance = CoreHelperUtil.calculateAndFormatBalance(tokenBalance as BalanceType[]);
const onTabChange = (index: number) => {
@@ -40,9 +41,16 @@ export function AccountWalletFeatures() {
});
};
- // TODO: Implement this features
- const onMissingPress = () => {
- SnackController.showError('Feature not implemented');
+ const onSendPress = () => {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'OPEN_SEND',
+ properties: {
+ network: caipNetwork?.id || '',
+ isSmartAccount: false
+ }
+ });
+ RouterController.push('WalletSend');
};
const onReceivePress = () => {
@@ -76,7 +84,7 @@ export function AccountWalletFeatures() {
backgroundColor="accent-glass-010"
pressedColor="accent-glass-020"
style={[styles.action, styles.actionRight]}
- onPress={onMissingPress}
+ onPress={onSendPress}
/>
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index cf94f9fd3..f38f37479 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -35,6 +35,9 @@ export function Header() {
UpgradeEmailWallet: 'Upgrade wallet',
WalletCompatibleNetworks: 'Compatible networks',
WalletReceive: 'Receive',
+ WalletSend: 'Send',
+ WalletSendPreview: 'Review send',
+ WalletSendSelectToken: 'Select token',
WhatIsANetwork: 'What is a network?',
WhatIsAWallet: 'What is a wallet?'
};
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
new file mode 100644
index 000000000..d69077810
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -0,0 +1,10 @@
+import { View, Text } from 'react-native';
+import styles from './styles';
+
+export function WalletSendView() {
+ return (
+
+ SEND
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
new file mode 100644
index 000000000..c866ab3d8
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
@@ -0,0 +1,8 @@
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ container: {
+ justifyContent: 'center',
+ alignItems: 'center'
+ }
+});
diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts
index c7189ecf1..d5d5f9364 100644
--- a/packages/wagmi/src/client.ts
+++ b/packages/wagmi/src/client.ts
@@ -1,15 +1,20 @@
-import { formatUnits, type Hex } from 'viem';
+import { formatUnits, type Hex, parseUnits } from 'viem';
import {
type GetAccountReturnType,
connect,
disconnect,
signMessage,
+ getAccount,
switchChain,
watchAccount,
watchConnectors,
getEnsName,
getEnsAvatar as wagmiGetEnsAvatar,
- getBalance
+ getBalance,
+ prepareTransactionRequest,
+ sendTransaction as wagmiSendTransaction,
+ waitForTransactionReceipt,
+ writeContract as wagmiWriteContract
} from '@wagmi/core';
import { mainnet, type Chain } from '@wagmi/core/chains';
import { EthereumProvider, OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
@@ -22,8 +27,10 @@ import {
type LibraryOptions,
type NetworkControllerClient,
type PublicStateControllerState,
+ type SendTransactionArgs,
type Token,
- Web3ModalScaffold
+ Web3ModalScaffold,
+ type WriteContractArgs
} from '@web3modal/scaffold-react-native';
import {
ConstantsUtil,
@@ -32,13 +39,14 @@ import {
StorageUtil
} from '@web3modal/scaffold-utils-react-native';
import { NetworkUtil } from '@web3modal/common-react-native';
+import { type Web3ModalSIWEClient } from '@web3modal/siwe-react-native';
import {
getCaipDefaultChain,
getEmailCaipNetworks,
- getWalletConnectCaipNetworks
+ getWalletConnectCaipNetworks,
+ requireCaipAddress
} from './utils/helpers';
import { defaultWagmiConfig } from './utils/defaultWagmiConfig';
-import { type Web3ModalSIWEClient } from '@web3modal/siwe-react-native';
// -- Types ---------------------------------------------------------------------
type WagmiConfig = ReturnType;
@@ -227,7 +235,50 @@ export class Web3Modal extends Web3ModalScaffold {
const { SIWEController } = await import('@web3modal/siwe-react-native');
await SIWEController.signOut();
}
- }
+ },
+
+ sendTransaction: async (data: SendTransactionArgs) => {
+ const { chainId } = getAccount(this.wagmiConfig);
+
+ const txParams = {
+ account: data.address,
+ to: data.to,
+ value: data.value,
+ gas: data.gas,
+ gasPrice: data.gasPrice,
+ data: data.data,
+ chainId,
+ type: 'legacy' as const
+ };
+
+ await prepareTransactionRequest(this.wagmiConfig, txParams);
+ const tx = await wagmiSendTransaction(this.wagmiConfig, txParams);
+
+ await waitForTransactionReceipt(this.wagmiConfig, { hash: tx, timeout: 25000 });
+
+ return tx;
+ },
+
+ writeContract: async (data: WriteContractArgs) => {
+ const caipAddress = this.getCaipAddress() || '';
+ const account = requireCaipAddress(caipAddress);
+ const chainId = NetworkUtil.caipNetworkIdToNumber(this.getCaipNetwork()?.id);
+
+ const tx = await wagmiWriteContract(wagmiConfig, {
+ chainId,
+ address: data.tokenAddress,
+ account,
+ abi: data.abi,
+ functionName: data.method,
+ args: [data.receiverAddress, data.tokenAmount]
+ });
+
+ return tx;
+ },
+
+ parseUnits,
+
+ formatUnits
};
super({
diff --git a/packages/wagmi/src/utils/helpers.ts b/packages/wagmi/src/utils/helpers.ts
index bab0ff02c..63b2e6a3f 100644
--- a/packages/wagmi/src/utils/helpers.ts
+++ b/packages/wagmi/src/utils/helpers.ts
@@ -7,7 +7,7 @@ import { PresetsUtil, ConstantsUtil } from '@web3modal/scaffold-utils-react-nati
import type { Connector } from '@wagmi/core';
import { EthereumProvider } from '@walletconnect/ethereum-provider';
import type { Web3ModalClientOptions } from '../client';
-import { http } from 'viem';
+import { http, type Hex } from 'viem';
export function getCaipDefaultChain(chain?: Web3ModalClientOptions['defaultChain']) {
if (!chain) {
@@ -56,3 +56,15 @@ export function getTransport({ chainId, projectId }: { chainId: number; projectI
return http(`${RPC_URL}/v1/?chainId=${ConstantsUtil.EIP155}:${chainId}&projectId=${projectId}`);
}
+
+export function requireCaipAddress(caipAddress: string) {
+ if (!caipAddress) {
+ throw new Error('No CAIP address provided');
+ }
+ const account = caipAddress.split(':')[2] as Hex;
+ if (!account) {
+ throw new Error('Invalid CAIP address');
+ }
+
+ return account;
+}
From 087190f44076ba410a177ef375a37487f3ddb4aa Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 27 Aug 2024 18:01:40 -0300
Subject: [PATCH 029/114] chore: wip send screen
---
packages/common/package.json | 1 +
packages/common/src/index.ts | 3 +-
packages/common/src/utils/NumberUtil.ts | 31 +++++++
packages/core/src/index.ts | 2 +
.../src/partials/w3m-input-token/intex.tsx | 90 +++++++++++++++++++
.../src/partials/w3m-input-token/styles.ts | 20 +++++
.../src/partials/w3m-input-token/utils.ts | 21 +++++
.../src/views/w3m-account-view/index.tsx | 2 +
.../src/views/w3m-wallet-send-view/index.tsx | 84 ++++++++++++++++-
.../src/views/w3m-wallet-send-view/styles.ts | 21 ++++-
yarn.lock | 8 ++
11 files changed, 275 insertions(+), 8 deletions(-)
create mode 100644 packages/common/src/utils/NumberUtil.ts
create mode 100644 packages/scaffold/src/partials/w3m-input-token/intex.tsx
create mode 100644 packages/scaffold/src/partials/w3m-input-token/styles.ts
create mode 100644 packages/scaffold/src/partials/w3m-input-token/utils.ts
diff --git a/packages/common/package.json b/packages/common/package.json
index 67e8fcddd..cfc0e8128 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -12,6 +12,7 @@
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
},
"dependencies": {
+ "bignumber.js": "9.1.2",
"dayjs": "1.11.10"
},
"files": [
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 67fc41c28..7e84124c2 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -1,5 +1,6 @@
export { ConstantsUtil } from './utils/ConstantsUtil';
-export { NetworkUtil } from './utils/NetworkUtil';
export { DateUtil } from './utils/DateUtil';
+export { NetworkUtil } from './utils/NetworkUtil';
+export { NumberUtil } from './utils/NumberUtil';
export { erc20ABI } from './contracts/erc20';
export * from './utils/TypeUtil';
diff --git a/packages/common/src/utils/NumberUtil.ts b/packages/common/src/utils/NumberUtil.ts
new file mode 100644
index 000000000..760071bad
--- /dev/null
+++ b/packages/common/src/utils/NumberUtil.ts
@@ -0,0 +1,31 @@
+import * as BigNumber from 'bignumber.js';
+
+export const NumberUtil = {
+ bigNumber(value: BigNumber.BigNumber.Value) {
+ return new BigNumber.BigNumber(value);
+ },
+
+ /**
+ * Multiply two numbers represented as strings with BigNumber to handle decimals correctly
+ * @param a string
+ * @param b string
+ * @returns
+ */
+ multiply(a: BigNumber.BigNumber.Value | undefined, b: BigNumber.BigNumber.Value | undefined) {
+ if (a === undefined || b === undefined) {
+ return BigNumber.BigNumber(0);
+ }
+
+ const aBigNumber = new BigNumber.BigNumber(a);
+ const bBigNumber = new BigNumber.BigNumber(b);
+
+ return aBigNumber.multipliedBy(bBigNumber);
+ },
+
+ roundNumber(number: number, threshold: number, fixed: number) {
+ const roundedNumber =
+ number.toString().length >= threshold ? Number(number).toFixed(fixed) : number;
+
+ return roundedNumber;
+ }
+};
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 0d9b5eb55..e1e8c96be 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -50,6 +50,8 @@ export {
type TransactionsControllerState
} from './controllers/TransactionsController';
+export { SendController, type SendControllerState } from './controllers/SendController';
+
// -- Utils -------------------------------------------------------------------
export { AssetUtil } from './utils/AssetUtil';
export { ConstantsUtil } from './utils/ConstantsUtil';
diff --git a/packages/scaffold/src/partials/w3m-input-token/intex.tsx b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
new file mode 100644
index 000000000..517b9ac90
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
@@ -0,0 +1,90 @@
+import { TextInput, type StyleProp, type ViewStyle } from 'react-native';
+import { FlexView, Link, Text, useTheme } from '@web3modal/ui-react-native';
+import { NumberUtil, type Balance } from '@web3modal/common-react-native';
+import styles from './styles';
+
+import { SendController } from '@web3modal/core-react-native';
+import { getMaxAmount, getSendValue } from './utils';
+
+export interface InputTokenProps {
+ token?: Balance;
+ sendTokenAmount?: number;
+ gasPriceInUSD?: number;
+ style?: StyleProp;
+}
+
+export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: InputTokenProps) {
+ const Theme = useTheme();
+ const sendValue = getSendValue(token, sendTokenAmount);
+ const maxAmount = getMaxAmount(token);
+ const maxError = token && sendTokenAmount && sendTokenAmount > Number(token.quantity.numeric);
+
+ const onInputChange = (value: string) => {
+ const formattedValue = value.replace(/,/g, '.');
+ Number(formattedValue)
+ ? SendController.setTokenAmount(Number(formattedValue))
+ : SendController.setTokenAmount(undefined);
+ };
+
+ const onMaxPress = () => {
+ if (token && gasPriceInUSD) {
+ const amountOfTokenGasRequires = NumberUtil.bigNumber(gasPriceInUSD.toFixed(5)).dividedBy(
+ token.price
+ );
+
+ const isNetworkToken = token.address === undefined;
+
+ const maxValue = isNetworkToken
+ ? NumberUtil.bigNumber(token.quantity.numeric).minus(amountOfTokenGasRequires)
+ : NumberUtil.bigNumber(token.quantity.numeric);
+
+ SendController.setTokenAmount(Number(maxValue.toFixed(20)));
+ }
+ };
+
+ return (
+
+
+
+ ETH
+
+
+
+ {sendValue ?? ''}
+
+
+
+ {maxAmount ?? '1.204 tst'}
+
+ Max
+
+
+
+ );
+}
diff --git a/packages/scaffold/src/partials/w3m-input-token/styles.ts b/packages/scaffold/src/partials/w3m-input-token/styles.ts
new file mode 100644
index 000000000..fa338ac9f
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-input-token/styles.ts
@@ -0,0 +1,20 @@
+import { BorderRadius, Spacing } from '@web3modal/ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ container: {
+ height: 100,
+ width: '100%',
+ borderRadius: BorderRadius.s,
+ borderWidth: 1
+ },
+ input: {
+ fontSize: 32,
+ flex: 1,
+ marginRight: Spacing.xs
+ },
+ sendValue: {
+ flex: 1,
+ marginRight: Spacing.xs
+ }
+});
diff --git a/packages/scaffold/src/partials/w3m-input-token/utils.ts b/packages/scaffold/src/partials/w3m-input-token/utils.ts
new file mode 100644
index 000000000..6f384082b
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-input-token/utils.ts
@@ -0,0 +1,21 @@
+import { type Balance, NumberUtil } from '@web3modal/common-react-native';
+import { UiUtil } from '@web3modal/ui-react-native';
+
+export function getSendValue(token?: Balance, sendTokenAmount?: number) {
+ if (token && sendTokenAmount) {
+ const price = token.price;
+ const totalValue = price * sendTokenAmount;
+
+ return totalValue ? `$${UiUtil.formatNumberToLocalString(totalValue, 2)}` : 'Incorrect value';
+ }
+
+ return null;
+}
+
+export function getMaxAmount(token?: Balance) {
+ if (token) {
+ NumberUtil.roundNumber(Number(token.quantity.numeric), 6, 5);
+ }
+
+ return null;
+}
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index 395f4bc87..3e4152237 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -17,6 +17,7 @@ import {
NetworkController,
OptionsController,
RouterController,
+ SendController,
SnackController
} from '@web3modal/core-react-native';
import { AccountWalletFeatures } from '../../partials/w3m-account-wallet-features';
@@ -46,6 +47,7 @@ export function AccountView() {
useEffect(() => {
AccountController.fetchTokenBalance();
+ SendController.resetSend();
}, []);
return (
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index d69077810..12bedcb62 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -1,10 +1,86 @@
-import { View, Text } from 'react-native';
+import { useEffect } from 'react';
+import { Platform, ScrollView } from 'react-native';
+import { useSnapshot } from 'valtio';
+import { AccountController, SendController } from '@web3modal/core-react-native';
+import {
+ Button,
+ FlexView,
+ IconBox,
+ LoadingSpinner,
+ Spacing,
+ Text
+} from '@web3modal/ui-react-native';
+import { InputToken } from '../../partials/w3m-input-token/intex';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import { useKeyboard } from '../../hooks/useKeyboard';
import styles from './styles';
export function WalletSendView() {
+ const { padding } = useCustomDimensions();
+ const { keyboardShown, keyboardHeight } = useKeyboard();
+ const { token, sendTokenAmount, receiverAddress, receiverProfileName, loading, gasPriceInUSD } =
+ useSnapshot(SendController.state);
+ const { tokenBalance } = useSnapshot(AccountController.state);
+
+ const paddingBottom = Platform.select({
+ android: keyboardShown ? keyboardHeight + Spacing['2xl'] : Spacing['2xl'],
+ default: Spacing['2xl']
+ });
+
+ const onSendPress = () => {
+ if (loading) return;
+ };
+
+ const getActionText = () => {
+ if (token && sendTokenAmount && sendTokenAmount > Number(token.quantity.numeric)) {
+ return 'Insufficient balance';
+ }
+
+ return 'Send';
+ };
+
+ useEffect(() => {
+ // TODO: remove this
+ SendController.setToken(tokenBalance[0]);
+ }, [tokenBalance]);
+
return (
-
- SEND
-
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
index c866ab3d8..ae86e5648 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
@@ -1,8 +1,23 @@
+import { Spacing } from '@web3modal/ui-react-native';
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
- container: {
- justifyContent: 'center',
- alignItems: 'center'
+ sendButton: {
+ width: '100%',
+ marginTop: Spacing.xl
+ },
+ tokenInput: {
+ marginBottom: Spacing.xs
+ },
+ mockInput: {
+ width: '100%',
+ borderWidth: 1,
+ height: 120,
+ borderRadius: 20
+ },
+ arrowIcon: {
+ position: 'absolute',
+ top: -30,
+ borderRadius: 20
}
});
diff --git a/yarn.lock b/yarn.lock
index fc776e2d5..616a8382a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10700,6 +10700,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@web3modal/common-react-native@workspace:packages/common"
dependencies:
+ bignumber.js: "npm:9.1.2"
dayjs: "npm:1.11.10"
languageName: unknown
linkType: soft
@@ -12054,6 +12055,13 @@ __metadata:
languageName: node
linkType: hard
+"bignumber.js@npm:9.1.2":
+ version: 9.1.2
+ resolution: "bignumber.js@npm:9.1.2"
+ checksum: e17786545433f3110b868725c449fa9625366a6e675cd70eb39b60938d6adbd0158cb4b3ad4f306ce817165d37e63f4aa3098ba4110db1d9a3b9f66abfbaf10d
+ languageName: node
+ linkType: hard
+
"binary-extensions@npm:^2.0.0":
version: 2.2.0
resolution: "binary-extensions@npm:2.2.0"
From fa3fa541c2266ac607d66081cabc930afd43551e Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 3 Sep 2024 17:05:39 -0300
Subject: [PATCH 030/114] chore: adding send view
---
.../src/partials/w3m-input-address/index.tsx | 46 +++++++++++++++++++
.../src/partials/w3m-input-address/styles.ts | 15 ++++++
.../src/partials/w3m-input-token/intex.tsx | 27 +++++++----
.../src/partials/w3m-input-token/utils.ts | 2 +-
.../src/views/w3m-wallet-send-view/index.tsx | 11 +++--
.../src/views/w3m-wallet-send-view/styles.ts | 3 ++
.../ui/src/composites/wui-button/index.tsx | 4 +-
.../ui/src/composites/wui-button/styles.ts | 2 +-
.../src/composites/wui-token-button/index.tsx | 18 ++++++++
.../src/composites/wui-token-button/styles.ts | 14 ++++++
packages/ui/src/index.ts | 1 +
11 files changed, 126 insertions(+), 17 deletions(-)
create mode 100644 packages/scaffold/src/partials/w3m-input-address/index.tsx
create mode 100644 packages/scaffold/src/partials/w3m-input-address/styles.ts
create mode 100644 packages/ui/src/composites/wui-token-button/index.tsx
create mode 100644 packages/ui/src/composites/wui-token-button/styles.ts
diff --git a/packages/scaffold/src/partials/w3m-input-address/index.tsx b/packages/scaffold/src/partials/w3m-input-address/index.tsx
new file mode 100644
index 000000000..7c5acc15d
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-input-address/index.tsx
@@ -0,0 +1,46 @@
+import { TextInput } from 'react-native';
+import { FlexView, useTheme } from '@web3modal/ui-react-native';
+import { SendController } from '@web3modal/core-react-native';
+import styles from './styles';
+
+export interface InputAddressProps {
+ value?: string;
+}
+
+export function InputAddress({ value }: InputAddressProps) {
+ const Theme = useTheme();
+
+ const onInputChange = (address: string) => {
+ SendController.setReceiverAddress(address);
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/scaffold/src/partials/w3m-input-address/styles.ts b/packages/scaffold/src/partials/w3m-input-address/styles.ts
new file mode 100644
index 000000000..5a4b2e7ed
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-input-address/styles.ts
@@ -0,0 +1,15 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius } from '@web3modal/ui-react-native';
+
+export default StyleSheet.create({
+ container: {
+ height: 100,
+ width: '100%',
+ borderRadius: BorderRadius.s,
+ borderWidth: 1
+ },
+ input: {
+ fontSize: 18,
+ flex: 1
+ }
+});
diff --git a/packages/scaffold/src/partials/w3m-input-token/intex.tsx b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
index 517b9ac90..ec65d3890 100644
--- a/packages/scaffold/src/partials/w3m-input-token/intex.tsx
+++ b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
@@ -1,9 +1,10 @@
+import { useState } from 'react';
import { TextInput, type StyleProp, type ViewStyle } from 'react-native';
-import { FlexView, Link, Text, useTheme } from '@web3modal/ui-react-native';
+import { FlexView, Link, Text, useTheme, TokenButton } from '@web3modal/ui-react-native';
import { NumberUtil, type Balance } from '@web3modal/common-react-native';
-import styles from './styles';
-
import { SendController } from '@web3modal/core-react-native';
+
+import styles from './styles';
import { getMaxAmount, getSendValue } from './utils';
export interface InputTokenProps {
@@ -15,12 +16,14 @@ export interface InputTokenProps {
export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: InputTokenProps) {
const Theme = useTheme();
+ const [inputValue, setInputValue] = useState(undefined);
const sendValue = getSendValue(token, sendTokenAmount);
const maxAmount = getMaxAmount(token);
const maxError = token && sendTokenAmount && sendTokenAmount > Number(token.quantity.numeric);
const onInputChange = (value: string) => {
const formattedValue = value.replace(/,/g, '.');
+ setInputValue(formattedValue);
Number(formattedValue)
? SendController.setTokenAmount(Number(formattedValue))
: SendController.setTokenAmount(undefined);
@@ -28,17 +31,18 @@ export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: Inp
const onMaxPress = () => {
if (token && gasPriceInUSD) {
- const amountOfTokenGasRequires = NumberUtil.bigNumber(gasPriceInUSD.toFixed(5)).dividedBy(
+ const amountOfTokenGasRequired = NumberUtil.bigNumber(gasPriceInUSD.toFixed(5)).dividedBy(
token.price
);
const isNetworkToken = token.address === undefined;
const maxValue = isNetworkToken
- ? NumberUtil.bigNumber(token.quantity.numeric).minus(amountOfTokenGasRequires)
+ ? NumberUtil.bigNumber(token.quantity.numeric).minus(amountOfTokenGasRequired)
: NumberUtil.bigNumber(token.quantity.numeric);
SendController.setTokenAmount(Number(maxValue.toFixed(20)));
+ setInputValue(maxValue.toFixed(20));
}
};
@@ -60,7 +64,7 @@ export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: Inp
style={[styles.input, { color: Theme['fg-100'] }]}
autoCapitalize="none"
autoCorrect={false}
- value={sendTokenAmount?.toLocaleString()}
+ value={inputValue}
onChangeText={onInputChange}
keyboardType="decimal-pad"
inputMode="decimal"
@@ -72,15 +76,20 @@ export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: Inp
numberOfLines={1}
autoFocus={!!token}
/>
- ETH
+
-
+
{sendValue ?? ''}
- {maxAmount ?? '1.204 tst'}
+ {maxAmount ?? ''}
Max
diff --git a/packages/scaffold/src/partials/w3m-input-token/utils.ts b/packages/scaffold/src/partials/w3m-input-token/utils.ts
index 6f384082b..158ba144c 100644
--- a/packages/scaffold/src/partials/w3m-input-token/utils.ts
+++ b/packages/scaffold/src/partials/w3m-input-token/utils.ts
@@ -14,7 +14,7 @@ export function getSendValue(token?: Balance, sendTokenAmount?: number) {
export function getMaxAmount(token?: Balance) {
if (token) {
- NumberUtil.roundNumber(Number(token.quantity.numeric), 6, 5);
+ return NumberUtil.roundNumber(Number(token.quantity.numeric), 6, 5);
}
return null;
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index 12bedcb62..641d1799e 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -13,6 +13,7 @@ import {
import { InputToken } from '../../partials/w3m-input-token/intex';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import { useKeyboard } from '../../hooks/useKeyboard';
+import { InputAddress } from '../../partials/w3m-input-address';
import styles from './styles';
export function WalletSendView() {
@@ -36,12 +37,12 @@ export function WalletSendView() {
return 'Insufficient balance';
}
- return 'Send';
+ return 'Preview Send';
};
useEffect(() => {
- // TODO: remove this
- SendController.setToken(tokenBalance[0]);
+ // TODO: check this
+ SendController.setToken(tokenBalance?.[0]);
}, [tokenBalance]);
return (
@@ -57,8 +58,8 @@ export function WalletSendView() {
gasPriceInUSD={gasPriceInUSD}
style={styles.tokenInput}
/>
-
-
+
+
- ) : (
+ ) : typeof children === 'string' ? (
{children}
+ ) : (
+ children
)}
{iconRight && (
+ {imageSrc && }
+ {text}
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-token-button/styles.ts b/packages/ui/src/composites/wui-token-button/styles.ts
new file mode 100644
index 000000000..ad753204b
--- /dev/null
+++ b/packages/ui/src/composites/wui-token-button/styles.ts
@@ -0,0 +1,14 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
+
+export default StyleSheet.create({
+ container: {
+ height: 40
+ },
+ image: {
+ width: 24,
+ height: 24,
+ borderRadius: BorderRadius.full,
+ marginRight: Spacing['2xs']
+ }
+});
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 5b8df3e18..e3c05c2c0 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -53,6 +53,7 @@ export { SearchBar, type SearchBarProps } from './composites/wui-search-bar';
export { Snackbar, type SnackbarProps } from './composites/wui-snackbar';
export { Tabs, type TabsProps } from './composites/wui-tabs';
export { Tag, type TagProps } from './composites/wui-tag';
+export { TokenButton, type TokenButtonProps } from './composites/wui-token-button';
export { Tooltip, type TooltipProps } from './composites/wui-tooltip';
export { WalletImage, type WalletImageProps } from './composites/wui-wallet-image';
From c30cfe6bb0c5c87e53942501527e0f0b8c716c6d Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 5 Sep 2024 14:59:39 -0300
Subject: [PATCH 031/114] chore: removed account redirect for universal wallets
---
packages/core/src/controllers/ModalController.ts | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/packages/core/src/controllers/ModalController.ts b/packages/core/src/controllers/ModalController.ts
index 5bbc51021..5b768354c 100644
--- a/packages/core/src/controllers/ModalController.ts
+++ b/packages/core/src/controllers/ModalController.ts
@@ -5,7 +5,6 @@ import { RouterController } from './RouterController';
import { PublicStateController } from './PublicStateController';
import { EventsController } from './EventsController';
import { ApiController } from './ApiController';
-import { ConnectorController } from './ConnectorController';
// -- Types --------------------------------------------- //
export interface ModalControllerState {
@@ -35,8 +34,7 @@ export const ModalController = {
if (options?.view) {
RouterController.reset(options.view);
} else if (AccountController.state.isConnected) {
- const isWallet = ConnectorController.state.connectedConnector === 'EMAIL';
- RouterController.reset(isWallet ? 'Account' : 'AccountDefault');
+ RouterController.reset('AccountDefault');
} else {
RouterController.reset('Connect');
}
From 411c192ec4c82d4d65a751788dd900cb2b721db6 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 5 Sep 2024 16:48:17 -0300
Subject: [PATCH 032/114] chore: removed changeset, solved ts error
---
.changeset/stupid-guests-turn.md | 18 ------------------
.../src/composites/wui-token-button/index.tsx | 7 ++++++-
2 files changed, 6 insertions(+), 19 deletions(-)
delete mode 100644 .changeset/stupid-guests-turn.md
diff --git a/.changeset/stupid-guests-turn.md b/.changeset/stupid-guests-turn.md
deleted file mode 100644
index 302af6e20..000000000
--- a/.changeset/stupid-guests-turn.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-'@web3modal/scaffold-react-native': minor
-'@web3modal/common-react-native': minor
-'@web3modal/email-react-native': minor
-'@web3modal/core-react-native': minor
-'@web3modal/siwe-react-native': minor
-'@web3modal/ui-react-native': minor
-'@web3modal/coinbase-ethers-react-native': minor
-'@web3modal/coinbase-wagmi-react-native': minor
-'@web3modal/email-ethers-react-native': minor
-'@web3modal/email-wagmi-react-native': minor
-'@web3modal/ethers-react-native': minor
-'@web3modal/ethers5-react-native': minor
-'@web3modal/scaffold-utils-react-native': minor
-'@web3modal/wagmi-react-native': minor
----
-
-feat: implemented wallet features for universal wallets
diff --git a/packages/ui/src/composites/wui-token-button/index.tsx b/packages/ui/src/composites/wui-token-button/index.tsx
index f50d3441a..551059544 100644
--- a/packages/ui/src/composites/wui-token-button/index.tsx
+++ b/packages/ui/src/composites/wui-token-button/index.tsx
@@ -4,11 +4,16 @@ import { Button } from '../wui-button';
import styles from './styles';
export interface TokenButtonProps {
- text: string;
+ text?: string;
imageSrc?: string;
}
export function TokenButton({ text, imageSrc }: TokenButtonProps) {
+ if (!text) {
+ // TODO: add empty state
+ return null;
+ }
+
return (
);
diff --git a/packages/scaffold/src/partials/w3m-input-address/styles.ts b/packages/scaffold/src/partials/w3m-input-address/styles.ts
index 9828b8504..bc2057216 100644
--- a/packages/scaffold/src/partials/w3m-input-address/styles.ts
+++ b/packages/scaffold/src/partials/w3m-input-address/styles.ts
@@ -9,7 +9,6 @@ export default StyleSheet.create({
borderWidth: 1
},
input: {
- fontSize: 18,
- flex: 1
+ fontSize: 18
}
});
diff --git a/packages/scaffold/src/partials/w3m-input-token/intex.tsx b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
index da1727b7f..e0de3293d 100644
--- a/packages/scaffold/src/partials/w3m-input-token/intex.tsx
+++ b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
@@ -1,4 +1,4 @@
-import { useState } from 'react';
+import { useRef, useState } from 'react';
import { TextInput, type StyleProp, type ViewStyle } from 'react-native';
import { FlexView, Link, Text, useTheme, TokenButton } from '@reown/appkit-ui-react-native';
import { NumberUtil, type Balance } from '@reown/appkit-common-react-native';
@@ -16,6 +16,7 @@ export interface InputTokenProps {
export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: InputTokenProps) {
const Theme = useTheme();
+ const valueInputRef = useRef(null);
const [inputValue, setInputValue] = useState(undefined);
const sendValue = getSendValue(token, sendTokenAmount);
const maxAmount = getMaxAmount(token);
@@ -43,6 +44,7 @@ export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: Inp
SendController.setTokenAmount(Number(maxValue.toFixed(20)));
setInputValue(maxValue.toFixed(20));
+ valueInputRef.current?.blur();
}
};
@@ -58,6 +60,7 @@ export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: Inp
>
{
+ await SwapController.getNetworkTokenPrice();
+ const gas = await SwapController.getInitialGasPrice();
+ if (gas?.gasPrice && gas?.gasPriceInUSD) {
+ SendController.setGasPrice(gas.gasPrice);
+ SendController.setGasPriceInUsd(gas.gasPriceInUSD);
+ }
+ }, []);
+
const onSendPress = () => {
if (SendController.state.loading) return;
};
@@ -47,7 +57,8 @@ export function WalletSendView() {
useEffect(() => {
// TODO: check this
SendController.setToken(tokenBalance?.[0]);
- }, [tokenBalance]);
+ fetchNetworkPrice();
+ }, [tokenBalance, fetchNetworkPrice]);
return (
-
+
Date: Thu, 19 Sep 2024 21:39:24 -0300
Subject: [PATCH 044/114] chore: working on preview send view
---
.../scaffold/src/modal/w3m-router/index.tsx | 3 +
.../src/partials/w3m-input-token/intex.tsx | 2 +-
.../components/preview-send-details.tsx | 55 ++++++++++++++++
.../components/preview-send-pill.tsx | 36 ++++++++++
.../w3m-wallet-send-preview-view/index.tsx | 66 +++++++++++++++++++
.../w3m-wallet-send-preview-view/styles.ts | 24 +++++++
.../src/views/w3m-wallet-send-view/index.tsx | 8 ++-
7 files changed, 192 insertions(+), 2 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index e1bb4b3fe..d3c514d92 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -25,6 +25,7 @@ import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-networks-view';
import { TransactionsView } from '../../views/w3m-transactions-view';
import { WalletSendView } from '../../views/w3m-wallet-send-view';
+import { WalletSendPreviewView } from '../../views/w3m-wallet-send-preview-view';
export function AppKitRouter() {
const { view } = useSnapshot(RouterController.state);
@@ -75,6 +76,8 @@ export function AppKitRouter() {
return WalletReceiveView;
case 'WalletSend':
return WalletSendView;
+ case 'WalletSendPreview':
+ return WalletSendPreviewView;
case 'WhatIsANetwork':
return WhatIsNetworkView;
case 'WhatIsAWallet':
diff --git a/packages/scaffold/src/partials/w3m-input-token/intex.tsx b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
index e0de3293d..ca27213bf 100644
--- a/packages/scaffold/src/partials/w3m-input-token/intex.tsx
+++ b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
@@ -17,7 +17,7 @@ export interface InputTokenProps {
export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: InputTokenProps) {
const Theme = useTheme();
const valueInputRef = useRef(null);
- const [inputValue, setInputValue] = useState(undefined);
+ const [inputValue, setInputValue] = useState(sendTokenAmount?.toString());
const sendValue = getSendValue(token, sendTokenAmount);
const maxAmount = getMaxAmount(token);
const maxError = token && sendTokenAmount && sendTokenAmount > Number(token.quantity.numeric);
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
new file mode 100644
index 000000000..6454c27a0
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
@@ -0,0 +1,55 @@
+import { BorderRadius, FlexView, Spacing, Text, useTheme } from '@reown/appkit-ui-react-native';
+import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
+
+export interface PreviewSendDetailsProps {
+ value?: string;
+ style?: StyleProp;
+}
+
+export function PreviewSendDetails({ value, style }: PreviewSendDetailsProps) {
+ const Theme = useTheme();
+
+ return (
+
+
+ Details
+
+
+
+ Network cost
+
+
+
+
+ Address
+
+
+
+
+ Network
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ justifyContent: 'center',
+ borderRadius: BorderRadius.xxs
+ },
+ title: {
+ marginBottom: Spacing.xs
+ },
+ item: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ padding: Spacing.s,
+ borderRadius: BorderRadius.xxs,
+ marginTop: Spacing['2xs']
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx
new file mode 100644
index 000000000..b3c477003
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx
@@ -0,0 +1,36 @@
+import { BorderRadius, FlexView, Text, useTheme } from '@reown/appkit-ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export interface PreviewSendPillProps {
+ text: string;
+ children: React.ReactNode;
+}
+
+export function PreviewSendPill({ text, children }: PreviewSendPillProps) {
+ const Theme = useTheme();
+
+ return (
+
+
+ {text}
+
+ {children}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ pill: {
+ borderRadius: BorderRadius.full,
+ borderWidth: 1
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
new file mode 100644
index 000000000..4d95b6113
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
@@ -0,0 +1,66 @@
+import { useSnapshot } from 'valtio';
+import { Avatar, FlexView, Icon, Image, Text, UiUtil } from '@reown/appkit-ui-react-native';
+import { NumberUtil } from '@reown/appkit-common-react-native';
+import { NetworkController, SendController } from '@reown/appkit-core-react-native';
+import { PreviewSendPill } from './components/preview-send-pill';
+import styles from './styles';
+import { PreviewSendDetails } from './components/preview-send-details';
+
+export function WalletSendPreviewView() {
+ const { caipNetwork } = useSnapshot(NetworkController.state);
+ const { token, receiverAddress, gasPriceInUSD } = useSnapshot(SendController.state);
+
+ const getSendValue = () => {
+ if (SendController.state.token && SendController.state.sendTokenAmount) {
+ const price = SendController.state.token.price;
+ const totalValue = price * SendController.state.sendTokenAmount;
+
+ return totalValue.toFixed(2);
+ }
+
+ return null;
+ };
+
+ const getTokenAmount = () => {
+ const value = SendController.state.sendTokenAmount
+ ? NumberUtil.roundNumber(SendController.state.sendTokenAmount, 6, 5)
+ : 'unknown';
+
+ return `${value} ${SendController.state.token?.symbol}`;
+ };
+
+ const formattedAddress = UiUtil.getTruncateString({
+ string: receiverAddress ? receiverAddress : '',
+ charsStart: 4,
+ charsEnd: 4,
+ truncate: 'middle'
+ });
+
+ return (
+
+
+
+
+ Send
+
+
+ ${getSendValue()}
+
+
+
+
+
+
+
+
+
+ To
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts
new file mode 100644
index 000000000..babe3e1f4
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts
@@ -0,0 +1,24 @@
+import { BorderRadius, Spacing } from '@reown/appkit-ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ container: {
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ tokenLogo: {
+ height: 32,
+ width: 32,
+ borderRadius: BorderRadius.full,
+ marginLeft: Spacing.xs
+ },
+ arrow: {
+ marginVertical: Spacing.xs
+ },
+ avatar: {
+ marginLeft: Spacing.xs
+ },
+ details: {
+ marginTop: Spacing['2xl']
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index 8f95d1997..ce74e5e8b 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -1,7 +1,12 @@
import { useCallback, useEffect } from 'react';
import { Platform, ScrollView } from 'react-native';
import { useSnapshot } from 'valtio';
-import { AccountController, SendController, SwapController } from '@reown/appkit-core-react-native';
+import {
+ AccountController,
+ RouterController,
+ SendController,
+ SwapController
+} from '@reown/appkit-core-react-native';
import {
Button,
FlexView,
@@ -40,6 +45,7 @@ export function WalletSendView() {
const onSendPress = () => {
if (SendController.state.loading) return;
+ RouterController.push('WalletSendPreview');
};
const getActionText = () => {
From 645aadcef5e48c10a730327cd403107028fa6af0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 20 Sep 2024 13:46:35 +0000
Subject: [PATCH 045/114] chore(deps): bump serve-static from 1.15.0 to 1.16.2
Bumps [serve-static](https://github.com/expressjs/serve-static) from 1.15.0 to 1.16.2.
- [Release notes](https://github.com/expressjs/serve-static/releases)
- [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md)
- [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2)
---
updated-dependencies:
- dependency-name: serve-static
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
yarn.lock | 30 +++++++++---------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index c88c9fc35..ea5f0c7fc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -21264,9 +21264,9 @@ __metadata:
languageName: node
linkType: hard
-"send@npm:0.18.0, send@npm:^0.18.0":
- version: 0.18.0
- resolution: "send@npm:0.18.0"
+"send@npm:0.19.0":
+ version: 0.19.0
+ resolution: "send@npm:0.19.0"
dependencies:
debug: "npm:2.6.9"
depd: "npm:2.0.0"
@@ -21281,13 +21281,13 @@ __metadata:
on-finished: "npm:2.4.1"
range-parser: "npm:~1.2.1"
statuses: "npm:2.0.1"
- checksum: 0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a
+ checksum: ea3f8a67a8f0be3d6bf9080f0baed6d2c51d11d4f7b4470de96a5029c598a7011c497511ccc28968b70ef05508675cebff27da9151dd2ceadd60be4e6cf845e3
languageName: node
linkType: hard
-"send@npm:0.19.0":
- version: 0.19.0
- resolution: "send@npm:0.19.0"
+"send@npm:^0.18.0":
+ version: 0.18.0
+ resolution: "send@npm:0.18.0"
dependencies:
debug: "npm:2.6.9"
depd: "npm:2.0.0"
@@ -21302,7 +21302,7 @@ __metadata:
on-finished: "npm:2.4.1"
range-parser: "npm:~1.2.1"
statuses: "npm:2.0.1"
- checksum: ea3f8a67a8f0be3d6bf9080f0baed6d2c51d11d4f7b4470de96a5029c598a7011c497511ccc28968b70ef05508675cebff27da9151dd2ceadd60be4e6cf845e3
+ checksum: 0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a
languageName: node
linkType: hard
@@ -21322,7 +21322,7 @@ __metadata:
languageName: node
linkType: hard
-"serve-static@npm:1.16.2":
+"serve-static@npm:1.16.2, serve-static@npm:^1.13.1":
version: 1.16.2
resolution: "serve-static@npm:1.16.2"
dependencies:
@@ -21334,18 +21334,6 @@ __metadata:
languageName: node
linkType: hard
-"serve-static@npm:^1.13.1":
- version: 1.15.0
- resolution: "serve-static@npm:1.15.0"
- dependencies:
- encodeurl: "npm:~1.0.2"
- escape-html: "npm:~1.0.3"
- parseurl: "npm:~1.3.3"
- send: "npm:0.18.0"
- checksum: fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba
- languageName: node
- linkType: hard
-
"set-blocking@npm:^2.0.0":
version: 2.0.0
resolution: "set-blocking@npm:2.0.0"
From d23f64a30881948d33197055e9dafbcd22a6e398 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 20 Sep 2024 13:46:37 +0000
Subject: [PATCH 046/114] chore(deps): bump fast-xml-parser from 4.2.7 to 4.5.0
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 4.2.7 to 4.5.0.
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v4.2.7...v4.5.0)
---
updated-dependencies:
- dependency-name: fast-xml-parser
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
yarn.lock | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index c88c9fc35..e9a78ef97 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14145,25 +14145,14 @@ __metadata:
languageName: node
linkType: hard
-"fast-xml-parser@npm:^4.0.12":
- version: 4.2.7
- resolution: "fast-xml-parser@npm:4.2.7"
- dependencies:
- strnum: "npm:^1.0.5"
- bin:
- fxparser: src/cli/cli.js
- checksum: 0681922d95713062ec6205fd41be503890c474a45831c39502e72fccf0b0bd88c49d2c2fa79c6d24d432573631d515967fd17938bcedf230cb134c291cbbbf5e
- languageName: node
- linkType: hard
-
-"fast-xml-parser@npm:^4.2.4":
- version: 4.3.2
- resolution: "fast-xml-parser@npm:4.3.2"
+"fast-xml-parser@npm:^4.0.12, fast-xml-parser@npm:^4.2.4":
+ version: 4.5.0
+ resolution: "fast-xml-parser@npm:4.5.0"
dependencies:
strnum: "npm:^1.0.5"
bin:
fxparser: src/cli/cli.js
- checksum: 7c1611349384656ec4faa9802fbc8cf8c01206a1b79193d5cd54586307801562509007f6cf16e5da7d43da4fa4639770f38959a285b9466aa98dab0a9b8ca171
+ checksum: 71d206c9e137f5c26af88d27dde0108068a5d074401901d643c500c36e95dfd828333a98bda020846c41f5b9b364e2b0e9be5b19b0bdcab5cf31559c07b80a95
languageName: node
linkType: hard
From 84fd082117d9527179a9d3b66aeb8c6068bf43d0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 20 Sep 2024 13:46:42 +0000
Subject: [PATCH 047/114] chore(deps): bump micromatch from 4.0.5 to 4.0.8
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8)
---
updated-dependencies:
- dependency-name: micromatch
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
yarn.lock | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index c88c9fc35..5163839d6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11025,7 +11025,16 @@ __metadata:
languageName: node
linkType: hard
-"braces@npm:^3.0.2, braces@npm:~3.0.2":
+"braces@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "braces@npm:3.0.3"
+ dependencies:
+ fill-range: "npm:^7.1.1"
+ checksum: 7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04
+ languageName: node
+ linkType: hard
+
+"braces@npm:~3.0.2":
version: 3.0.2
resolution: "braces@npm:3.0.2"
dependencies:
@@ -14248,6 +14257,15 @@ __metadata:
languageName: node
linkType: hard
+"fill-range@npm:^7.1.1":
+ version: 7.1.1
+ resolution: "fill-range@npm:7.1.1"
+ dependencies:
+ to-regex-range: "npm:^5.0.1"
+ checksum: b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018
+ languageName: node
+ linkType: hard
+
"filter-obj@npm:^1.1.0":
version: 1.1.0
resolution: "filter-obj@npm:1.1.0"
@@ -18134,12 +18152,12 @@ __metadata:
linkType: hard
"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5":
- version: 4.0.5
- resolution: "micromatch@npm:4.0.5"
+ version: 4.0.8
+ resolution: "micromatch@npm:4.0.8"
dependencies:
- braces: "npm:^3.0.2"
+ braces: "npm:^3.0.3"
picomatch: "npm:^2.3.1"
- checksum: 3d6505b20f9fa804af5d8c596cb1c5e475b9b0cd05f652c5b56141cf941bd72adaeb7a436fda344235cef93a7f29b7472efc779fcdb83b478eab0867b95cdeff
+ checksum: 166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8
languageName: node
linkType: hard
From 8cfe95d360fd1292ed111833fb689dae3d4bb071 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 20 Sep 2024 11:28:15 -0300
Subject: [PATCH 048/114] chore: preview send view
---
.../components/preview-send-details.tsx | 43 +++++++++++++++++--
.../w3m-wallet-send-preview-view/index.tsx | 43 ++++++++++++++++---
.../w3m-wallet-send-preview-view/styles.ts | 13 +++++-
.../src/views/w3m-wallet-send-view/index.tsx | 1 +
4 files changed, 91 insertions(+), 9 deletions(-)
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
index 6454c27a0..ceea64b03 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
@@ -1,14 +1,39 @@
-import { BorderRadius, FlexView, Spacing, Text, useTheme } from '@reown/appkit-ui-react-native';
+import { AssetUtil, type CaipNetwork } from '@reown/appkit-core-react-native';
+import {
+ BorderRadius,
+ FlexView,
+ NetworkImage,
+ Spacing,
+ Text,
+ UiUtil,
+ useTheme
+} from '@reown/appkit-ui-react-native';
import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
export interface PreviewSendDetailsProps {
- value?: string;
+ address?: string;
+ caipNetwork?: CaipNetwork;
+ networkFee?: number;
style?: StyleProp;
}
-export function PreviewSendDetails({ value, style }: PreviewSendDetailsProps) {
+export function PreviewSendDetails({
+ address,
+ caipNetwork,
+ networkFee,
+ style
+}: PreviewSendDetailsProps) {
const Theme = useTheme();
+ const formattedAddress = UiUtil.getTruncateString({
+ string: address ? address : '',
+ charsStart: 6,
+ charsEnd: 8,
+ truncate: 'middle'
+ });
+
+ const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+
return (
Network cost
+
+ ${UiUtil.formatNumberToLocalString(networkFee, 2)}
+
Address
+
+ {formattedAddress}
+
Network
+
);
@@ -51,5 +83,10 @@ const styles = StyleSheet.create({
padding: Spacing.s,
borderRadius: BorderRadius.xxs,
marginTop: Spacing['2xs']
+ },
+ networkImage: {
+ height: 24,
+ width: 24,
+ borderRadius: BorderRadius.full
}
});
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
index 4d95b6113..848935b4c 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
@@ -1,7 +1,11 @@
import { useSnapshot } from 'valtio';
-import { Avatar, FlexView, Icon, Image, Text, UiUtil } from '@reown/appkit-ui-react-native';
+import { Avatar, Button, FlexView, Icon, Image, Text, UiUtil } from '@reown/appkit-ui-react-native';
import { NumberUtil } from '@reown/appkit-common-react-native';
-import { NetworkController, SendController } from '@reown/appkit-core-react-native';
+import {
+ NetworkController,
+ RouterController,
+ SendController
+} from '@reown/appkit-core-react-native';
import { PreviewSendPill } from './components/preview-send-pill';
import styles from './styles';
import { PreviewSendDetails } from './components/preview-send-details';
@@ -37,7 +41,7 @@ export function WalletSendPreviewView() {
});
return (
-
+
@@ -48,7 +52,17 @@ export function WalletSendPreviewView() {
-
+ {token?.iconUrl ? (
+
+ ) : (
+
+ )}
@@ -60,7 +74,26 @@ export function WalletSendPreviewView() {
-
+
+
+
+
+ Review transaction carefully
+
+
+
+
+ Cancel
+
+
+ Send
+
+
);
}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts
index babe3e1f4..432a72c36 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/styles.ts
@@ -19,6 +19,17 @@ export default StyleSheet.create({
marginLeft: Spacing.xs
},
details: {
- marginTop: Spacing['2xl']
+ marginTop: Spacing['2xl'],
+ marginBottom: Spacing.s
+ },
+ reviewIcon: {
+ marginRight: Spacing['3xs']
+ },
+ cancelButton: {
+ flex: 1
+ },
+ sendButton: {
+ marginLeft: Spacing.s,
+ flex: 3
}
});
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index ce74e5e8b..1c308ed18 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -45,6 +45,7 @@ export function WalletSendView() {
const onSendPress = () => {
if (SendController.state.loading) return;
+ // TODO: add validations
RouterController.push('WalletSendPreview');
};
From e55ad32fd3e1630f3b28d3895f01a6c94bdeca25 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 20 Sep 2024 17:45:16 -0300
Subject: [PATCH 049/114] chore: working on send flow
---
.../core/src/controllers/RouterController.ts | 37 ++++++++++++++++++-
.../core/src/controllers/SendController.ts | 19 +++++-----
.../scaffold/src/modal/w3m-modal/index.tsx | 6 ++-
.../w3m-wallet-send-preview-view/index.tsx | 6 ++-
packages/wallet/src/AppKitAuthWebview.tsx | 19 +++++++---
packages/wallet/src/AppKitFrameConstants.ts | 12 +++++-
6 files changed, 78 insertions(+), 21 deletions(-)
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index d579dd33d..6d29bf004 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -2,6 +2,15 @@ import { proxy } from 'valtio';
import type { WcWallet, CaipNetwork, Connector } from '../utils/TypeUtil';
// -- Types --------------------------------------------- //
+type TransactionAction = {
+ goBack: boolean;
+ view: RouterControllerState['view'] | null;
+ close?: boolean;
+ replace?: boolean;
+ onSuccess?: () => void;
+ onCancel?: () => void;
+};
+
export interface RouterControllerState {
view:
| 'Account'
@@ -36,12 +45,14 @@ export interface RouterControllerState {
email?: string;
newEmail?: string;
};
+ transactionStack: TransactionAction[];
}
// -- State --------------------------------------------- //
const state = proxy({
view: 'Connect',
- history: ['Connect']
+ history: ['Connect'],
+ transactionStack: []
});
// -- Controller ---------------------------------------- //
@@ -56,6 +67,30 @@ export const RouterController = {
}
},
+ pushTransactionStack(action: TransactionAction) {
+ state.transactionStack.push(action);
+ },
+
+ popTransactionStack(cancel?: boolean) {
+ const action = state.transactionStack.pop();
+
+ if (!action) {
+ return;
+ }
+
+ if (cancel) {
+ this.goBack();
+ action?.onCancel?.();
+ } else {
+ if (action.goBack) {
+ this.goBack();
+ } else if (action.view) {
+ this.reset(action.view);
+ }
+ action?.onSuccess?.();
+ }
+ },
+
reset(view: RouterControllerState['view']) {
state.view = view;
state.history = [view];
diff --git a/packages/core/src/controllers/SendController.ts b/packages/core/src/controllers/SendController.ts
index 8e369052e..9766386ee 100644
--- a/packages/core/src/controllers/SendController.ts
+++ b/packages/core/src/controllers/SendController.ts
@@ -2,16 +2,15 @@ import { subscribeKey as subKey } from 'valtio/vanilla/utils';
import { proxy, ref, subscribe as sub } from 'valtio/vanilla';
import { type Balance } from '@reown/appkit-common-react-native';
import { erc20ABI } from '@reown/appkit-common-react-native';
-// import { RouterController } from './RouterController';
import { AccountController } from './AccountController';
import { ConnectionController } from './ConnectionController';
import { SnackController } from './SnackController';
import { CoreHelperUtil } from '../utils/CoreHelperUtil';
import { EventsController } from './EventsController';
import { NetworkController } from './NetworkController';
+import { RouterController } from './RouterController';
// -- Types --------------------------------------------- //
-
export interface TxParams {
receiverAddress: string;
sendTokenAmount: number;
@@ -136,10 +135,10 @@ export const SendController = {
},
async sendNativeToken(params: TxParams) {
- // RouterController.pushTransactionStack({
- // view: 'Account',
- // goBack: false
- // });
+ RouterController.pushTransactionStack({
+ view: 'Account',
+ goBack: false
+ });
const to = params.receiverAddress as `0x${string}`;
const address = AccountController.state.address as `0x${string}`;
@@ -185,10 +184,10 @@ export const SendController = {
},
async sendERC20Token(params: ContractWriteParams) {
- // RouterController.pushTransactionStack({
- // view: 'Account',
- // goBack: false
- // });
+ RouterController.pushTransactionStack({
+ view: 'Account',
+ goBack: false
+ });
const amount = ConnectionController.parseUnits(
params.sendTokenAmount.toString(),
diff --git a/packages/scaffold/src/modal/w3m-modal/index.tsx b/packages/scaffold/src/modal/w3m-modal/index.tsx
index eb377731d..c793a71e2 100644
--- a/packages/scaffold/src/modal/w3m-modal/index.tsx
+++ b/packages/scaffold/src/modal/w3m-modal/index.tsx
@@ -24,6 +24,8 @@ import { Snackbar } from '../../partials/w3m-snackbar';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
+const viewsAboveModal = ['ConnectingSiwe', 'WalletSendPreview'];
+
export function AppKit() {
const { open, loading } = useSnapshot(ModalController.state);
const { view: activeView } = useSnapshot(RouterController.state);
@@ -35,7 +37,7 @@ export function AppKit() {
const portraitHeight = height - 120;
const landScapeHeight = height * 0.95 - (StatusBar.currentHeight ?? 0);
const authProvider = connectors.find(c => c.type === 'AUTH')?.provider as AppKitFrameProvider;
- const modalCoverScreen = activeView !== 'ConnectingSiwe';
+ const enableCoverScreen = !viewsAboveModal.includes(activeView);
const AuthView = authProvider?.AuthView;
const onBackButtonPress = () => {
@@ -119,7 +121,7 @@ export function AppKit() {
<>
{
+ SendController.sendToken();
+ };
+
return (
@@ -90,7 +94,7 @@ export function WalletSendPreviewView() {
Cancel
-
+
Send
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index 72e18ba2e..0f3ef1e62 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -8,11 +8,13 @@ import {
OptionsController,
ModalController,
type OptionsControllerState,
- StorageUtil
+ StorageUtil,
+ RouterController
} from '@reown/appkit-core-react-native';
import { useTheme, BorderRadius } from '@reown/appkit-ui-react-native';
import type { AppKitFrameProvider } from './AppKitFrameProvider';
-import { AppKitFrameConstants, AppKitFrameRpcConstants } from './AppKitFrameConstants';
+import { AppKitFrameConstants } from './AppKitFrameConstants';
+import { AppKitFrameHelpers } from './AppKitFrameHelpers';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
@@ -50,13 +52,20 @@ export function AuthWebview() {
provider.onMessage(event);
provider.onRpcRequest(event, () => {
- if (!AppKitFrameRpcConstants.SAFE_RPC_METHODS.includes(event.payload.method)) {
- setIsVisible(true);
+ if (AppKitFrameHelpers.checkIfRequestExists(event)) {
+ if (!AppKitFrameHelpers.checkIfRequestIsAllowed(event)) {
+ setIsVisible(true);
+ }
}
});
provider.onRpcResponse(event, () => {
- setIsVisible(false);
+ if (RouterController.state.transactionStack.length === 0) {
+ setIsVisible(false);
+ } else {
+ // TODO: send boolean in false in case of error
+ RouterController?.popTransactionStack();
+ }
});
provider.onIsConnected(event, () => {
diff --git a/packages/wallet/src/AppKitFrameConstants.ts b/packages/wallet/src/AppKitFrameConstants.ts
index 5ddd69ffe..a0a13d0f3 100644
--- a/packages/wallet/src/AppKitFrameConstants.ts
+++ b/packages/wallet/src/AppKitFrameConstants.ts
@@ -105,9 +105,17 @@ export const AppKitFrameRpcConstants = {
'eth_newPendingTransactionFilter',
'eth_sendRawTransaction',
'eth_syncing',
- 'eth_uninstallFilter'
+ 'eth_uninstallFilter',
+ 'wallet_getCapabilities',
+ 'wallet_getCallsStatus'
+ ],
+ NOT_SAFE_RPC_METHODS: [
+ 'personal_sign',
+ 'eth_signTypedData_v4',
+ 'eth_sendTransaction',
+ 'wallet_sendCalls',
+ 'wallet_grantPermissions'
],
- NOT_SAFE_RPC_METHODS: ['personal_sign', 'eth_signTypedData_v4', 'eth_sendTransaction'],
GET_CHAIN_ID: 'eth_chainId',
RPC_METHOD_NOT_ALLOWED_MESSAGE: 'Requested RPC call is not allowed',
RPC_METHOD_NOT_ALLOWED_UI_MESSAGE: 'Action not allowed'
From 4c84e830c0a0c45c49b9c3ec6f07e4d084a209a7 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 23 Sep 2024 14:57:01 -0300
Subject: [PATCH 050/114] chore: auth provider refactor
---
.../core/src/controllers/SendController.ts | 4 +
.../w3m-wallet-send-preview-view/index.tsx | 4 +-
packages/wallet/src/AppKitAuthWebview.tsx | 45 +-
packages/wallet/src/AppKitFrameHelpers.ts | 18 +-
packages/wallet/src/AppKitFrameProvider.ts | 598 +++++++-----------
packages/wallet/src/AppKitFrameSchema.ts | 179 ++++--
packages/wallet/src/AppKitFrameTypes.ts | 27 +-
packages/wallet/src/index.ts | 2 +-
8 files changed, 414 insertions(+), 463 deletions(-)
diff --git a/packages/core/src/controllers/SendController.ts b/packages/core/src/controllers/SendController.ts
index 9766386ee..5153f4cd8 100644
--- a/packages/core/src/controllers/SendController.ts
+++ b/packages/core/src/controllers/SendController.ts
@@ -93,6 +93,7 @@ export const SendController = {
sendToken() {
if (this.state.token?.address && this.state.sendTokenAmount && this.state.receiverAddress) {
+ state.loading = true;
EventsController.sendEvent({
type: 'track',
event: 'SEND_INITIATED',
@@ -115,6 +116,7 @@ export const SendController = {
this.state.gasPrice &&
this.state.token?.quantity.decimals
) {
+ state.loading = true;
EventsController.sendEvent({
type: 'track',
event: 'SEND_INITIATED',
@@ -169,6 +171,7 @@ export const SendController = {
});
this.resetSend();
} catch (error) {
+ state.loading = false;
EventsController.sendEvent({
type: 'track',
event: 'SEND_ERROR',
@@ -215,6 +218,7 @@ export const SendController = {
this.resetSend();
}
} catch (error) {
+ state.loading = false;
SnackController.showError('Something went wrong');
}
},
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
index 353f7e17c..5e2661ae1 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
@@ -12,7 +12,7 @@ import { PreviewSendDetails } from './components/preview-send-details';
export function WalletSendPreviewView() {
const { caipNetwork } = useSnapshot(NetworkController.state);
- const { token, receiverAddress, gasPriceInUSD } = useSnapshot(SendController.state);
+ const { token, receiverAddress, gasPriceInUSD, loading } = useSnapshot(SendController.state);
const getSendValue = () => {
if (SendController.state.token && SendController.state.sendTokenAmount) {
@@ -94,7 +94,7 @@ export function WalletSendPreviewView() {
Cancel
-
+
Send
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index 0f3ef1e62..438e511dc 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -15,6 +15,7 @@ import { useTheme, BorderRadius } from '@reown/appkit-ui-react-native';
import type { AppKitFrameProvider } from './AppKitFrameProvider';
import { AppKitFrameConstants } from './AppKitFrameConstants';
import { AppKitFrameHelpers } from './AppKitFrameHelpers';
+import type { AppKitFrameTypes } from './AppKitFrameTypes';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
@@ -23,7 +24,7 @@ export function AuthWebview() {
const Theme = useTheme();
const { connectors } = useSnapshot(ConnectorController.state);
const { projectId, sdkVersion } = useSnapshot(OptionsController.state) as OptionsControllerState;
- const [isVisible, setIsVisible] = useState(false);
+ const [isWebviewVisibile, setIsWebviewOpen] = useState(false);
const [isBackdropVisible, setIsBackdropVisible] = useState(false);
const animatedHeight = useRef(new Animated.Value(0));
const backdropOpacity = useRef(new Animated.Value(0));
@@ -51,21 +52,37 @@ export function AuthWebview() {
provider.onMessage(event);
- provider.onRpcRequest(event, () => {
- if (AppKitFrameHelpers.checkIfRequestExists(event)) {
- if (!AppKitFrameHelpers.checkIfRequestIsAllowed(event)) {
- setIsVisible(true);
+ provider.onRpcRequest((request: AppKitFrameTypes.RPCRequest) => {
+ if (AppKitFrameHelpers.checkIfRequestExists(request)) {
+ if (!AppKitFrameHelpers.checkIfRequestIsAllowed(request)) {
+ setIsWebviewOpen(true);
}
}
});
- provider.onRpcResponse(event, () => {
+ provider.onRpcSuccess((_, request) => {
+ const isSafeRequest = AppKitFrameHelpers.checkIfRequestIsSafe(request);
+ if (isSafeRequest) {
+ return;
+ }
+
if (RouterController.state.transactionStack.length === 0) {
- setIsVisible(false);
+ ModalController.close();
} else {
- // TODO: send boolean in false in case of error
RouterController?.popTransactionStack();
}
+ setIsWebviewOpen(false);
+ });
+
+ provider.onRpcError(() => {
+ if (isWebviewVisibile) {
+ if (RouterController.state.transactionStack.length === 0) {
+ ModalController.close();
+ } else {
+ RouterController?.popTransactionStack(true);
+ }
+ }
+ setIsWebviewOpen(false);
});
provider.onIsConnected(event, () => {
@@ -87,27 +104,27 @@ export function AuthWebview() {
useEffect(() => {
Animated.timing(animatedHeight.current, {
- toValue: isVisible ? 1 : 0,
+ toValue: isWebviewVisibile ? 1 : 0,
duration: 200,
useNativeDriver: false
}).start();
Animated.timing(webviewOpacity.current, {
- toValue: isVisible ? 1 : 0,
+ toValue: isWebviewVisibile ? 1 : 0,
duration: 300,
useNativeDriver: false
}).start();
- if (isVisible) {
+ if (isWebviewVisibile) {
setIsBackdropVisible(true);
}
Animated.timing(backdropOpacity.current, {
- toValue: isVisible ? 0.7 : 0,
+ toValue: isWebviewVisibile ? 0.7 : 0,
duration: 300,
useNativeDriver: false
- }).start(() => setIsBackdropVisible(isVisible));
- }, [animatedHeight, backdropOpacity, isVisible, setIsBackdropVisible]);
+ }).start(() => setIsBackdropVisible(isWebviewVisibile));
+ }, [animatedHeight, backdropOpacity, isWebviewVisibile, setIsBackdropVisible]);
useEffect(() => {
provider?.setWebviewRef(webviewRef);
diff --git a/packages/wallet/src/AppKitFrameHelpers.ts b/packages/wallet/src/AppKitFrameHelpers.ts
index 297a5052d..212fd6219 100644
--- a/packages/wallet/src/AppKitFrameHelpers.ts
+++ b/packages/wallet/src/AppKitFrameHelpers.ts
@@ -23,22 +23,18 @@ export const AppKitFrameHelpers = {
}
},
- checkIfRequestExists(request: unknown) {
- const method = this.getRequestMethod(request);
-
+ checkIfRequestExists(request: AppKitFrameTypes.RPCRequest) {
return (
- AppKitFrameRpcConstants.NOT_SAFE_RPC_METHODS.includes(method) ||
- AppKitFrameRpcConstants.SAFE_RPC_METHODS.includes(method)
+ AppKitFrameRpcConstants.NOT_SAFE_RPC_METHODS.includes(request.method) ||
+ AppKitFrameRpcConstants.SAFE_RPC_METHODS.includes(request.method)
);
},
- getRequestMethod(request: unknown) {
- return (request as { payload: AppKitFrameTypes.RPCRequest })?.payload?.method;
+ checkIfRequestIsAllowed(request: AppKitFrameTypes.RPCRequest) {
+ return AppKitFrameRpcConstants.SAFE_RPC_METHODS.includes(request.method);
},
- checkIfRequestIsAllowed(request: unknown) {
- const method = this.getRequestMethod(request);
-
- return AppKitFrameRpcConstants.SAFE_RPC_METHODS.includes(method);
+ checkIfRequestIsSafe(request: AppKitFrameTypes.RPCRequest) {
+ return AppKitFrameRpcConstants.SAFE_RPC_METHODS.includes(request.method);
}
};
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index 05d6a60fa..d09b08655 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -1,3 +1,4 @@
+import { EventEmitter } from 'events';
import type { RefObject } from 'react';
import type WebView from 'react-native-webview';
import { CoreHelperUtil } from '@reown/appkit-core-react-native';
@@ -8,25 +9,6 @@ import { AppKitFrameHelpers } from './AppKitFrameHelpers';
import { AppKitFrameSchema } from './AppKitFrameSchema';
import { AuthWebview } from './AppKitAuthWebview';
-// -- Types -----------------------------------------------------------
-type Resolver = { resolve: (value: T) => void; reject: (reason?: unknown) => void } | undefined;
-type ConnectEmailResolver = Resolver;
-type ConnectDeviceResolver = Resolver;
-type ConnectOtpResolver = Resolver;
-type ConnectResolver = Resolver;
-type DisconnectResolver = Resolver;
-type IsConnectedResolver = Resolver;
-type GetChainIdResolver = Resolver;
-type SwitchChainResolver = Resolver;
-type RpcRequestResolver = Resolver;
-type UpdateEmailResolver = Resolver;
-type UpdateEmailPrimaryOtpResolver = Resolver;
-type UpdateEmailSecondaryOtpResolver = Resolver<
- AppKitFrameTypes.Responses['FrameUpdateEmailSecondaryOtpResolver']
->;
-type SyncThemeResolver = Resolver;
-type SyncDappDataResolver = Resolver;
-
// -- Provider --------------------------------------------------------
export class AppKitFrameProvider {
private webviewRef: RefObject | undefined;
@@ -37,6 +19,13 @@ export class AppKitFrameProvider {
private email: string | undefined;
+ private rpcRequestHandler?: (request: AppKitFrameTypes.RPCRequest) => void;
+ private rpcSuccessHandler?: (
+ response: AppKitFrameTypes.RPCResponse,
+ request: AppKitFrameTypes.RPCRequest
+ ) => void;
+ private rpcErrorHandler?: (error: Error, request: AppKitFrameTypes.RPCRequest) => void;
+
public webviewLoadPromise: Promise;
public webviewLoadPromiseResolver:
@@ -48,33 +37,11 @@ export class AppKitFrameProvider {
public AuthView = AuthWebview;
- private connectEmailResolver: ConnectEmailResolver = undefined;
-
- private connectDeviceResolver: ConnectDeviceResolver = undefined;
-
- private connectOtpResolver: ConnectOtpResolver | undefined = undefined;
-
- private connectResolver: ConnectResolver = undefined;
-
- private disconnectResolver: DisconnectResolver = undefined;
-
- private isConnectedResolver: IsConnectedResolver = undefined;
-
- private getChainIdResolver: GetChainIdResolver = undefined;
-
- private switchChainResolver: SwitchChainResolver = undefined;
-
- private rpcRequestResolver: RpcRequestResolver = undefined;
-
- private updateEmailResolver: UpdateEmailResolver = undefined;
-
- private updateEmailPrimaryOtpResolver: UpdateEmailPrimaryOtpResolver = undefined;
+ private openRpcRequests: Array<
+ AppKitFrameTypes.RPCRequest & { abortController: AbortController }
+ > = [];
- private updateEmailSecondaryOtpResolver: UpdateEmailSecondaryOtpResolver = undefined;
-
- private syncThemeResolver: SyncThemeResolver = undefined;
-
- private syncDappDataResolver: SyncDappDataResolver = undefined;
+ public events: EventEmitter = new EventEmitter();
public constructor(projectId: string, metadata: AppKitFrameTypes.Metadata) {
this.webviewLoadPromise = new Promise((resolve, reject) => {
@@ -92,72 +59,9 @@ export class AppKitFrameProvider {
this.webviewRef = webviewRef;
}
- public onMessage(e: AppKitFrameTypes.FrameEvent) {
- this.onFrameEvent(e, event => {
- // console.log('💻 received', e); // eslint-disable-line no-console
- switch (event.type) {
- case AppKitFrameConstants.FRAME_CONNECT_EMAIL_SUCCESS:
- return this.onConnectEmailSuccess(event);
- case AppKitFrameConstants.FRAME_CONNECT_EMAIL_ERROR:
- return this.onConnectEmailError(event);
- case AppKitFrameConstants.FRAME_CONNECT_DEVICE_SUCCESS:
- return this.onConnectDeviceSuccess();
- case AppKitFrameConstants.FRAME_CONNECT_DEVICE_ERROR:
- return this.onConnectDeviceError(event);
- case AppKitFrameConstants.FRAME_CONNECT_OTP_SUCCESS:
- return this.onConnectOtpSuccess();
- case AppKitFrameConstants.FRAME_CONNECT_OTP_ERROR:
- return this.onConnectOtpError(event);
- case AppKitFrameConstants.FRAME_GET_USER_SUCCESS:
- return this.onConnectSuccess(event);
- case AppKitFrameConstants.FRAME_GET_USER_ERROR:
- return this.onConnectError(event);
- case AppKitFrameConstants.FRAME_IS_CONNECTED_SUCCESS:
- return this.onIsConnectedSuccess(event);
- case AppKitFrameConstants.FRAME_IS_CONNECTED_ERROR:
- return this.onIsConnectedError(event);
- case AppKitFrameConstants.FRAME_GET_CHAIN_ID_SUCCESS:
- return this.onGetChainIdSuccess(event);
- case AppKitFrameConstants.FRAME_GET_CHAIN_ID_ERROR:
- return this.onGetChainIdError(event);
- case AppKitFrameConstants.FRAME_SIGN_OUT_SUCCESS:
- return this.onSignOutSuccess();
- case AppKitFrameConstants.FRAME_SIGN_OUT_ERROR:
- return this.onSignOutError(event);
- case AppKitFrameConstants.FRAME_SWITCH_NETWORK_SUCCESS:
- return this.onSwitchChainSuccess(event);
- case AppKitFrameConstants.FRAME_SWITCH_NETWORK_ERROR:
- return this.onSwitchChainError(event);
- case AppKitFrameConstants.FRAME_RPC_REQUEST_SUCCESS:
- return this.onRpcRequestSuccess(event);
- case AppKitFrameConstants.FRAME_RPC_REQUEST_ERROR:
- return this.onRpcRequestError(event);
- case AppKitFrameConstants.FRAME_SESSION_UPDATE:
- return this.onSessionUpdate(event);
- case AppKitFrameConstants.FRAME_UPDATE_EMAIL_SUCCESS:
- return this.onUpdateEmailSuccess(event);
- case AppKitFrameConstants.FRAME_UPDATE_EMAIL_ERROR:
- return this.onUpdateEmailError(event);
- case AppKitFrameConstants.FRAME_UPDATE_EMAIL_PRIMARY_OTP_SUCCESS:
- return this.onUpdateEmailPrimaryOtpSuccess();
- case AppKitFrameConstants.FRAME_UPDATE_EMAIL_PRIMARY_OTP_ERROR:
- return this.onUpdateEmailPrimaryOtpError(event);
- case AppKitFrameConstants.FRAME_UPDATE_EMAIL_SECONDARY_OTP_SUCCESS:
- return this.onUpdateEmailSecondaryOtpSuccess(event);
- case AppKitFrameConstants.FRAME_UPDATE_EMAIL_SECONDARY_OTP_ERROR:
- return this.onUpdateEmailSecondaryOtpError(event);
- case AppKitFrameConstants.FRAME_SYNC_THEME_SUCCESS:
- return this.onSyncThemeSuccess();
- case AppKitFrameConstants.FRAME_SYNC_THEME_ERROR:
- return this.onSyncThemeError(event);
- case AppKitFrameConstants.FRAME_SYNC_DAPP_DATA_SUCCESS:
- return this.onSyncDappDataSuccess();
- case AppKitFrameConstants.FRAME_SYNC_DAPP_DATA_ERROR:
- return this.onSyncDappDataError(event);
- default:
- return null;
- }
- });
+ public onMessage(event: AppKitFrameTypes.FrameEvent) {
+ // console.log('💻 received', e); // eslint-disable-line no-console
+ this.events.emit('message', event);
}
public onWebviewLoaded() {
@@ -196,124 +100,141 @@ export class AppKitFrameProvider {
}
public rejectRpcRequest() {
- this.rpcRequestResolver?.reject();
+ try {
+ this.openRpcRequests.forEach(({ abortController, method }) => {
+ if (!AppKitFrameRpcConstants.SAFE_RPC_METHODS.includes(method)) {
+ abortController.abort();
+ }
+ });
+ this.openRpcRequests = [];
+ } catch (e) {}
}
public async connectEmail(payload: AppKitFrameTypes.Requests['AppConnectEmailRequest']) {
await this.webviewLoadPromise;
await AppKitFrameHelpers.checkIfAllowedToTriggerEmail();
- this.postAppEvent({ type: AppKitFrameConstants.APP_CONNECT_EMAIL, payload });
- return new Promise(
- (resolve, reject) => {
- this.connectEmailResolver = { resolve, reject };
- }
- );
+ const response = await this.appEvent<'ConnectEmail'>({
+ type: AppKitFrameConstants.APP_CONNECT_EMAIL,
+ payload
+ } as AppKitFrameTypes.AppEvent);
+
+ this.setNewLastEmailLoginTime();
+
+ return response;
}
public async connectDevice() {
await this.webviewLoadPromise;
- this.postAppEvent({ type: AppKitFrameConstants.APP_CONNECT_DEVICE });
- return new Promise((resolve, reject) => {
- this.connectDeviceResolver = { resolve, reject };
- });
+ const response = await this.appEvent<'ConnectDevice'>({
+ type: AppKitFrameConstants.APP_CONNECT_DEVICE
+ } as AppKitFrameTypes.AppEvent);
+
+ return response;
}
public async connectOtp(payload: AppKitFrameTypes.Requests['AppConnectOtpRequest']) {
await this.webviewLoadPromise;
- this.postAppEvent({ type: AppKitFrameConstants.APP_CONNECT_OTP, payload });
- return new Promise((resolve, reject) => {
- this.connectOtpResolver = { resolve, reject };
- });
+ const response = await this.appEvent<'ConnectOtp'>({
+ type: AppKitFrameConstants.APP_CONNECT_OTP,
+ payload
+ } as AppKitFrameTypes.AppEvent);
+
+ return response;
}
public async isConnected() {
await this.webviewLoadPromise;
- this.postAppEvent({
+
+ const response = await this.appEvent<'IsConnected'>({
type: AppKitFrameConstants.APP_IS_CONNECTED,
payload: undefined
- });
+ } as AppKitFrameTypes.AppEvent);
- return new Promise(
- (resolve, reject) => {
- this.isConnectedResolver = { resolve, reject };
- }
- );
+ if (!response.isConnected) {
+ this.deleteEmailLoginCache();
+ }
+
+ return response;
}
public async getChainId() {
await this.webviewLoadPromise;
- this.postAppEvent({ type: AppKitFrameConstants.APP_GET_CHAIN_ID });
- return new Promise((resolve, reject) => {
- this.getChainIdResolver = { resolve, reject };
- });
+ const response = await this.appEvent<'GetChainId'>({
+ type: AppKitFrameConstants.APP_GET_CHAIN_ID
+ } as AppKitFrameTypes.AppEvent);
+
+ this.setLastUsedChainId(response.chainId);
+
+ return response;
}
public async updateEmail(payload: AppKitFrameTypes.Requests['AppUpdateEmailRequest']) {
await this.webviewLoadPromise;
await AppKitFrameHelpers.checkIfAllowedToTriggerEmail();
- this.postAppEvent({ type: AppKitFrameConstants.APP_UPDATE_EMAIL, payload });
- return new Promise(
- (resolve, reject) => {
- this.updateEmailResolver = { resolve, reject };
- }
- );
+ const response = await this.appEvent<'UpdateEmail'>({
+ type: AppKitFrameConstants.APP_UPDATE_EMAIL,
+ payload
+ } as AppKitFrameTypes.AppEvent);
+
+ this.setNewLastEmailLoginTime();
+
+ return response;
}
public async updateEmailPrimaryOtp(
payload: AppKitFrameTypes.Requests['AppUpdateEmailPrimaryOtpRequest']
) {
await this.webviewLoadPromise;
- this.postAppEvent({
+
+ const response = await this.appEvent<'UpdateEmailPrimaryOtp'>({
type: AppKitFrameConstants.APP_UPDATE_EMAIL_PRIMARY_OTP,
payload
- });
+ } as AppKitFrameTypes.AppEvent);
- return new Promise((resolve, reject) => {
- this.updateEmailPrimaryOtpResolver = { resolve, reject };
- });
+ return response;
}
public async updateEmailSecondaryOtp(
payload: AppKitFrameTypes.Requests['AppUpdateEmailSecondaryOtpRequest']
) {
await this.webviewLoadPromise;
- this.postAppEvent({
+
+ const response = await this.appEvent<'UpdateEmailSecondaryOtp'>({
type: AppKitFrameConstants.APP_UPDATE_EMAIL_SECONDARY_OTP,
payload
- });
+ } as AppKitFrameTypes.AppEvent);
- return new Promise(
- (resolve, reject) => {
- this.updateEmailSecondaryOtpResolver = { resolve, reject };
- }
- );
+ this.setEmailLoginSuccess(response.newEmail);
+
+ return response;
}
public async syncTheme(payload: AppKitFrameTypes.Requests['AppSyncThemeRequest']) {
await this.webviewLoadPromise;
- this.postAppEvent({ type: AppKitFrameConstants.APP_SYNC_THEME, payload });
- return new Promise((resolve, reject) => {
- this.syncThemeResolver = { resolve, reject };
- });
+ const response = await this.appEvent<'SyncTheme'>({
+ type: AppKitFrameConstants.APP_SYNC_THEME,
+ payload
+ } as AppKitFrameTypes.AppEvent);
+
+ return response;
}
public async syncDappData(payload: AppKitFrameTypes.Requests['AppSyncDappDataRequest']) {
await this.webviewLoadPromise;
const metadata = payload.metadata ?? this.metadata;
- this.postAppEvent({
+
+ const response = await this.appEvent<'SyncDappData'>({
type: AppKitFrameConstants.APP_SYNC_DAPP_DATA,
payload: { ...payload, metadata }
- });
+ } as AppKitFrameTypes.AppEvent);
- return new Promise((resolve, reject) => {
- this.syncDappDataResolver = { resolve, reject };
- });
+ return response;
}
// -- Provider Methods ------------------------------------------------
@@ -322,60 +243,74 @@ export class AppKitFrameProvider {
const chainId = payload?.chainId ?? lastUsedChain ?? 1;
await this.webviewLoadPromise;
- this.postAppEvent({
+ const response = await this.appEvent<'GetUser'>({
type: AppKitFrameConstants.APP_GET_USER,
- payload: { chainId }
- });
+ payload: { ...payload, chainId }
+ } as AppKitFrameTypes.AppEvent);
- return new Promise((resolve, reject) => {
- this.connectResolver = { resolve, reject };
- });
+ this.setEmailLoginSuccess(response.email);
+ this.setLastUsedChainId(response.chainId);
+
+ return response;
}
public async switchNetwork(chainId: number) {
await this.webviewLoadPromise;
- this.postAppEvent({
+
+ const response = await this.appEvent<'SwitchNetwork'>({
type: AppKitFrameConstants.APP_SWITCH_NETWORK,
payload: { chainId }
- });
+ } as AppKitFrameTypes.AppEvent);
- return new Promise(
- (resolve, reject) => {
- this.switchChainResolver = { resolve, reject };
- }
- );
+ this.setLastUsedChainId(response.chainId);
+
+ return response;
}
public async disconnect() {
await this.webviewLoadPromise;
- this.postAppEvent({ type: AppKitFrameConstants.APP_SIGN_OUT });
- return new Promise((resolve, reject) => {
- this.disconnectResolver = { resolve, reject };
+ const response = await this.appEvent<'SignOut'>({
+ type: AppKitFrameConstants.APP_SIGN_OUT
});
+
+ this.deleteEmailLoginCache();
+
+ return response;
}
- public async request(req: AppKitFrameTypes.RPCRequest) {
- if (AppKitFrameRpcConstants.GET_CHAIN_ID === req.method) {
- return await this.getLastUsedChainId();
+ public async request(req: AppKitFrameTypes.RPCRequest): Promise {
+ try {
+ if (AppKitFrameRpcConstants.GET_CHAIN_ID === req.method) {
+ return this.getLastUsedChainId();
+ }
+
+ this.rpcRequestHandler?.(req);
+ const response = await this.appEvent<'Rpc'>({
+ type: AppKitFrameConstants.APP_RPC_REQUEST,
+ payload: req
+ } as AppKitFrameTypes.AppEvent);
+ this.rpcSuccessHandler?.(response, req);
+
+ return response;
+ } catch (error) {
+ this.rpcErrorHandler?.(error as Error, req);
+ throw error;
}
- await this.webviewLoadPromise;
- this.postAppEvent({
- type: AppKitFrameConstants.APP_RPC_REQUEST,
- payload: req
- });
+ }
- return new Promise((resolve, reject) => {
- this.rpcRequestResolver = { resolve, reject };
- });
+ public onRpcRequest(callback: (request: AppKitFrameTypes.RPCRequest) => void) {
+ this.rpcRequestHandler = callback;
}
- public onRpcRequest(event: AppKitFrameTypes.AppEvent, callback: (request: unknown) => void) {
- this.onAppEvent(event, appEvent => {
- if (appEvent.type.includes(AppKitFrameConstants.RPC_METHOD_KEY)) {
- callback(appEvent);
- }
- });
+ public onRpcSuccess(
+ callback: (response: AppKitFrameTypes.FrameEvent, request: AppKitFrameTypes.RPCRequest) => void
+ ) {
+ this.rpcSuccessHandler = callback;
+ }
+
+ public onRpcError(callback: (error: Error) => void) {
+ this.rpcErrorHandler = callback;
}
public onRpcResponse(event: AppKitFrameTypes.FrameEvent, callback: (request: unknown) => void) {
@@ -408,193 +343,6 @@ export class AppKitFrameProvider {
});
}
- // -- Promise Handlers ------------------------------------------------
- private onConnectEmailSuccess(
- event: Extract
- ) {
- this.connectEmailResolver?.resolve(event.payload);
- this.setNewLastEmailLoginTime();
- }
-
- private onConnectEmailError(
- event: Extract
- ) {
- this.connectEmailResolver?.reject(event.payload.message);
- }
-
- private onConnectDeviceSuccess() {
- this.connectDeviceResolver?.resolve(undefined);
- }
-
- private onConnectDeviceError(
- event: Extract
- ) {
- this.connectDeviceResolver?.reject(event.payload.message);
- }
-
- private onConnectOtpSuccess() {
- this.connectOtpResolver?.resolve(undefined);
- }
-
- private onConnectOtpError(
- event: Extract
- ) {
- this.connectOtpResolver?.reject(event.payload.message);
- }
-
- private onConnectSuccess(
- event: Extract
- ) {
- this.setEmailLoginSuccess(event.payload.email);
- this.setLastUsedChainId(event.payload.chainId);
- this.connectResolver?.resolve(event.payload);
- }
-
- private onConnectError(
- event: Extract
- ) {
- this.connectResolver?.reject(event.payload.message);
- }
-
- private onIsConnectedSuccess(
- event: Extract
- ) {
- if (!event.payload.isConnected) {
- this.deleteEmailLoginCache();
- }
- this.isConnectedResolver?.resolve(event.payload);
- }
-
- private onIsConnectedError(
- event: Extract
- ) {
- this.isConnectedResolver?.reject(event.payload.message);
- }
-
- private onGetChainIdSuccess(
- event: Extract
- ) {
- this.setLastUsedChainId(event.payload.chainId);
- this.getChainIdResolver?.resolve(event.payload);
- }
-
- private onGetChainIdError(
- event: Extract
- ) {
- this.getChainIdResolver?.reject(event.payload.message);
- }
-
- private onSignOutSuccess() {
- this.disconnectResolver?.resolve(undefined);
- this.deleteEmailLoginCache();
- }
-
- private onSignOutError(
- event: Extract
- ) {
- this.disconnectResolver?.reject(event.payload.message);
- }
-
- private onSwitchChainSuccess(
- event: Extract
- ) {
- this.setLastUsedChainId(event.payload.chainId);
- this.switchChainResolver?.resolve(event.payload);
- }
-
- private onSwitchChainError(
- event: Extract
- ) {
- this.switchChainResolver?.reject(event.payload.message);
- }
-
- private onRpcRequestSuccess(
- event: Extract
- ) {
- this.rpcRequestResolver?.resolve(event.payload);
- }
-
- private onRpcRequestError(
- event: Extract
- ) {
- this.rpcRequestResolver?.reject(event.payload.message);
- }
-
- private onSessionUpdate(
- event: Extract
- ) {
- const { payload } = event;
- if (payload) {
- // Ilja TODO: this.setSessionToken(payload.token)
- }
- }
-
- private onUpdateEmailSuccess(
- event: Extract
- ) {
- this.updateEmailResolver?.resolve(event.payload);
- this.setNewLastEmailLoginTime();
- }
-
- private onUpdateEmailError(
- event: Extract
- ) {
- this.updateEmailResolver?.reject(event.payload.message);
- }
-
- private onUpdateEmailPrimaryOtpSuccess() {
- this.updateEmailPrimaryOtpResolver?.resolve(undefined);
- }
-
- private onUpdateEmailPrimaryOtpError(
- event: Extract<
- AppKitFrameTypes.FrameEvent,
- { type: '@w3m-frame/UPDATE_EMAIL_PRIMARY_OTP_ERROR' }
- >
- ) {
- this.updateEmailPrimaryOtpResolver?.reject(event.payload.message);
- }
-
- private onUpdateEmailSecondaryOtpSuccess(
- event: Extract<
- AppKitFrameTypes.FrameEvent,
- { type: '@w3m-frame/UPDATE_EMAIL_SECONDARY_OTP_SUCCESS' }
- >
- ) {
- const { newEmail } = event.payload;
- this.setEmailLoginSuccess(newEmail);
- this.updateEmailSecondaryOtpResolver?.resolve({ newEmail });
- }
-
- private onUpdateEmailSecondaryOtpError(
- event: Extract<
- AppKitFrameTypes.FrameEvent,
- { type: '@w3m-frame/UPDATE_EMAIL_SECONDARY_OTP_ERROR' }
- >
- ) {
- this.updateEmailSecondaryOtpResolver?.reject(event.payload.message);
- }
-
- private onSyncThemeSuccess() {
- this.syncThemeResolver?.resolve(undefined);
- }
-
- private onSyncThemeError(
- event: Extract
- ) {
- this.syncThemeResolver?.reject(event.payload.message);
- }
-
- private onSyncDappDataSuccess() {
- this.syncDappDataResolver?.resolve(undefined);
- }
-
- private onSyncDappDataError(
- event: Extract
- ) {
- this.syncDappDataResolver?.reject(event.payload.message);
- }
-
// -- Private Methods -------------------------------------------------
private setNewLastEmailLoginTime() {
AppKitFrameStorage.set(AppKitFrameConstants.LAST_EMAIL_LOGIN_TIME, Date.now().toString());
@@ -627,6 +375,70 @@ export class AppKitFrameProvider {
return undefined;
}
+ private async registerFrameEventHandler(
+ id: string,
+ callback: (event: AppKitFrameTypes.FrameEvent) => void,
+ signal: AbortSignal
+ ) {
+ const eventEmitter = this.events;
+ function eventHandler(data: AppKitFrameTypes.FrameEvent) {
+ if (!data.type?.includes(AppKitFrameConstants.FRAME_EVENT_KEY)) {
+ return;
+ }
+ const frameEvent = AppKitFrameSchema.frameEvent.parse(data);
+ if (frameEvent.id === id) {
+ callback(frameEvent);
+ eventEmitter.removeListener('message', eventHandler);
+ }
+ }
+
+ eventEmitter.addListener('message', eventHandler);
+ signal.addEventListener('abort', () => {
+ eventEmitter.removeListener('message', eventHandler);
+ });
+ }
+
+ private async appEvent(
+ event: Omit
+ ): Promise {
+ await this.webviewLoadPromise;
+ const type = event.type.replace('@w3m-app/', '');
+
+ return new Promise((resolve, reject) => {
+ const id = Math.random().toString(36).substring(7);
+
+ this.postAppEvent({ ...event, id } as AppKitFrameTypes.AppEvent);
+ const abortController = new AbortController();
+ if (type === 'RPC_REQUEST') {
+ const rpcEvent = event as Extract<
+ AppKitFrameTypes.AppEvent,
+ { type: '@w3m-app/RPC_REQUEST' }
+ >;
+ this.openRpcRequests = [...this.openRpcRequests, { ...rpcEvent.payload, abortController }];
+ }
+ abortController.signal.addEventListener('abort', () => {
+ if (type === 'RPC_REQUEST') {
+ reject(new Error('Request was aborted'));
+ }
+ });
+
+ function handler(frameEvent: AppKitFrameTypes.FrameEvent) {
+ if (frameEvent.type === `@w3m-frame/${type}_SUCCESS`) {
+ if ('payload' in frameEvent) {
+ resolve(frameEvent.payload);
+ }
+ resolve(undefined as unknown as AppKitFrameTypes.Responses[`Frame${T}Response`]);
+ } else if (frameEvent.type === `@w3m-frame/${type}_ERROR`) {
+ if ('payload' in frameEvent) {
+ reject(new Error(frameEvent.payload?.message || 'An error occurred'));
+ }
+ reject(new Error('An error occurred'));
+ }
+ }
+ this.registerFrameEventHandler(id, handler, abortController.signal);
+ });
+ }
+
private onFrameEvent(
event: AppKitFrameTypes.FrameEvent,
callback: (event: AppKitFrameTypes.FrameEvent) => void
@@ -679,3 +491,21 @@ export class AppKitFrameProvider {
return email;
}
}
+
+export interface AppKitFrameProviderMethods {
+ // Email
+ connectEmail: AppKitFrameProvider['connectEmail'];
+ connectOtp: AppKitFrameProvider['connectOtp'];
+ updateEmail: AppKitFrameProvider['updateEmail'];
+ updateEmailPrimaryOtp: AppKitFrameProvider['updateEmailPrimaryOtp'];
+ updateEmailSecondaryOtp: AppKitFrameProvider['updateEmailSecondaryOtp'];
+ getEmail: AppKitFrameProvider['getEmail'];
+
+ // Social
+ connectDevice: AppKitFrameProvider['connectDevice'];
+
+ // Misc
+ syncTheme: AppKitFrameProvider['syncTheme'];
+ syncDappData: AppKitFrameProvider['syncDappData'];
+ switchNetwork: AppKitFrameProvider['switchNetwork'];
+}
diff --git a/packages/wallet/src/AppKitFrameSchema.ts b/packages/wallet/src/AppKitFrameSchema.ts
index 6ee16be62..552338641 100644
--- a/packages/wallet/src/AppKitFrameSchema.ts
+++ b/packages/wallet/src/AppKitFrameSchema.ts
@@ -29,10 +29,10 @@ export const GetTransactionByHashResponse = z.object({
v: z.string(),
value: z.string()
});
-export const AppSwitchNetworkRequest = z.object({ chainId: z.number() });
+export const AppSwitchNetworkRequest = z.object({ chainId: z.string().or(z.number()) });
export const AppConnectEmailRequest = z.object({ email: z.string().email() });
export const AppConnectOtpRequest = z.object({ otp: z.string() });
-export const AppGetUserRequest = z.object({ chainId: z.optional(z.number()) });
+export const AppGetUserRequest = z.object({ chainId: z.optional(z.string().or(z.number())) });
export const AppUpdateEmailRequest = z.object({ email: z.string().email() });
export const AppUpdateEmailPrimaryOtpRequest = z.object({ otp: z.string() });
export const AppUpdateEmailSecondaryOtpRequest = z.object({ otp: z.string() });
@@ -73,7 +73,7 @@ export const FrameGetUserResponse = z.object({
export const FrameIsConnectedResponse = z.object({ isConnected: z.boolean() });
export const FrameGetChainIdResponse = z.object({ chainId: z.number() });
export const FrameSwitchNetworkResponse = z.object({ chainId: z.number() });
-export const FrameUpdateEmailSecondaryOtpResolver = z.object({ newEmail: z.string().email() });
+export const FrameUpdateEmailSecondaryOtpResponse = z.object({ newEmail: z.string().email() });
export const RpcResponse = z.any();
@@ -258,28 +258,35 @@ export const FrameSession = z.object({
token: z.string()
});
+export const EventSchema = z.object({
+ // Remove optional once all packages are updated
+ id: z.string().optional()
+});
+
export const AppKitFrameSchema = {
// -- App Events -----------------------------------------------------------
- appEvent: z
- .object({ type: zType('APP_SWITCH_NETWORK'), payload: AppSwitchNetworkRequest })
+ appEvent: EventSchema.extend({
+ type: zType('APP_SWITCH_NETWORK'),
+ payload: AppSwitchNetworkRequest
+ })
- .or(z.object({ type: zType('APP_CONNECT_EMAIL'), payload: AppConnectEmailRequest }))
+ .or(EventSchema.extend({ type: zType('APP_CONNECT_EMAIL'), payload: AppConnectEmailRequest }))
- .or(z.object({ type: zType('APP_CONNECT_DEVICE') }))
+ .or(EventSchema.extend({ type: zType('APP_CONNECT_DEVICE') }))
- .or(z.object({ type: zType('APP_CONNECT_OTP'), payload: AppConnectOtpRequest }))
+ .or(EventSchema.extend({ type: zType('APP_CONNECT_OTP'), payload: AppConnectOtpRequest }))
- .or(z.object({ type: zType('APP_GET_USER'), payload: z.optional(AppGetUserRequest) }))
+ .or(EventSchema.extend({ type: zType('APP_GET_USER'), payload: z.optional(AppGetUserRequest) }))
- .or(z.object({ type: zType('APP_SIGN_OUT') }))
+ .or(EventSchema.extend({ type: zType('APP_SIGN_OUT') }))
- .or(z.object({ type: zType('APP_IS_CONNECTED'), payload: z.optional(FrameSession) }))
+ .or(EventSchema.extend({ type: zType('APP_IS_CONNECTED'), payload: z.optional(FrameSession) }))
- .or(z.object({ type: zType('APP_GET_CHAIN_ID') }))
+ .or(EventSchema.extend({ type: zType('APP_GET_CHAIN_ID') }))
.or(
- z.object({
+ EventSchema.extend({
type: zType('APP_RPC_REQUEST'),
payload: RpcPersonalSignRequest.or(RpcEthSendTransactionRequest)
.or(RpcEthAccountsRequest)
@@ -322,96 +329,145 @@ export const AppKitFrameSchema = {
})
)
- .or(z.object({ type: zType('APP_UPDATE_EMAIL'), payload: AppUpdateEmailRequest }))
+ .or(EventSchema.extend({ type: zType('APP_UPDATE_EMAIL'), payload: AppUpdateEmailRequest }))
.or(
- z.object({
+ EventSchema.extend({
type: zType('APP_UPDATE_EMAIL_PRIMARY_OTP'),
payload: AppUpdateEmailPrimaryOtpRequest
})
)
.or(
- z.object({
+ EventSchema.extend({
type: zType('APP_UPDATE_EMAIL_SECONDARY_OTP'),
payload: AppUpdateEmailSecondaryOtpRequest
})
)
- .or(z.object({ type: zType('APP_SYNC_THEME'), payload: AppSyncThemeRequest }))
+ .or(EventSchema.extend({ type: zType('APP_SYNC_THEME'), payload: AppSyncThemeRequest }))
- .or(z.object({ type: zType('APP_SYNC_DAPP_DATA'), payload: AppSyncDappDataRequest })),
+ .or(EventSchema.extend({ type: zType('APP_SYNC_DAPP_DATA'), payload: AppSyncDappDataRequest })),
// -- Frame Events ---------------------------------------------------------
- frameEvent: z
- .object({ type: zType('FRAME_SWITCH_NETWORK_ERROR'), payload: zError, origin: z.string() })
+ frameEvent: EventSchema.extend({
+ type: zType('FRAME_SWITCH_NETWORK_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_SWITCH_NETWORK_SUCCESS'),
payload: FrameSwitchNetworkResponse,
origin: z.string()
})
)
- .or(z.object({ type: zType('FRAME_CONNECT_EMAIL_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_CONNECT_EMAIL_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_CONNECT_EMAIL_SUCCESS'),
payload: FrameConnectEmailResponse,
origin: z.string()
})
)
- .or(z.object({ type: zType('FRAME_CONNECT_OTP_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_CONNECT_OTP_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
- .or(z.object({ type: zType('FRAME_CONNECT_OTP_SUCCESS'), origin: z.string() }))
+ .or(EventSchema.extend({ type: zType('FRAME_CONNECT_OTP_SUCCESS'), origin: z.string() }))
.or(
- z.object({ type: zType('FRAME_CONNECT_DEVICE_ERROR'), payload: zError, origin: z.string() })
+ EventSchema.extend({
+ type: zType('FRAME_CONNECT_DEVICE_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
)
- .or(z.object({ type: zType('FRAME_CONNECT_DEVICE_SUCCESS'), origin: z.string() }))
+ .or(EventSchema.extend({ type: zType('FRAME_CONNECT_DEVICE_SUCCESS'), origin: z.string() }))
- .or(z.object({ type: zType('FRAME_GET_USER_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_USER_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_GET_USER_SUCCESS'),
payload: FrameGetUserResponse,
origin: z.string()
})
)
- .or(z.object({ type: zType('FRAME_SIGN_OUT_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_SIGN_OUT_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
- .or(z.object({ type: zType('FRAME_SIGN_OUT_SUCCESS'), origin: z.string() }))
+ .or(EventSchema.extend({ type: zType('FRAME_SIGN_OUT_SUCCESS'), origin: z.string() }))
- .or(z.object({ type: zType('FRAME_IS_CONNECTED_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_IS_CONNECTED_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_IS_CONNECTED_SUCCESS'),
payload: FrameIsConnectedResponse,
origin: z.string()
})
)
- .or(z.object({ type: zType('FRAME_GET_CHAIN_ID_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_CHAIN_ID_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_GET_CHAIN_ID_SUCCESS'),
payload: FrameGetChainIdResponse,
origin: z.string()
})
)
- .or(z.object({ type: zType('FRAME_RPC_REQUEST_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_RPC_REQUEST_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_RPC_REQUEST_SUCCESS'),
payload: RpcResponse,
origin: z.string()
@@ -419,13 +475,23 @@ export const AppKitFrameSchema = {
)
.or(
- z.object({ type: zType('FRAME_SESSION_UPDATE'), payload: FrameSession, origin: z.string() })
+ EventSchema.extend({
+ type: zType('FRAME_SESSION_UPDATE'),
+ payload: FrameSession,
+ origin: z.string()
+ })
)
- .or(z.object({ type: zType('FRAME_UPDATE_EMAIL_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_UPDATE_EMAIL_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_UPDATE_EMAIL_SUCCESS'),
payload: FrameUpdateEmailResponse,
origin: z.string()
@@ -433,17 +499,22 @@ export const AppKitFrameSchema = {
)
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_UPDATE_EMAIL_PRIMARY_OTP_ERROR'),
payload: zError,
origin: z.string()
})
)
- .or(z.object({ type: zType('FRAME_UPDATE_EMAIL_PRIMARY_OTP_SUCCESS'), origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_UPDATE_EMAIL_PRIMARY_OTP_SUCCESS'),
+ origin: z.string()
+ })
+ )
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_UPDATE_EMAIL_SECONDARY_OTP_ERROR'),
payload: zError,
origin: z.string()
@@ -451,20 +522,30 @@ export const AppKitFrameSchema = {
)
.or(
- z.object({
+ EventSchema.extend({
type: zType('FRAME_UPDATE_EMAIL_SECONDARY_OTP_SUCCESS'),
- payload: FrameUpdateEmailSecondaryOtpResolver,
+ payload: FrameUpdateEmailSecondaryOtpResponse,
origin: z.string()
})
)
- .or(z.object({ type: zType('FRAME_SYNC_THEME_ERROR'), payload: zError, origin: z.string() }))
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_SYNC_THEME_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
- .or(z.object({ type: zType('FRAME_SYNC_THEME_SUCCESS'), origin: z.string() }))
+ .or(EventSchema.extend({ type: zType('FRAME_SYNC_THEME_SUCCESS'), origin: z.string() }))
.or(
- z.object({ type: zType('FRAME_SYNC_DAPP_DATA_ERROR'), payload: zError, origin: z.string() })
+ EventSchema.extend({
+ type: zType('FRAME_SYNC_DAPP_DATA_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
)
- .or(z.object({ type: zType('FRAME_SYNC_DAPP_DATA_SUCCESS'), origin: z.string() }))
+ .or(EventSchema.extend({ type: zType('FRAME_SYNC_DAPP_DATA_SUCCESS'), origin: z.string() }))
};
diff --git a/packages/wallet/src/AppKitFrameTypes.ts b/packages/wallet/src/AppKitFrameTypes.ts
index bc29ab59e..256f9f137 100644
--- a/packages/wallet/src/AppKitFrameTypes.ts
+++ b/packages/wallet/src/AppKitFrameTypes.ts
@@ -48,7 +48,7 @@ import {
FrameSession,
AppGetUserRequest,
AppUpdateEmailRequest,
- FrameUpdateEmailSecondaryOtpResolver,
+ FrameUpdateEmailSecondaryOtpResponse,
AppUpdateEmailPrimaryOtpRequest,
AppUpdateEmailSecondaryOtpRequest,
AppSyncThemeRequest,
@@ -80,9 +80,16 @@ export namespace AppKitFrameTypes {
FrameGetChainIdResponse: z.infer;
FrameGetUserResponse: z.infer;
FrameIsConnectedResponse: z.infer;
- FrameUpdateEmailSecondaryOtpResolver: z.infer;
FrameSwitchNetworkResponse: z.infer;
FrameUpdateEmailResponse: z.infer;
+ FrameConnectOtpResponse: undefined;
+ FrameSyncThemeResponse: undefined;
+ FrameSyncDappDataResponse: undefined;
+ FrameUpdateEmailPrimaryOtpResponse: undefined;
+ FrameUpdateEmailSecondaryOtpResponse: z.infer;
+ FrameConnectDeviceResponse: undefined;
+ FrameSignOutResponse: undefined;
+ FrameRpcResponse: RPCResponse;
}
export interface Network {
@@ -139,4 +146,20 @@ export namespace AppKitFrameTypes {
export type RPCResponse = z.infer;
export type FrameSessionType = z.infer;
+
+ export type ProviderRequestType =
+ | 'GetUser'
+ | 'ConnectDevice'
+ | 'ConnectEmail'
+ | 'ConnectOtp'
+ | 'SwitchNetwork'
+ | 'UpdateEmail'
+ | 'SyncTheme'
+ | 'SyncDappData'
+ | 'UpdateEmailPrimaryOtp'
+ | 'UpdateEmailSecondaryOtp'
+ | 'GetChainId'
+ | 'IsConnected'
+ | 'SignOut'
+ | 'Rpc';
}
diff --git a/packages/wallet/src/index.ts b/packages/wallet/src/index.ts
index c2c9f6d54..f77b09495 100644
--- a/packages/wallet/src/index.ts
+++ b/packages/wallet/src/index.ts
@@ -1,5 +1,5 @@
export { AppKitFrameHelpers } from './AppKitFrameHelpers';
-export { AppKitFrameProvider } from './AppKitFrameProvider';
+export { AppKitFrameProvider, type AppKitFrameProviderMethods } from './AppKitFrameProvider';
export { AppKitFrameSchema } from './AppKitFrameSchema';
export { AppKitFrameConstants, AppKitFrameRpcConstants } from './AppKitFrameConstants';
export { AppKitFrameStorage } from './AppKitFrameStorage';
From f37bfba8a5a986217e2f6dade4cc43f42de57262 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 23 Sep 2024 15:50:39 -0300
Subject: [PATCH 051/114] chore: send changes
---
.../src/partials/w3m-input-token/intex.tsx | 20 ++++++++++---------
.../views/w3m-account-default-view/index.tsx | 5 ++++-
.../views/w3m-wallet-receive-view/index.tsx | 4 +---
.../src/views/w3m-wallet-send-view/index.tsx | 8 ++++++--
packages/wallet/src/AppKitAuthWebview.tsx | 2 +-
5 files changed, 23 insertions(+), 16 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-input-token/intex.tsx b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
index ca27213bf..b327ff4de 100644
--- a/packages/scaffold/src/partials/w3m-input-token/intex.tsx
+++ b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
@@ -2,7 +2,7 @@ import { useRef, useState } from 'react';
import { TextInput, type StyleProp, type ViewStyle } from 'react-native';
import { FlexView, Link, Text, useTheme, TokenButton } from '@reown/appkit-ui-react-native';
import { NumberUtil, type Balance } from '@reown/appkit-common-react-native';
-import { SendController } from '@reown/appkit-core-react-native';
+import { ConstantsUtil, SendController } from '@reown/appkit-core-react-native';
import styles from './styles';
import { getMaxAmount, getSendValue } from './utils';
@@ -10,11 +10,11 @@ import { getMaxAmount, getSendValue } from './utils';
export interface InputTokenProps {
token?: Balance;
sendTokenAmount?: number;
- gasPriceInUSD?: number;
+ gasPrice?: number;
style?: StyleProp;
}
-export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: InputTokenProps) {
+export function InputToken({ token, sendTokenAmount, gasPrice, style }: InputTokenProps) {
const Theme = useTheme();
const valueInputRef = useRef(null);
const [inputValue, setInputValue] = useState(sendTokenAmount?.toString());
@@ -31,15 +31,17 @@ export function InputToken({ token, sendTokenAmount, gasPriceInUSD, style }: Inp
};
const onMaxPress = () => {
- if (token && gasPriceInUSD) {
- const amountOfTokenGasRequired = NumberUtil.bigNumber(gasPriceInUSD.toFixed(5)).dividedBy(
- token.price
- );
+ if (token && gasPrice) {
+ const isNetworkToken =
+ token.address === undefined ||
+ Object.values(ConstantsUtil.NATIVE_TOKEN_ADDRESS).some(
+ nativeAddress => token?.address === nativeAddress
+ );
- const isNetworkToken = token.address === undefined;
+ const numericGas = NumberUtil.bigNumber(gasPrice).shiftedBy(-token.quantity.decimals);
const maxValue = isNetworkToken
- ? NumberUtil.bigNumber(token.quantity.numeric).minus(amountOfTokenGasRequired)
+ ? NumberUtil.bigNumber(token.quantity.numeric).minus(numericGas)
: NumberUtil.bigNumber(token.quantity.numeric);
SendController.setTokenAmount(Number(maxValue.toFixed(20)));
diff --git a/packages/scaffold/src/views/w3m-account-default-view/index.tsx b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
index 3295bad8f..b00070b4f 100644
--- a/packages/scaffold/src/views/w3m-account-default-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
@@ -78,7 +78,10 @@ export function AccountDefaultView() {
};
const onCopyAddress = () => {
- if (AccountController.state.address) {
+ if (AccountController.state.profileName) {
+ OptionsController.copyToClipboard(AccountController.state.profileName);
+ SnackController.showSuccess('Name copied');
+ } else if (AccountController.state.address) {
OptionsController.copyToClipboard(
AccountController.state.profileName ?? AccountController.state.address
);
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
index ce7c0c8c1..51693a34f 100644
--- a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
@@ -45,9 +45,7 @@ export function WalletReceiveView() {
const onCopyAddress = () => {
if (canCopy && AccountController.state.address) {
- OptionsController.copyToClipboard(
- AccountController.state.profileName ?? AccountController.state.address
- );
+ OptionsController.copyToClipboard(AccountController.state.address);
SnackController.showSuccess('Address copied');
}
};
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index 1c308ed18..0ad2686e0 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -24,7 +24,7 @@ import styles from './styles';
export function WalletSendView() {
const { padding } = useCustomDimensions();
const { keyboardShown, keyboardHeight } = useKeyboard();
- const { token, sendTokenAmount, receiverAddress, loading, gasPriceInUSD } = useSnapshot(
+ const { token, sendTokenAmount, receiverAddress, loading, gasPrice } = useSnapshot(
SendController.state
);
const { tokenBalance } = useSnapshot(AccountController.state);
@@ -58,6 +58,10 @@ export function WalletSendView() {
return 'Insufficient balance';
}
+ if (!SendController.state.receiverAddress) {
+ return 'Add address';
+ }
+
return 'Preview Send';
};
@@ -77,7 +81,7 @@ export function WalletSendView() {
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index 438e511dc..32a1bee7d 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -75,7 +75,7 @@ export function AuthWebview() {
});
provider.onRpcError(() => {
- if (isWebviewVisibile) {
+ if (ModalController.state.open) {
if (RouterController.state.transactionStack.length === 0) {
ModalController.close();
} else {
From 66b3551bc5d6f37081a75cc09f39065371ad348d Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 23 Sep 2024 19:41:25 -0300
Subject: [PATCH 052/114] chore: select token view
---
packages/core/src/utils/CoreHelperUtil.ts | 21 ++++
.../scaffold/src/modal/w3m-router/index.tsx | 3 +
.../src/partials/w3m-input-token/intex.tsx | 27 ++++--
.../index.tsx | 47 +++++++++
.../styles.ts | 11 +++
.../src/views/w3m-wallet-send-view/index.tsx | 49 ++++++++--
.../src/views/w3m-wallet-send-view/styles.ts | 5 +-
.../ui/src/composites/wui-button/styles.ts | 2 +-
.../src/composites/wui-list-token/index.tsx | 96 +++++++++++--------
.../src/composites/wui-token-button/index.tsx | 24 +++--
.../src/composites/wui-token-button/styles.ts | 4 +
packages/wallet/src/AppKitFrameProvider.ts | 11 ---
12 files changed, 216 insertions(+), 84 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-wallet-send-select-token-view/styles.ts
diff --git a/packages/core/src/utils/CoreHelperUtil.ts b/packages/core/src/utils/CoreHelperUtil.ts
index 6fd2906ee..99eb1255b 100644
--- a/packages/core/src/utils/CoreHelperUtil.ts
+++ b/packages/core/src/utils/CoreHelperUtil.ts
@@ -157,6 +157,27 @@ export const CoreHelperUtil = {
return formattedBalance ? `${formattedBalance} ${symbol}` : `0.000 ${symbol || ''}`;
},
+ isAddress(address: string, chain = 'eip155'): boolean {
+ switch (chain) {
+ case 'eip155':
+ if (!/^(?:0x)?[0-9a-f]{40}$/iu.test(address)) {
+ return false;
+ } else if (
+ /^(?:0x)?[0-9a-f]{40}$/iu.test(address) ||
+ /^(?:0x)?[0-9A-F]{40}$/iu.test(address)
+ ) {
+ return true;
+ }
+
+ return false;
+ case 'solana':
+ return /[1-9A-HJ-NP-Za-km-z]{32,44}$/iu.test(address);
+
+ default:
+ return false;
+ }
+ },
+
getApiUrl() {
return CommonConstants.API_URL;
},
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index d3c514d92..f7c313e57 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -26,6 +26,7 @@ import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-netw
import { TransactionsView } from '../../views/w3m-transactions-view';
import { WalletSendView } from '../../views/w3m-wallet-send-view';
import { WalletSendPreviewView } from '../../views/w3m-wallet-send-preview-view';
+import { WalletSendSelectTokenView } from '../../views/w3m-wallet-send-select-token-view';
export function AppKitRouter() {
const { view } = useSnapshot(RouterController.state);
@@ -78,6 +79,8 @@ export function AppKitRouter() {
return WalletSendView;
case 'WalletSendPreview':
return WalletSendPreviewView;
+ case 'WalletSendSelectToken':
+ return WalletSendSelectTokenView;
case 'WhatIsANetwork':
return WhatIsNetworkView;
case 'WhatIsAWallet':
diff --git a/packages/scaffold/src/partials/w3m-input-token/intex.tsx b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
index b327ff4de..1e89612b9 100644
--- a/packages/scaffold/src/partials/w3m-input-token/intex.tsx
+++ b/packages/scaffold/src/partials/w3m-input-token/intex.tsx
@@ -4,17 +4,24 @@ import { FlexView, Link, Text, useTheme, TokenButton } from '@reown/appkit-ui-re
import { NumberUtil, type Balance } from '@reown/appkit-common-react-native';
import { ConstantsUtil, SendController } from '@reown/appkit-core-react-native';
-import styles from './styles';
import { getMaxAmount, getSendValue } from './utils';
+import styles from './styles';
export interface InputTokenProps {
token?: Balance;
sendTokenAmount?: number;
gasPrice?: number;
style?: StyleProp;
+ onTokenPress?: () => void;
}
-export function InputToken({ token, sendTokenAmount, gasPrice, style }: InputTokenProps) {
+export function InputToken({
+ token,
+ sendTokenAmount,
+ gasPrice,
+ style,
+ onTokenPress
+}: InputTokenProps) {
const Theme = useTheme();
const valueInputRef = useRef(null);
const [inputValue, setInputValue] = useState(sendTokenAmount?.toString());
@@ -81,7 +88,7 @@ export function InputToken({ token, sendTokenAmount, gasPrice, style }: InputTok
numberOfLines={1}
autoFocus={!!token}
/>
-
+
{sendValue ?? ''}
-
-
- {maxAmount ?? ''}
-
- Max
-
+ {token && (
+
+
+ {maxAmount ?? ''}
+
+ Max
+
+ )}
);
diff --git a/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
new file mode 100644
index 000000000..7f9253425
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
@@ -0,0 +1,47 @@
+import { useSnapshot } from 'valtio';
+
+import { FlexView, ListToken, Text } from '@reown/appkit-ui-react-native';
+import {
+ AccountController,
+ AssetUtil,
+ NetworkController,
+ RouterController,
+ SendController
+} from '@reown/appkit-core-react-native';
+import { ScrollView } from 'react-native';
+import styles from './styles';
+import type { Balance } from '@reown/appkit-common-react-native';
+
+export function WalletSendSelectTokenView() {
+ const { tokenBalance } = useSnapshot(AccountController.state);
+ const { caipNetwork } = useSnapshot(NetworkController.state);
+ const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+
+ const onTokenPress = (token: Balance) => {
+ SendController.setToken(token);
+ SendController.setTokenAmount(undefined);
+ RouterController.goBack();
+ };
+
+ return (
+
+
+
+ Your tokens
+
+ {tokenBalance?.map(token => (
+ onTokenPress(token)}
+ />
+ ))}
+
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-select-token-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/styles.ts
new file mode 100644
index 000000000..43dcd318a
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/styles.ts
@@ -0,0 +1,11 @@
+import { StyleSheet } from 'react-native';
+import { Spacing } from '@reown/appkit-ui-react-native';
+
+export default StyleSheet.create({
+ container: {
+ minHeight: 250
+ },
+ title: {
+ marginBottom: Spacing.xs
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index 0ad2686e0..154e21f23 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -3,6 +3,7 @@ import { Platform, ScrollView } from 'react-native';
import { useSnapshot } from 'valtio';
import {
AccountController,
+ CoreHelperUtil,
RouterController,
SendController,
SwapController
@@ -44,32 +45,55 @@ export function WalletSendView() {
}, []);
const onSendPress = () => {
- if (SendController.state.loading) return;
- // TODO: add validations
RouterController.push('WalletSendPreview');
};
const getActionText = () => {
+ if (!SendController.state.token) {
+ return 'Select token';
+ }
+
if (
- SendController.state.token &&
SendController.state.sendTokenAmount &&
+ SendController.state.token &&
SendController.state.sendTokenAmount > Number(SendController.state.token.quantity.numeric)
) {
- return 'Insufficient balance';
+ return 'Insufficient funds';
+ }
+
+ if (!SendController.state.sendTokenAmount) {
+ return 'Add amount';
+ }
+
+ if (SendController.state.sendTokenAmount && SendController.state.token?.price) {
+ const value = SendController.state.sendTokenAmount * SendController.state.token.price;
+ if (!value) {
+ return 'Incorrect value';
+ }
+ }
+
+ if (
+ SendController.state.receiverAddress &&
+ !CoreHelperUtil.isAddress(SendController.state.receiverAddress)
+ ) {
+ return 'Invalid address';
}
if (!SendController.state.receiverAddress) {
return 'Add address';
}
- return 'Preview Send';
+ return 'Preview send';
};
useEffect(() => {
- // TODO: check this
- SendController.setToken(tokenBalance?.[0]);
+ if (!token) {
+ SendController.setToken(tokenBalance?.[0]);
+ }
fetchNetworkPrice();
- }, [tokenBalance, fetchNetworkPrice]);
+ }, [token, tokenBalance, fetchNetworkPrice]);
+
+ const actionText = getActionText();
return (
RouterController.push('WalletSendSelectToken')}
/>
@@ -98,7 +123,11 @@ export function WalletSendView() {
style={styles.arrowIcon}
/>
-
+
{loading ? (
) : (
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
index 9abf25791..7fded2195 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
@@ -1,10 +1,11 @@
-import { Spacing } from '@reown/appkit-ui-react-native';
+import { BorderRadius, Spacing } from '@reown/appkit-ui-react-native';
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
sendButton: {
width: '100%',
- marginTop: Spacing.xl
+ marginTop: Spacing.xl,
+ borderRadius: BorderRadius.xs
},
tokenInput: {
marginBottom: Spacing.xs
diff --git a/packages/ui/src/composites/wui-button/styles.ts b/packages/ui/src/composites/wui-button/styles.ts
index 5fc51c1e6..8da1107cf 100644
--- a/packages/ui/src/composites/wui-button/styles.ts
+++ b/packages/ui/src/composites/wui-button/styles.ts
@@ -14,7 +14,7 @@ export const getThemedButtonStyle = (
if (disabled) {
return {
- backgroundColor: variant === 'fill' ? theme['gray-glass-002'] : theme['gray-glass-010'],
+ backgroundColor: variant === 'fill' ? theme['gray-glass-005'] : theme['gray-glass-010'],
borderColor: theme['gray-glass-002']
};
}
diff --git a/packages/ui/src/composites/wui-list-token/index.tsx b/packages/ui/src/composites/wui-list-token/index.tsx
index 43acad2cf..30b8662eb 100644
--- a/packages/ui/src/composites/wui-list-token/index.tsx
+++ b/packages/ui/src/composites/wui-list-token/index.tsx
@@ -1,3 +1,4 @@
+import { Pressable } from 'react-native';
import { Icon } from '../../components/wui-icon';
import { Image } from '../../components/wui-image';
import { Text } from '../../components/wui-text';
@@ -13,59 +14,70 @@ export interface ListTokenProps {
value?: number;
amount?: string;
currency: string;
+ onPress?: () => void;
}
-export function ListToken({ imageSrc, networkSrc, name, value, amount, currency }: ListTokenProps) {
+export function ListToken({
+ imageSrc,
+ networkSrc,
+ name,
+ value,
+ amount,
+ currency,
+ onPress
+}: ListTokenProps) {
const Theme = useTheme();
return (
-
-
- {imageSrc ? (
-
- ) : (
+
+
+
+ {imageSrc ? (
+
+ ) : (
+
+
+
+ )}
-
+ {networkSrc ? (
+
+ ) : (
+
+ )}
+
+
+
+ {name}
+
+
+ {UiUtil.formatNumberToLocalString(amount, 4)} {currency}
+
- )}
-
- {networkSrc ? (
-
- ) : (
-
- )}
-
-
-
- {name}
-
-
- {UiUtil.formatNumberToLocalString(amount, 4)} {currency}
-
+
+ ${value?.toFixed(2) ?? '0.00'}
+
-
- ${value?.toFixed(2) ?? '0.00'}
-
-
+
);
}
diff --git a/packages/ui/src/composites/wui-token-button/index.tsx b/packages/ui/src/composites/wui-token-button/index.tsx
index 551059544..b7a489e2a 100644
--- a/packages/ui/src/composites/wui-token-button/index.tsx
+++ b/packages/ui/src/composites/wui-token-button/index.tsx
@@ -1,23 +1,29 @@
+import type { Balance } from '@reown/appkit-common-react-native';
import { Image } from '../../components/wui-image';
import { Text } from '../../components/wui-text';
import { Button } from '../wui-button';
import styles from './styles';
export interface TokenButtonProps {
- text?: string;
- imageSrc?: string;
+ onPress?: () => void;
+ token?: Balance;
}
-export function TokenButton({ text, imageSrc }: TokenButtonProps) {
- if (!text) {
- // TODO: add empty state
- return null;
+export function TokenButton({ token, onPress }: TokenButtonProps) {
+ if (!token) {
+ return (
+
+
+ Select token
+
+
+ );
}
return (
-
- {imageSrc && }
- {text}
+
+ {token?.iconUrl && }
+ {token?.symbol && {token.symbol}}
);
}
diff --git a/packages/ui/src/composites/wui-token-button/styles.ts b/packages/ui/src/composites/wui-token-button/styles.ts
index ad753204b..7ece57a06 100644
--- a/packages/ui/src/composites/wui-token-button/styles.ts
+++ b/packages/ui/src/composites/wui-token-button/styles.ts
@@ -2,6 +2,10 @@ import { StyleSheet } from 'react-native';
import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
export default StyleSheet.create({
+ selectButton: {
+ height: 40,
+ paddingHorizontal: Spacing.m
+ },
container: {
height: 40
},
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index d09b08655..41f336a7e 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -453,17 +453,6 @@ export class AppKitFrameProvider {
callback(frameEvent);
}
- private onAppEvent(
- event: AppKitFrameTypes.AppEvent,
- callback: (event: AppKitFrameTypes.AppEvent) => void
- ) {
- if (!event.type?.includes(AppKitFrameConstants.APP_EVENT_KEY)) {
- return;
- }
- const appEvent = AppKitFrameSchema.appEvent.parse(event);
- callback(appEvent);
- }
-
private postAppEvent(event: AppKitFrameTypes.AppEvent) {
if (!this.webviewRef?.current) {
throw new Error('AppKitFrameProvider: webviewRef is not set');
From b03481f3895d7979978108aed59f958488cb35ec Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 23 Sep 2024 19:58:44 -0300
Subject: [PATCH 053/114] chore: ui improvements
---
.../w3m-wallet-send-preview-view/index.tsx | 103 +++++++++---------
.../index.tsx | 41 +++++--
.../styles.ts | 6 +-
3 files changed, 92 insertions(+), 58 deletions(-)
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
index 5e2661ae1..0c0fd66ba 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
@@ -1,4 +1,5 @@
import { useSnapshot } from 'valtio';
+import { ScrollView } from 'react-native';
import { Avatar, Button, FlexView, Icon, Image, Text, UiUtil } from '@reown/appkit-ui-react-native';
import { NumberUtil } from '@reown/appkit-common-react-native';
import {
@@ -6,11 +7,13 @@ import {
RouterController,
SendController
} from '@reown/appkit-core-react-native';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import { PreviewSendPill } from './components/preview-send-pill';
import styles from './styles';
import { PreviewSendDetails } from './components/preview-send-details';
export function WalletSendPreviewView() {
+ const { padding } = useCustomDimensions();
const { caipNetwork } = useSnapshot(NetworkController.state);
const { token, receiverAddress, gasPriceInUSD, loading } = useSnapshot(SendController.state);
@@ -45,59 +48,61 @@ export function WalletSendPreviewView() {
};
return (
-
-
-
+
+
+
+
+
+ Send
+
+
+ ${getSendValue()}
+
+
+
+ {token?.iconUrl ? (
+
+ ) : (
+
+ )}
+
+
+
+
- Send
+ To
-
- ${getSendValue()}
+
+
+
+
+
+
+
+
+ Review transaction carefully
-
- {token?.iconUrl ? (
-
- ) : (
-
- )}
-
-
-
-
-
- To
-
-
-
-
-
-
-
-
-
- Review transaction carefully
-
-
-
-
- Cancel
-
-
- Send
-
+
+
+ Cancel
+
+
+ Send
+
+
-
+
);
}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
index 7f9253425..80175219d 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
@@ -1,6 +1,7 @@
+import { useState } from 'react';
import { useSnapshot } from 'valtio';
-
-import { FlexView, ListToken, Text } from '@reown/appkit-ui-react-native';
+import { ScrollView } from 'react-native';
+import { FlexView, InputText, ListToken, Text } from '@reown/appkit-ui-react-native';
import {
AccountController,
AssetUtil,
@@ -8,14 +9,26 @@ import {
RouterController,
SendController
} from '@reown/appkit-core-react-native';
-import { ScrollView } from 'react-native';
-import styles from './styles';
import type { Balance } from '@reown/appkit-common-react-native';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import styles from './styles';
+
export function WalletSendSelectTokenView() {
+ const { padding } = useCustomDimensions();
const { tokenBalance } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+ const [tokenSearch, setTokenSearch] = useState('');
+ const [filteredTokens, setFilteredTokens] = useState(tokenBalance ?? []);
+
+ const onSearchChange = (value: string) => {
+ setTokenSearch(value);
+ const filtered = AccountController.state.tokenBalance?.filter(token =>
+ token.name.toLowerCase().includes(value.toLowerCase())
+ );
+ setFilteredTokens(filtered ?? []);
+ };
const onTokenPress = (token: Balance) => {
SendController.setToken(token);
@@ -24,14 +37,26 @@ export function WalletSendSelectTokenView() {
};
return (
-
-
+
+
+
+
+
Your tokens
- {tokenBalance?.map(token => (
+ {filteredTokens.map((token, index) => (
Date: Tue, 24 Sep 2024 14:46:26 -0300
Subject: [PATCH 054/114] fix: added usdt abi
---
packages/common/src/contracts/usdt.ts | 192 ++++++++++++++++++
packages/common/src/index.ts | 2 +
packages/common/src/utils/ConstantsUtil.ts | 5 +-
packages/common/src/utils/ContractUtil.ts | 14 ++
packages/common/src/utils/NamesUtil.ts | 10 +
.../controllers/BlockchainApiController.ts | 11 +
.../src/controllers/ConnectionController.ts | 10 +
.../core/src/controllers/EnsController.ts | 39 ++++
.../core/src/controllers/SendController.ts | 12 +-
packages/core/src/index.ts | 2 +
packages/core/src/utils/TypeUtil.ts | 28 +++
packages/scaffold/src/client.ts | 10 +
.../src/partials/w3m-input-address/index.tsx | 29 ++-
.../components/preview-send-details.tsx | 11 +-
.../w3m-wallet-send-preview-view/index.tsx | 44 +++-
.../src/views/w3m-wallet-send-view/index.tsx | 7 +-
packages/wagmi/src/client.ts | 45 +++-
17 files changed, 444 insertions(+), 27 deletions(-)
create mode 100644 packages/common/src/contracts/usdt.ts
create mode 100644 packages/common/src/utils/ContractUtil.ts
create mode 100644 packages/common/src/utils/NamesUtil.ts
create mode 100644 packages/core/src/controllers/EnsController.ts
diff --git a/packages/common/src/contracts/usdt.ts b/packages/common/src/contracts/usdt.ts
new file mode 100644
index 000000000..abfe5deae
--- /dev/null
+++ b/packages/common/src/contracts/usdt.ts
@@ -0,0 +1,192 @@
+export const usdtABI = [
+ {
+ type: 'event',
+ name: 'Approval',
+ inputs: [
+ {
+ indexed: true,
+ name: 'owner',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'spender',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'value',
+ type: 'uint256'
+ }
+ ]
+ },
+ {
+ type: 'event',
+ name: 'Transfer',
+ inputs: [
+ {
+ indexed: true,
+ name: 'from',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'to',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'value',
+ type: 'uint256'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'allowance',
+ stateMutability: 'view',
+ inputs: [
+ {
+ name: 'owner',
+ type: 'address'
+ },
+ {
+ name: 'spender',
+ type: 'address'
+ }
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'approve',
+ stateMutability: 'nonpayable',
+ inputs: [
+ {
+ name: 'spender',
+ type: 'address'
+ },
+ {
+ name: 'amount',
+ type: 'uint256'
+ }
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'balanceOf',
+ stateMutability: 'view',
+ inputs: [
+ {
+ name: 'account',
+ type: 'address'
+ }
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'decimals',
+ stateMutability: 'view',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'uint8'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'name',
+ stateMutability: 'view',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'string'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'symbol',
+ stateMutability: 'view',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'string'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'totalSupply',
+ stateMutability: 'view',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ]
+ },
+ {
+ type: 'function',
+ name: 'transfer',
+ stateMutability: 'nonpayable',
+ inputs: [
+ {
+ name: 'recipient',
+ type: 'address'
+ },
+ {
+ name: 'amount',
+ type: 'uint256'
+ }
+ ],
+ outputs: []
+ },
+ {
+ type: 'function',
+ name: 'transferFrom',
+ stateMutability: 'nonpayable',
+ inputs: [
+ {
+ name: 'sender',
+ type: 'address'
+ },
+ {
+ name: 'recipient',
+ type: 'address'
+ },
+ {
+ name: 'amount',
+ type: 'uint256'
+ }
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ]
+ }
+] as const;
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 7e84124c2..13f0e979b 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -1,5 +1,7 @@
export { ConstantsUtil } from './utils/ConstantsUtil';
+export { ContractUtil } from './utils/ContractUtil';
export { DateUtil } from './utils/DateUtil';
+export { NamesUtil } from './utils/NamesUtil';
export { NetworkUtil } from './utils/NetworkUtil';
export { NumberUtil } from './utils/NumberUtil';
export { erc20ABI } from './contracts/erc20';
diff --git a/packages/common/src/utils/ConstantsUtil.ts b/packages/common/src/utils/ConstantsUtil.ts
index 064d54442..bf2e03385 100644
--- a/packages/common/src/utils/ConstantsUtil.ts
+++ b/packages/common/src/utils/ConstantsUtil.ts
@@ -1,7 +1,10 @@
export const ConstantsUtil = {
+ WC_NAME_SUFFIX: '.reown.id',
+ WC_NAME_SUFFIX_LEGACY: '.wcn.id',
BLOCKCHAIN_API_RPC_URL: 'https://rpc.walletconnect.org',
PULSE_API_URL: 'https://pulse.walletconnect.org',
API_URL: 'https://api.web3modal.org',
COINBASE_CONNECTOR_ID: 'coinbaseWallet',
- COINBASE_EXPLORER_ID: 'fd20dc426fb37566d803205b19bbc1d4096b248ac04548e3cfb6b3a38bd033aa'
+ COINBASE_EXPLORER_ID: 'fd20dc426fb37566d803205b19bbc1d4096b248ac04548e3cfb6b3a38bd033aa',
+ USDT_CONTRACT_ADDRESS: '0xdac17f958d2ee523a2206206994597c13d831ec7'
};
diff --git a/packages/common/src/utils/ContractUtil.ts b/packages/common/src/utils/ContractUtil.ts
new file mode 100644
index 000000000..3af0e3214
--- /dev/null
+++ b/packages/common/src/utils/ContractUtil.ts
@@ -0,0 +1,14 @@
+import { erc20ABI } from '../contracts/erc20';
+import { usdtABI } from '../contracts/usdt';
+import { ConstantsUtil } from './ConstantsUtil';
+
+export const ContractUtil = {
+ getABI: (tokenAddress: string) => {
+ switch (tokenAddress) {
+ case ConstantsUtil.USDT_CONTRACT_ADDRESS:
+ return usdtABI;
+ default:
+ return erc20ABI;
+ }
+ }
+};
diff --git a/packages/common/src/utils/NamesUtil.ts b/packages/common/src/utils/NamesUtil.ts
new file mode 100644
index 000000000..312eda743
--- /dev/null
+++ b/packages/common/src/utils/NamesUtil.ts
@@ -0,0 +1,10 @@
+import { ConstantsUtil } from './ConstantsUtil';
+
+export const NamesUtil = {
+ isReownName(value: string) {
+ return (
+ value?.endsWith(ConstantsUtil.WC_NAME_SUFFIX_LEGACY) ||
+ value?.endsWith(ConstantsUtil.WC_NAME_SUFFIX)
+ );
+ }
+};
diff --git a/packages/core/src/controllers/BlockchainApiController.ts b/packages/core/src/controllers/BlockchainApiController.ts
index b87d7e626..ddf7eb854 100644
--- a/packages/core/src/controllers/BlockchainApiController.ts
+++ b/packages/core/src/controllers/BlockchainApiController.ts
@@ -8,6 +8,7 @@ import type {
BlockchainApiGasPriceResponse,
BlockchainApiIdentityRequest,
BlockchainApiIdentityResponse,
+ BlockchainApiLookupEnsName,
BlockchainApiTokenPriceRequest,
BlockchainApiTokenPriceResponse,
BlockchainApiTransactionsRequest,
@@ -112,6 +113,16 @@ export const BlockchainApiController = {
});
},
+ async lookupEnsName(name: string) {
+ return state.api.get({
+ path: `/v1/profile/account/${name}`,
+ params: {
+ projectId: OptionsController.state.projectId,
+ apiVersion: '2'
+ }
+ });
+ },
+
setClientId(clientId: string | null) {
state.clientId = clientId;
state.api = new FetchUtil({ baseUrl, clientId });
diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts
index 7ee531432..62faa4539 100644
--- a/packages/core/src/controllers/ConnectionController.ts
+++ b/packages/core/src/controllers/ConnectionController.ts
@@ -31,6 +31,8 @@ export interface ConnectionControllerClient {
formatUnits: (value: bigint, decimals: number) => string;
writeContract: (args: WriteContractArgs) => Promise<`0x${string}` | null>;
disconnect: () => Promise;
+ getEnsAddress: (value: string) => Promise;
+ getEnsAvatar: (value: string) => Promise;
}
export interface ConnectionControllerState {
@@ -147,6 +149,14 @@ export const ConnectionController = {
return this._getClient().writeContract(args);
},
+ async getEnsAddress(value: string) {
+ return this._getClient().getEnsAddress(value);
+ },
+
+ async getEnsAvatar(value: string) {
+ return this._getClient().getEnsAvatar(value);
+ },
+
clearUri() {
state.wcUri = undefined;
state.wcPairingExpiry = undefined;
diff --git a/packages/core/src/controllers/EnsController.ts b/packages/core/src/controllers/EnsController.ts
new file mode 100644
index 000000000..c80fadf21
--- /dev/null
+++ b/packages/core/src/controllers/EnsController.ts
@@ -0,0 +1,39 @@
+import { subscribeKey as subKey } from 'valtio/vanilla/utils';
+import { proxy, subscribe as sub } from 'valtio/vanilla';
+import { BlockchainApiController } from './BlockchainApiController';
+import type { BlockchainApiEnsError } from '../utils/TypeUtil';
+
+// -- Types --------------------------------------------- //
+
+export interface EnsControllerState {
+ loading: boolean;
+}
+
+type StateKey = keyof EnsControllerState;
+
+// -- State --------------------------------------------- //
+const state = proxy({
+ loading: false
+});
+
+// -- Controller ---------------------------------------- //
+export const EnsController = {
+ state,
+
+ subscribe(callback: (newState: EnsControllerState) => void) {
+ return sub(state, () => callback(state));
+ },
+
+ subscribeKey(key: K, callback: (value: EnsControllerState[K]) => void) {
+ return subKey(state, key, callback);
+ },
+
+ async resolveName(name: string) {
+ try {
+ return await BlockchainApiController.lookupEnsName(name);
+ } catch (e) {
+ const error = e as BlockchainApiEnsError;
+ throw new Error(error?.reasons?.[0]?.description || 'Error resolving name');
+ }
+ }
+};
diff --git a/packages/core/src/controllers/SendController.ts b/packages/core/src/controllers/SendController.ts
index 5153f4cd8..b4acf79b2 100644
--- a/packages/core/src/controllers/SendController.ts
+++ b/packages/core/src/controllers/SendController.ts
@@ -1,7 +1,6 @@
import { subscribeKey as subKey } from 'valtio/vanilla/utils';
import { proxy, ref, subscribe as sub } from 'valtio/vanilla';
-import { type Balance } from '@reown/appkit-common-react-native';
-import { erc20ABI } from '@reown/appkit-common-react-native';
+import { ContractUtil, type Balance } from '@reown/appkit-common-react-native';
import { AccountController } from './AccountController';
import { ConnectionController } from './ConnectionController';
import { SnackController } from './SnackController';
@@ -204,15 +203,16 @@ export const SendController = {
params.receiverAddress &&
params.tokenAddress
) {
+ const tokenAddress = CoreHelperUtil.getPlainAddress(
+ params.tokenAddress as `${string}:${string}:${string}`
+ ) as `0x${string}`;
await ConnectionController.writeContract({
fromAddress: AccountController.state.address as `0x${string}`,
- tokenAddress: CoreHelperUtil.getPlainAddress(
- params.tokenAddress as `${string}:${string}:${string}`
- ) as `0x${string}`,
+ tokenAddress,
receiverAddress: params.receiverAddress as `0x${string}`,
tokenAmount: amount,
method: 'transfer',
- abi: erc20ABI
+ abi: ContractUtil.getABI(tokenAddress)
});
SnackController.showSuccess('Transaction started');
this.resetSend();
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 6b62e4e2c..3e0469362 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -47,6 +47,8 @@ export { SwapController, type SwapControllerState } from './controllers/SwapCont
export { EventsController, type EventsControllerState } from './controllers/EventsController';
+export { EnsController, type EnsControllerState } from './controllers/EnsController';
+
export {
TransactionsController,
type TransactionsControllerState
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index b3b2d54fe..4b380d0b9 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -1,5 +1,9 @@
import type { Balance, Transaction } from '@reown/appkit-common-react-native';
+export interface BaseError {
+ message?: string;
+}
+
export type CaipAddress = `${string}:${string}:${string}`;
export type CaipNetworkId = `${string}:${string}`;
@@ -170,6 +174,30 @@ export interface BlockchainApiGasPriceResponse {
instant: string;
}
+export interface BlockchainApiEnsError extends BaseError {
+ status: string;
+ reasons: { name: string; description: string }[];
+}
+
+export type ReownName = `${string}.reown.id` | `${string}.wcn.id`;
+
+export interface BlockchainApiLookupEnsName {
+ name: ReownName;
+ registered: number;
+ updated: number;
+ addresses: Record<
+ string,
+ {
+ address: string;
+ created: string;
+ }
+ >;
+ attributes: {
+ avatar?: string;
+ bio?: string;
+ }[];
+}
+
// -- OptionsController Types ---------------------------------------------------
export interface Token {
address: string;
diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts
index 64d04d9b8..66760372f 100644
--- a/packages/scaffold/src/client.ts
+++ b/packages/scaffold/src/client.ts
@@ -21,6 +21,7 @@ import {
BlockchainApiController,
ConnectionController,
ConnectorController,
+ EnsController,
EventsController,
ModalController,
NetworkController,
@@ -135,6 +136,15 @@ export class AppKitScaffold {
return EventsController.subscribe(callback);
}
+ public resolveReownName = async (name: string) => {
+ const wcNameAddress = await EnsController.resolveName(name);
+ const networkNameAddresses = wcNameAddress?.addresses
+ ? Object.values(wcNameAddress?.addresses)
+ : [];
+
+ return networkNameAddresses[0]?.address || false;
+ };
+
// -- Protected ----------------------------------------------------------------
protected setIsConnected: (typeof AccountController)['setIsConnected'] = isConnected => {
AccountController.setIsConnected(isConnected);
diff --git a/packages/scaffold/src/partials/w3m-input-address/index.tsx b/packages/scaffold/src/partials/w3m-input-address/index.tsx
index 79a8404f1..40e67a8a2 100644
--- a/packages/scaffold/src/partials/w3m-input-address/index.tsx
+++ b/packages/scaffold/src/partials/w3m-input-address/index.tsx
@@ -1,8 +1,10 @@
+import { useState } from 'react';
import { TextInput } from 'react-native';
import { FlexView, useTheme } from '@reown/appkit-ui-react-native';
-import { SendController } from '@reown/appkit-core-react-native';
+import { ConnectionController, SendController } from '@reown/appkit-core-react-native';
+
+import { useDebounceCallback } from '../../hooks/useDebounceCallback';
import styles from './styles';
-import { useState } from 'react';
export interface InputAddressProps {
value?: string;
@@ -12,11 +14,29 @@ export function InputAddress({ value }: InputAddressProps) {
const Theme = useTheme();
const [inputValue, setInputValue] = useState(value);
+ const onSearch = async (search: string) => {
+ SendController.setLoading(true);
+ const address = await ConnectionController.getEnsAddress(search);
+ SendController.setLoading(false);
+
+ if (address) {
+ SendController.setReceiverProfileName(search);
+ SendController.setReceiverAddress(address);
+ const avatar = await ConnectionController.getEnsAvatar(search);
+ SendController.setReceiverProfileImageUrl(avatar || undefined);
+ } else {
+ SendController.setReceiverAddress(search);
+ SendController.setReceiverProfileName(undefined);
+ SendController.setReceiverProfileImageUrl(undefined);
+ }
+ };
+
+ const onDebounceSearch = useDebounceCallback({ callback: onSearch, delay: 800 });
+
const onInputChange = (address: string) => {
setInputValue(address);
SendController.setReceiverAddress(address);
-
- //TODO: Search ENS domain
+ onDebounceSearch(address);
};
return (
@@ -45,6 +65,7 @@ export function InputAddress({ value }: InputAddressProps) {
underlineColorAndroid="transparent"
selectTextOnFocus={false}
multiline
+ returnKeyLabel="Done"
/>
);
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
index ceea64b03..5acc900e7 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
@@ -12,6 +12,7 @@ import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
export interface PreviewSendDetailsProps {
address?: string;
+ name?: string;
caipNetwork?: CaipNetwork;
networkFee?: number;
style?: StyleProp;
@@ -19,12 +20,20 @@ export interface PreviewSendDetailsProps {
export function PreviewSendDetails({
address,
+ name,
caipNetwork,
networkFee,
style
}: PreviewSendDetailsProps) {
const Theme = useTheme();
+ const formattedName = UiUtil.getTruncateString({
+ string: name ?? '',
+ charsStart: 20,
+ charsEnd: 0,
+ truncate: 'end'
+ });
+
const formattedAddress = UiUtil.getTruncateString({
string: address ? address : '',
charsStart: 6,
@@ -52,7 +61,7 @@ export function PreviewSendDetails({
- Address
+ {formattedName ?? 'Address'}
{formattedAddress}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
index 0c0fd66ba..bb907f59a 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
@@ -15,7 +15,14 @@ import { PreviewSendDetails } from './components/preview-send-details';
export function WalletSendPreviewView() {
const { padding } = useCustomDimensions();
const { caipNetwork } = useSnapshot(NetworkController.state);
- const { token, receiverAddress, gasPriceInUSD, loading } = useSnapshot(SendController.state);
+ const {
+ token,
+ receiverAddress,
+ receiverProfileName,
+ receiverProfileImageUrl,
+ gasPriceInUSD,
+ loading
+ } = useSnapshot(SendController.state);
const getSendValue = () => {
if (SendController.state.token && SendController.state.sendTokenAmount) {
@@ -36,17 +43,29 @@ export function WalletSendPreviewView() {
return `${value} ${SendController.state.token?.symbol}`;
};
- const formattedAddress = UiUtil.getTruncateString({
- string: receiverAddress ? receiverAddress : '',
- charsStart: 4,
- charsEnd: 4,
- truncate: 'middle'
- });
+ const formattedAddress = receiverProfileName
+ ? UiUtil.getTruncateString({
+ string: receiverProfileName,
+ charsStart: 20,
+ charsEnd: 0,
+ truncate: 'end'
+ })
+ : UiUtil.getTruncateString({
+ string: receiverAddress ? receiverAddress : '',
+ charsStart: 4,
+ charsEnd: 4,
+ truncate: 'middle'
+ });
const onSend = () => {
SendController.sendToken();
};
+ const onCancel = () => {
+ RouterController.goBack();
+ SendController.setLoading(false);
+ };
+
return (
@@ -79,13 +98,20 @@ export function WalletSendPreviewView() {
To
-
+
@@ -95,7 +121,7 @@ export function WalletSendPreviewView() {
-
+
Cancel
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index 154e21f23..e87b933e7 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -25,9 +25,8 @@ import styles from './styles';
export function WalletSendView() {
const { padding } = useCustomDimensions();
const { keyboardShown, keyboardHeight } = useKeyboard();
- const { token, sendTokenAmount, receiverAddress, loading, gasPrice } = useSnapshot(
- SendController.state
- );
+ const { token, sendTokenAmount, receiverAddress, receiverProfileName, loading, gasPrice } =
+ useSnapshot(SendController.state);
const { tokenBalance } = useSnapshot(AccountController.state);
const paddingBottom = Platform.select({
@@ -110,7 +109,7 @@ export function WalletSendView() {
onTokenPress={() => RouterController.push('WalletSendSelectToken')}
/>
-
+
{
+ try {
+ if (!this.wagmiConfig) {
+ throw new Error(
+ 'networkControllerClient:getApprovedCaipNetworksData - wagmiConfig is undefined'
+ );
+ }
+ const chainId = Number(NetworkUtil.caipNetworkIdToNumber(this.getCaipNetwork()?.id));
+ let ensName: boolean | GetEnsAddressReturnType = false;
+ let wcName: boolean | string = false;
+ if (NamesUtil.isReownName(value)) {
+ wcName = (await this.resolveReownName(value)) || false;
+ }
+ if (chainId === 1) {
+ ensName = await wagmiGetEnsAddress(this.wagmiConfig, {
+ name: normalize(value),
+ chainId
+ });
+ }
+
+ return ensName || wcName || false;
+ } catch {
+ return false;
+ }
+ },
+ getEnsAvatar: async (value: string) => {
+ const chainId = Number(NetworkUtil.caipNetworkIdToNumber(this.getCaipNetwork()?.id));
+ if (chainId !== mainnet.id) {
+ return false;
+ }
+ const avatar = await wagmiGetEnsAvatar(this.wagmiConfig, {
+ name: normalize(value),
+ chainId
+ });
+
+ return avatar || false;
+ }
};
super({
From 79e46067b7613f71adb4c83e74bae51a6b6b094c Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 24 Sep 2024 16:01:44 -0300
Subject: [PATCH 055/114] chore: added refresh control to token and activity
list
---
.../src/controllers/TransactionsController.ts | 13 ++++++++--
.../partials/w3m-account-activity/index.tsx | 26 +++++++++++++++----
.../src/partials/w3m-account-tokens/index.tsx | 26 ++++++++++++++++---
3 files changed, 55 insertions(+), 10 deletions(-)
diff --git a/packages/core/src/controllers/TransactionsController.ts b/packages/core/src/controllers/TransactionsController.ts
index 9a8b44adb..599da1b91 100644
--- a/packages/core/src/controllers/TransactionsController.ts
+++ b/packages/core/src/controllers/TransactionsController.ts
@@ -33,7 +33,7 @@ export const TransactionsController = {
return sub(state, () => callback(state));
},
- async fetchTransactions(accountAddress?: string) {
+ async fetchTransactions(accountAddress?: string, reset?: boolean) {
const { projectId } = OptionsController.state;
if (!projectId || !accountAddress) {
@@ -42,6 +42,10 @@ export const TransactionsController = {
state.loading = true;
+ if (reset) {
+ state.next = undefined;
+ }
+
try {
const response = await BlockchainApiController.fetchTransactions({
account: accountAddress,
@@ -50,7 +54,12 @@ export const TransactionsController = {
});
const nonSpamTransactions = this.filterSpamTransactions(response?.data ?? []);
- const filteredTransactions = [...state.transactions, ...nonSpamTransactions];
+ let filteredTransactions = [...state.transactions, ...nonSpamTransactions];
+ filteredTransactions = [...state.transactions, ...nonSpamTransactions];
+
+ if (reset) {
+ filteredTransactions = nonSpamTransactions;
+ }
state.loading = false;
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index 8f5ee67a7..f2ee5cb8a 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -1,13 +1,14 @@
-import { useMemo } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { useSnapshot } from 'valtio';
-import { ScrollView, View, type StyleProp, type ViewStyle } from 'react-native';
+import { ScrollView, View, type StyleProp, type ViewStyle, RefreshControl } from 'react-native';
import {
FlexView,
Link,
ListTransaction,
LoadingSpinner,
Text,
- TransactionUtil
+ TransactionUtil,
+ useTheme
} from '@reown/appkit-ui-react-native';
import { type Transaction, type TransactionImage } from '@reown/appkit-common-react-native';
import {
@@ -27,6 +28,8 @@ interface Props {
}
export function AccountActivity({ style }: Props) {
+ const Theme = useTheme();
+ const [refreshing, setRefreshing] = useState(false);
const { loading, transactions, next } = useSnapshot(TransactionsController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
@@ -45,6 +48,12 @@ export function AccountActivity({ style }: Props) {
});
};
+ const onRefresh = useCallback(async () => {
+ setRefreshing(true);
+ await TransactionsController.fetchTransactions(AccountController.state.address, true);
+ setRefreshing(false);
+ }, []);
+
const transactionsByYear = useMemo(() => {
return TransactionsController.getTransactionsByYearAndMonth(transactions as Transaction[]);
}, [transactions]);
@@ -71,10 +80,17 @@ export function AccountActivity({ style }: Props) {
return (
+ }
>
{Object.keys(transactionsByYear)
.reverse()
@@ -137,7 +153,7 @@ export function AccountActivity({ style }: Props) {
Load more
)}
- {loading && }
+ {loading && !refreshing && }
)}
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index 46b222fb5..bbc8b7972 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,4 +1,5 @@
-import { ScrollView, type StyleProp, type ViewStyle } from 'react-native';
+import { useCallback, useState } from 'react';
+import { RefreshControl, ScrollView, type StyleProp, type ViewStyle } from 'react-native';
import { useSnapshot } from 'valtio';
import {
AccountController,
@@ -6,17 +7,25 @@ import {
NetworkController,
RouterController
} from '@reown/appkit-core-react-native';
-import { FlexView, ListItem, Text, ListToken } from '@reown/appkit-ui-react-native';
+import { FlexView, ListItem, Text, ListToken, useTheme } from '@reown/appkit-ui-react-native';
interface Props {
style?: StyleProp;
}
export function AccountTokens({ style }: Props) {
+ const Theme = useTheme();
+ const [refreshing, setRefreshing] = useState(false);
const { tokenBalance } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
+ const onRefresh = useCallback(async () => {
+ setRefreshing(true);
+ AccountController.fetchTokenBalance();
+ setRefreshing(false);
+ }, []);
+
const onReceivePress = () => {
RouterController.push('WalletReceive');
};
@@ -37,7 +46,18 @@ export function AccountTokens({ style }: Props) {
}
return (
-
+
+ }
+ >
{tokenBalance.map(token => (
Date: Tue, 24 Sep 2024 16:03:31 -0300
Subject: [PATCH 056/114] chore: avatar colors based on address
---
.../composites/AccountButton.stories.tsx | 9 +++----
.../src/modal/w3m-account-button/index.tsx | 4 +--
.../views/w3m-account-default-view/index.tsx | 2 +-
.../partials/w3m-connecting-siwe/index.tsx | 7 +-----
.../composites/wui-account-button/index.tsx | 25 +++++++++++++------
.../src/composites/wui-account-pill/index.tsx | 2 +-
6 files changed, 26 insertions(+), 23 deletions(-)
diff --git a/apps/gallery/stories/composites/AccountButton.stories.tsx b/apps/gallery/stories/composites/AccountButton.stories.tsx
index 807c542f3..d9d45f862 100644
--- a/apps/gallery/stories/composites/AccountButton.stories.tsx
+++ b/apps/gallery/stories/composites/AccountButton.stories.tsx
@@ -12,8 +12,8 @@ const meta: Meta = {
address: {
control: { type: 'text' }
},
- isProfileName: {
- control: { type: 'boolean' }
+ profileName: {
+ control: { type: 'text' }
},
networkSrc: {
control: { type: 'text' }
@@ -26,8 +26,7 @@ const meta: Meta = {
avatarSrc: avatarImageSrc,
address: '0xDBbD65026a07cFbFa1aa92744E4D69951686077d',
networkSrc: networkImageSrc,
- balance: '0.527 ETH',
- isProfileName: false
+ balance: '0.527 ETH'
}
};
@@ -41,7 +40,7 @@ export const Default: Story = {
address={args.address}
networkSrc={args.networkSrc}
balance={args.balance}
- isProfileName={args.isProfileName}
+ profileName={args.profileName}
/>
)
};
diff --git a/packages/scaffold/src/modal/w3m-account-button/index.tsx b/packages/scaffold/src/modal/w3m-account-button/index.tsx
index d6fe2907e..4f3186407 100644
--- a/packages/scaffold/src/modal/w3m-account-button/index.tsx
+++ b/packages/scaffold/src/modal/w3m-account-button/index.tsx
@@ -34,8 +34,8 @@ export function AccountButton({ balance, disabled, style, testID }: AccountButto
return (
-
+
{profileName
diff --git a/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx b/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx
index 27581c98f..3473feaac 100644
--- a/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx
+++ b/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx
@@ -106,12 +106,7 @@ export function ConnectingSiwe({ style }: Props) {
{walletIcon ? (
) : (
-
+
)}
diff --git a/packages/ui/src/composites/wui-account-button/index.tsx b/packages/ui/src/composites/wui-account-button/index.tsx
index f77410a2b..ccf9e4b99 100644
--- a/packages/ui/src/composites/wui-account-button/index.tsx
+++ b/packages/ui/src/composites/wui-account-button/index.tsx
@@ -15,7 +15,7 @@ export interface AccountButtonProps {
imageHeaders?: Record;
avatarSrc?: string;
address?: string;
- isProfileName?: boolean;
+ profileName?: string;
balance?: string;
onPress?: () => void;
disabled?: boolean;
@@ -28,7 +28,7 @@ export function AccountButton({
imageHeaders,
avatarSrc,
address,
- isProfileName,
+ profileName,
balance,
onPress,
disabled,
@@ -73,6 +73,20 @@ export function AccountButton({
return null;
}
+ const formattedAddress = profileName
+ ? UiUtil.getTruncateString({
+ string: profileName,
+ charsStart: 18,
+ charsEnd: 0,
+ truncate: 'end'
+ })
+ : UiUtil.getTruncateString({
+ string: address || '',
+ charsStart: 4,
+ charsEnd: 6,
+ truncate: 'middle'
+ });
+
return (
{address && (
- {UiUtil.getTruncateString({
- string: address,
- charsStart: isProfileName ? 18 : 4,
- charsEnd: isProfileName ? 0 : 6,
- truncate: isProfileName ? 'end' : 'middle'
- })}
+ {formattedAddress}
)}
diff --git a/packages/ui/src/composites/wui-account-pill/index.tsx b/packages/ui/src/composites/wui-account-pill/index.tsx
index 07f76d56e..9b7ebd886 100644
--- a/packages/ui/src/composites/wui-account-pill/index.tsx
+++ b/packages/ui/src/composites/wui-account-pill/index.tsx
@@ -50,7 +50,7 @@ export function AccountPill({
onPress={onPress}
hitSlop={10}
>
-
+
{profileName
? UiUtil.getTruncateString({
From f01db273695cbdf7176f5a628dca0a8ed2b2153e Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 09:54:41 -0300
Subject: [PATCH 057/114] chore: compacted erc20 and usdt abi, added more usdt
contract adddresses
---
packages/common/src/contracts/erc20.ts | 192 +-----------------
packages/common/src/contracts/usdt.ts | 151 +-------------
packages/common/src/utils/ConstantsUtil.ts | 17 +-
packages/common/src/utils/ContractUtil.ts | 11 +-
.../core/src/controllers/SendController.ts | 2 +-
5 files changed, 32 insertions(+), 341 deletions(-)
diff --git a/packages/common/src/contracts/erc20.ts b/packages/common/src/contracts/erc20.ts
index 8f735d820..cf48b5c1e 100644
--- a/packages/common/src/contracts/erc20.ts
+++ b/packages/common/src/contracts/erc20.ts
@@ -1,62 +1,9 @@
export const erc20ABI = [
{
- constant: true,
- inputs: [],
- name: 'name',
- outputs: [
- {
- name: '',
- type: 'string'
- }
- ],
- payable: false,
- stateMutability: 'view',
- type: 'function'
- },
- {
- constant: false,
- inputs: [
- {
- name: '_spender',
- type: 'address'
- },
- {
- name: '_value',
- type: 'uint256'
- }
- ],
- name: 'approve',
- outputs: [
- {
- name: '',
- type: 'bool'
- }
- ],
- payable: false,
+ type: 'function',
+ name: 'transfer',
stateMutability: 'nonpayable',
- type: 'function'
- },
- {
- constant: true,
- inputs: [],
- name: 'totalSupply',
- outputs: [
- {
- name: '',
- type: 'uint256'
- }
- ],
- payable: false,
- stateMutability: 'view',
- type: 'function'
- },
- {
- constant: false,
inputs: [
- {
- name: '_from',
- type: 'address'
- },
{
name: '_to',
type: 'address'
@@ -66,67 +13,22 @@ export const erc20ABI = [
type: 'uint256'
}
],
- name: 'transferFrom',
outputs: [
{
name: '',
type: 'bool'
}
- ],
- payable: false,
- stateMutability: 'nonpayable',
- type: 'function'
+ ]
},
{
- constant: true,
- inputs: [],
- name: 'decimals',
- outputs: [
- {
- name: '',
- type: 'uint8'
- }
- ],
- payable: false,
- stateMutability: 'view',
- type: 'function'
- },
- {
- constant: true,
+ type: 'function',
+ name: 'transferFrom',
+ stateMutability: 'nonpayable',
inputs: [
{
- name: '_owner',
+ name: '_from',
type: 'address'
- }
- ],
- name: 'balanceOf',
- outputs: [
- {
- name: 'balance',
- type: 'uint256'
- }
- ],
- payable: false,
- stateMutability: 'view',
- type: 'function'
- },
- {
- constant: true,
- inputs: [],
- name: 'symbol',
- outputs: [
- {
- name: '',
- type: 'string'
- }
- ],
- payable: false,
- stateMutability: 'view',
- type: 'function'
- },
- {
- constant: false,
- inputs: [
+ },
{
name: '_to',
type: 'address'
@@ -136,87 +38,11 @@ export const erc20ABI = [
type: 'uint256'
}
],
- name: 'transfer',
outputs: [
{
name: '',
type: 'bool'
}
- ],
- payable: false,
- stateMutability: 'nonpayable',
- type: 'function'
- },
- {
- constant: true,
- inputs: [
- {
- name: '_owner',
- type: 'address'
- },
- {
- name: '_spender',
- type: 'address'
- }
- ],
- name: 'allowance',
- outputs: [
- {
- name: '',
- type: 'uint256'
- }
- ],
- payable: false,
- stateMutability: 'view',
- type: 'function'
- },
- {
- payable: true,
- stateMutability: 'payable',
- type: 'fallback'
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- name: 'owner',
- type: 'address'
- },
- {
- indexed: true,
- name: 'spender',
- type: 'address'
- },
- {
- indexed: false,
- name: 'value',
- type: 'uint256'
- }
- ],
- name: 'Approval',
- type: 'event'
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- name: 'from',
- type: 'address'
- },
- {
- indexed: true,
- name: 'to',
- type: 'address'
- },
- {
- indexed: false,
- name: 'value',
- type: 'uint256'
- }
- ],
- name: 'Transfer',
- type: 'event'
+ ]
}
];
diff --git a/packages/common/src/contracts/usdt.ts b/packages/common/src/contracts/usdt.ts
index abfe5deae..8d2dbe957 100644
--- a/packages/common/src/contracts/usdt.ts
+++ b/packages/common/src/contracts/usdt.ts
@@ -1,153 +1,4 @@
export const usdtABI = [
- {
- type: 'event',
- name: 'Approval',
- inputs: [
- {
- indexed: true,
- name: 'owner',
- type: 'address'
- },
- {
- indexed: true,
- name: 'spender',
- type: 'address'
- },
- {
- indexed: false,
- name: 'value',
- type: 'uint256'
- }
- ]
- },
- {
- type: 'event',
- name: 'Transfer',
- inputs: [
- {
- indexed: true,
- name: 'from',
- type: 'address'
- },
- {
- indexed: true,
- name: 'to',
- type: 'address'
- },
- {
- indexed: false,
- name: 'value',
- type: 'uint256'
- }
- ]
- },
- {
- type: 'function',
- name: 'allowance',
- stateMutability: 'view',
- inputs: [
- {
- name: 'owner',
- type: 'address'
- },
- {
- name: 'spender',
- type: 'address'
- }
- ],
- outputs: [
- {
- name: '',
- type: 'uint256'
- }
- ]
- },
- {
- type: 'function',
- name: 'approve',
- stateMutability: 'nonpayable',
- inputs: [
- {
- name: 'spender',
- type: 'address'
- },
- {
- name: 'amount',
- type: 'uint256'
- }
- ],
- outputs: [
- {
- name: '',
- type: 'bool'
- }
- ]
- },
- {
- type: 'function',
- name: 'balanceOf',
- stateMutability: 'view',
- inputs: [
- {
- name: 'account',
- type: 'address'
- }
- ],
- outputs: [
- {
- name: '',
- type: 'uint256'
- }
- ]
- },
- {
- type: 'function',
- name: 'decimals',
- stateMutability: 'view',
- inputs: [],
- outputs: [
- {
- name: '',
- type: 'uint8'
- }
- ]
- },
- {
- type: 'function',
- name: 'name',
- stateMutability: 'view',
- inputs: [],
- outputs: [
- {
- name: '',
- type: 'string'
- }
- ]
- },
- {
- type: 'function',
- name: 'symbol',
- stateMutability: 'view',
- inputs: [],
- outputs: [
- {
- name: '',
- type: 'string'
- }
- ]
- },
- {
- type: 'function',
- name: 'totalSupply',
- stateMutability: 'view',
- inputs: [],
- outputs: [
- {
- name: '',
- type: 'uint256'
- }
- ]
- },
{
type: 'function',
name: 'transfer',
@@ -189,4 +40,4 @@ export const usdtABI = [
}
]
}
-] as const;
+];
diff --git a/packages/common/src/utils/ConstantsUtil.ts b/packages/common/src/utils/ConstantsUtil.ts
index bf2e03385..4d21f178c 100644
--- a/packages/common/src/utils/ConstantsUtil.ts
+++ b/packages/common/src/utils/ConstantsUtil.ts
@@ -6,5 +6,20 @@ export const ConstantsUtil = {
API_URL: 'https://api.web3modal.org',
COINBASE_CONNECTOR_ID: 'coinbaseWallet',
COINBASE_EXPLORER_ID: 'fd20dc426fb37566d803205b19bbc1d4096b248ac04548e3cfb6b3a38bd033aa',
- USDT_CONTRACT_ADDRESS: '0xdac17f958d2ee523a2206206994597c13d831ec7'
+ USDT_CONTRACT_ADDRESSES: [
+ // Mainnet
+ '0xdac17f958d2ee523a2206206994597c13d831ec7',
+ // Polygon
+ '0xc2132d05d31c914a87c6611c10748aeb04b58e8f',
+ // Avalanche
+ '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
+ // Cosmos
+ '0x919C1c267BC06a7039e03fcc2eF738525769109c',
+ // Celo
+ '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
+ // Binance
+ '0x55d398326f99059fF775485246999027B3197955',
+ // Arbitrum
+ '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9'
+ ]
};
diff --git a/packages/common/src/utils/ContractUtil.ts b/packages/common/src/utils/ContractUtil.ts
index 3af0e3214..d102267ea 100644
--- a/packages/common/src/utils/ContractUtil.ts
+++ b/packages/common/src/utils/ContractUtil.ts
@@ -3,12 +3,11 @@ import { usdtABI } from '../contracts/usdt';
import { ConstantsUtil } from './ConstantsUtil';
export const ContractUtil = {
- getABI: (tokenAddress: string) => {
- switch (tokenAddress) {
- case ConstantsUtil.USDT_CONTRACT_ADDRESS:
- return usdtABI;
- default:
- return erc20ABI;
+ getERC20Abi: (tokenAddress: string) => {
+ if (ConstantsUtil.USDT_CONTRACT_ADDRESSES.includes(tokenAddress)) {
+ return usdtABI;
}
+
+ return erc20ABI;
}
};
diff --git a/packages/core/src/controllers/SendController.ts b/packages/core/src/controllers/SendController.ts
index b4acf79b2..ab97b33ab 100644
--- a/packages/core/src/controllers/SendController.ts
+++ b/packages/core/src/controllers/SendController.ts
@@ -212,7 +212,7 @@ export const SendController = {
receiverAddress: params.receiverAddress as `0x${string}`,
tokenAmount: amount,
method: 'transfer',
- abi: ContractUtil.getABI(tokenAddress)
+ abi: ContractUtil.getERC20Abi(tokenAddress)
});
SnackController.showSuccess('Transaction started');
this.resetSend();
From c8acebbc763d41c335cf8329d18afefd86c4b943 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 09:55:21 -0300
Subject: [PATCH 058/114] chore: added ethers methods to resolve ens and write
contract
---
packages/ethers/src/client.ts | 36 ++++++++++++++++-
packages/ethers5/src/client.ts | 74 +++++++++++++++++++++++-----------
2 files changed, 85 insertions(+), 25 deletions(-)
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 2fdf57284..284585ba2 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -26,7 +26,7 @@ import {
AppKitScaffold,
type WriteContractArgs
} from '@reown/appkit-scaffold-react-native';
-import { NetworkUtil } from '@reown/appkit-common-react-native';
+import { NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import {
ConstantsUtil,
PresetsUtil,
@@ -343,6 +343,40 @@ export class AppKit extends AppKitScaffold {
}
throw new Error('Contract method is undefined');
+ },
+
+ getEnsAddress: async (value: string) => {
+ try {
+ const chainId = Number(this.getCaipNetwork()?.id);
+ let ensName: string | null = null;
+ let wcName: boolean | string = false;
+
+ if (NamesUtil.isReownName(value)) {
+ wcName = (await this?.resolveReownName(value)) || false;
+ }
+
+ // If on mainnet, fetch from ENS
+ if (chainId === 1) {
+ const ensProvider = new InfuraProvider('mainnet');
+ ensName = await ensProvider.resolveName(value);
+ }
+
+ return ensName || wcName || false;
+ } catch {
+ return false;
+ }
+ },
+
+ getEnsAvatar: async (value: string) => {
+ const chainId = Number(NetworkUtil.caipNetworkIdToNumber(this.getCaipNetwork()?.id));
+ if (chainId === 1) {
+ const ensProvider = new InfuraProvider('mainnet');
+ const avatar = await ensProvider.getAvatar(value);
+
+ return avatar || false;
+ }
+
+ return false;
}
};
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index 6057128b0..2b0af1c3b 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -1,4 +1,4 @@
-import { ethers, utils } from 'ethers';
+import { Contract, ethers, utils } from 'ethers';
import {
type CaipAddress,
type CaipNetwork,
@@ -10,6 +10,7 @@ import {
type PublicStateControllerState,
type SendTransactionArgs,
type Token,
+ type WriteContractArgs,
AppKitScaffold
} from '@reown/appkit-scaffold-react-native';
import {
@@ -29,7 +30,7 @@ import {
type CombinedProviderType,
type AppKitFrameProvider
} from '@reown/appkit-scaffold-utils-react-native';
-import { NetworkUtil } from '@reown/appkit-common-react-native';
+import { NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import EthereumProvider, { OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
import type { EthereumProviderOptions } from '@walletconnect/ethereum-provider';
@@ -304,36 +305,61 @@ export class AppKit extends AppKitScaffold {
const txReceipt = await txResponse.wait();
return (txReceipt?.blockHash as `0x${string}`) || null;
- }
+ },
- // writeContract: async (data: WriteContractArgs) => {
- // const { chainId, provider, address } = EthersStoreUtil.state;
+ writeContract: async (data: WriteContractArgs) => {
+ const { chainId, provider, address } = EthersStoreUtil.state;
+ if (!provider) {
+ throw new Error('writeContract - provider is undefined');
+ }
+ if (!address) {
+ throw new Error('writeContract - address is undefined');
+ }
+ const browserProvider = new ethers.providers.Web3Provider(provider, chainId);
+ const signer = browserProvider.getSigner(address);
+ const contract = new Contract(data.tokenAddress, data.abi, signer);
+ if (!contract || !data.method) {
+ throw new Error('Contract method is undefined');
+ }
+ const method = contract[data.method];
+ if (method) {
+ return await method(data.receiverAddress, data.tokenAmount);
+ }
+ throw new Error('Contract method is undefined');
+ },
- // if (!provider) {
- // throw new Error('ethersClient:writeContract - provider is undefined');
- // }
+ getEnsAddress: async (value: string) => {
+ try {
+ const { chainId } = EthersStoreUtil.state;
+ let ensName: string | null = null;
+ let wcName: boolean | string = false;
- // if (!address) {
- // throw new Error('ethersClient:writeContract - address is undefined');
- // }
+ if (NamesUtil.isReownName(value)) {
+ wcName = (await this.resolveReownName(value)) || false;
+ }
- // const browserProvider = new BrowserProvider(provider, chainId);
- // const signer = new JsonRpcSigner(browserProvider, address);
- // const contract = new Contract(data.tokenAddress, data.abi, signer);
+ if (chainId === 1) {
+ const ensProvider = new ethers.providers.InfuraProvider('mainnet');
+ ensName = await ensProvider.resolveName(value);
+ }
- // if (!contract || !data.method) {
- // throw new Error('Contract method is undefined');
- // }
+ return ensName || wcName || false;
+ } catch {
+ return false;
+ }
+ },
- // const method = contract[data.method];
- // if (method) {
- // const tx = await method(data.receiverAddress, data.tokenAmount);
+ getEnsAvatar: async (value: string) => {
+ const { chainId } = EthersStoreUtil.state;
+ if (chainId === 1) {
+ const ensProvider = new ethers.providers.InfuraProvider('mainnet');
+ const avatar = await ensProvider.getAvatar(value);
- // return tx;
- // }
+ return avatar || false;
+ }
- // throw new Error('Contract method is undefined');
- // }
+ return false;
+ }
};
super({
From 656572ca5866d16eb470aba7cc8477ffb7ea572b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 25 Sep 2024 12:58:17 +0000
Subject: [PATCH 059/114] chore(deps): bump braces from 3.0.2 to 3.0.3
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)
---
updated-dependencies:
- dependency-name: braces
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
yarn.lock | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 5db5017ce..1a91f5f47 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11025,7 +11025,7 @@ __metadata:
languageName: node
linkType: hard
-"braces@npm:^3.0.3":
+"braces@npm:^3.0.3, braces@npm:~3.0.2":
version: 3.0.3
resolution: "braces@npm:3.0.3"
dependencies:
@@ -11034,15 +11034,6 @@ __metadata:
languageName: node
linkType: hard
-"braces@npm:~3.0.2":
- version: 3.0.2
- resolution: "braces@npm:3.0.2"
- dependencies:
- fill-range: "npm:^7.0.1"
- checksum: 321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381
- languageName: node
- linkType: hard
-
"brorand@npm:^1.1.0":
version: 1.1.0
resolution: "brorand@npm:1.1.0"
@@ -14237,15 +14228,6 @@ __metadata:
languageName: node
linkType: hard
-"fill-range@npm:^7.0.1":
- version: 7.0.1
- resolution: "fill-range@npm:7.0.1"
- dependencies:
- to-regex-range: "npm:^5.0.1"
- checksum: 7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f
- languageName: node
- linkType: hard
-
"fill-range@npm:^7.1.1":
version: 7.1.1
resolution: "fill-range@npm:7.1.1"
From d522dcb675dc7d072cf3aec31919afa914a688a2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 25 Sep 2024 12:58:19 +0000
Subject: [PATCH 060/114] chore(deps): bump fast-loops from 1.1.3 to 1.1.4
Bumps [fast-loops](https://github.com/robinweser/fast-loops) from 1.1.3 to 1.1.4.
- [Commits](https://github.com/robinweser/fast-loops/commits)
---
updated-dependencies:
- dependency-name: fast-loops
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
yarn.lock | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 5db5017ce..37d8e0020 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14127,9 +14127,9 @@ __metadata:
linkType: hard
"fast-loops@npm:^1.1.3":
- version: 1.1.3
- resolution: "fast-loops@npm:1.1.3"
- checksum: ba71c001704c44a617053ed34b1a8c0d2ed9723022eb7b93c98299d9862f93213609b32c9daec7d606625ab318769d11da8bb06e9ddd9c28e3bda1249fb6e36d
+ version: 1.1.4
+ resolution: "fast-loops@npm:1.1.4"
+ checksum: 25e8a608fccc0d84c1d037efa715ab1e6f21576e1070931b3ed966657204c47ed2b1cba16e5c46ddde2d62aba0b4100d86616d995318b7367fa0a902a78ed885
languageName: node
linkType: hard
From d56f2fd04454a7cf93cf6eddca0949a91a3bc10d Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 10:16:14 -0300
Subject: [PATCH 061/114] chore: test fix
---
.../controllers/RouterController.test.ts | 24 ++++++++++++-------
.../partials/w3m-connecting-siwe/index.tsx | 2 +-
2 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/packages/core/src/__tests__/controllers/RouterController.test.ts b/packages/core/src/__tests__/controllers/RouterController.test.ts
index c6a1c09dd..8e5d56f1f 100644
--- a/packages/core/src/__tests__/controllers/RouterController.test.ts
+++ b/packages/core/src/__tests__/controllers/RouterController.test.ts
@@ -5,7 +5,8 @@ describe('RouterController', () => {
it('should have valid default state', () => {
expect(RouterController.state).toEqual({
view: 'Connect',
- history: ['Connect']
+ history: ['Connect'],
+ transactionStack: []
});
});
@@ -13,7 +14,8 @@ describe('RouterController', () => {
RouterController.push('Account');
expect(RouterController.state).toEqual({
view: 'Account',
- history: ['Connect', 'Account']
+ history: ['Connect', 'Account'],
+ transactionStack: []
});
});
@@ -21,7 +23,8 @@ describe('RouterController', () => {
RouterController.push('Account');
expect(RouterController.state).toEqual({
view: 'Account',
- history: ['Connect', 'Account']
+ history: ['Connect', 'Account'],
+ transactionStack: []
});
});
@@ -29,7 +32,8 @@ describe('RouterController', () => {
RouterController.goBack();
expect(RouterController.state).toEqual({
view: 'Connect',
- history: ['Connect']
+ history: ['Connect'],
+ transactionStack: []
});
});
@@ -37,7 +41,8 @@ describe('RouterController', () => {
RouterController.goBack();
expect(RouterController.state).toEqual({
view: 'Connect',
- history: ['Connect']
+ history: ['Connect'],
+ transactionStack: []
});
});
@@ -45,7 +50,8 @@ describe('RouterController', () => {
RouterController.reset('Account');
expect(RouterController.state).toEqual({
view: 'Account',
- history: ['Account']
+ history: ['Account'],
+ transactionStack: []
});
});
@@ -54,7 +60,8 @@ describe('RouterController', () => {
RouterController.replace('Networks');
expect(RouterController.state).toEqual({
view: 'Networks',
- history: ['Account', 'Networks']
+ history: ['Account', 'Networks'],
+ transactionStack: []
});
});
@@ -67,7 +74,8 @@ describe('RouterController', () => {
history: ['Account', 'Networks', 'ConnectingWalletConnect'],
data: {
wallet: { id: 'test', name: 'TestWallet' }
- }
+ },
+ transactionStack: []
});
});
});
diff --git a/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx b/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx
index 3473feaac..f53f5fcff 100644
--- a/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx
+++ b/packages/siwe/src/scaffold/partials/w3m-connecting-siwe/index.tsx
@@ -25,7 +25,7 @@ export function ConnectingSiwe({ style }: Props) {
const Theme = useTheme();
const { metadata } = useSnapshot(OptionsController.state);
const { connectedWalletImageUrl, pressedWallet } = useSnapshot(ConnectionController.state);
- const { address, profileName, profileImage } = useSnapshot(AccountController.state);
+ const { address, profileImage } = useSnapshot(AccountController.state);
const dappIcon = metadata?.icons[0] || '';
const dappPosition = useAnimatedValue(10);
const walletPosition = useAnimatedValue(-10);
From 07f5829d93fc923e63198cc00809c3bda4ce22f0 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 10:19:06 -0300
Subject: [PATCH 062/114] chore: snapshot action change
---
.github/workflows/snapshot.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml
index 110c2f250..b8d1ab43e 100644
--- a/.github/workflows/snapshot.yml
+++ b/.github/workflows/snapshot.yml
@@ -20,7 +20,7 @@ jobs:
uses: ./.github/actions/setup
- name: Publish Snapshots
- continue-on-error: true
+ continue-on-error: false
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
From 0a819476618a38160436d14ed7a69a6adbffadca Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 10:56:33 -0300
Subject: [PATCH 063/114] chore: small ui change
---
.../components/preview-send-details.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
index 5acc900e7..e7d75bfb6 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
@@ -61,7 +61,7 @@ export function PreviewSendDetails({
- {formattedName ?? 'Address'}
+ {formattedName || 'Address'}
{formattedAddress}
From b02a7d39f4c23802dd4619671fe263a2faa17775 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 11:02:09 -0300
Subject: [PATCH 064/114] chore: changeset file
---
.changeset/old-beers-agree.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 .changeset/old-beers-agree.md
diff --git a/.changeset/old-beers-agree.md b/.changeset/old-beers-agree.md
new file mode 100644
index 000000000..4c944e903
--- /dev/null
+++ b/.changeset/old-beers-agree.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': minor
+'@reown/appkit-coinbase-wagmi-react-native': minor
+'@reown/appkit-scaffold-utils-react-native': minor
+'@reown/appkit-auth-ethers-react-native': minor
+'@reown/appkit-auth-wagmi-react-native': minor
+'@reown/appkit-scaffold-react-native': minor
+'@reown/appkit-ethers5-react-native': minor
+'@reown/appkit-common-react-native': minor
+'@reown/appkit-ethers-react-native': minor
+'@reown/appkit-wallet-react-native': minor
+'@reown/appkit-wagmi-react-native': minor
+'@reown/appkit-core-react-native': minor
+'@reown/appkit-siwe-react-native': minor
+'@reown/appkit-ui-react-native': minor
+---
+
+feat: added wallet features for universal wallets
From f81884ac7386f8069ab22225141384be8e11e248 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 11:20:26 -0300
Subject: [PATCH 065/114] chore: code style
---
.../src/controllers/TransactionsController.ts | 1 -
.../scaffold/src/hooks/useDebounceCallback.ts | 2 +-
.../components/preview-send-details.tsx | 2 +-
.../w3m-wallet-send-preview-view/index.tsx | 2 +-
.../src/views/w3m-wallet-send-view/index.tsx | 2 +-
.../ui/src/composites/wui-button/index.tsx | 24 +++++++++----------
packages/wallet/src/AppKitAuthWebview.tsx | 8 +++----
7 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/packages/core/src/controllers/TransactionsController.ts b/packages/core/src/controllers/TransactionsController.ts
index 599da1b91..af350299f 100644
--- a/packages/core/src/controllers/TransactionsController.ts
+++ b/packages/core/src/controllers/TransactionsController.ts
@@ -55,7 +55,6 @@ export const TransactionsController = {
const nonSpamTransactions = this.filterSpamTransactions(response?.data ?? []);
let filteredTransactions = [...state.transactions, ...nonSpamTransactions];
- filteredTransactions = [...state.transactions, ...nonSpamTransactions];
if (reset) {
filteredTransactions = nonSpamTransactions;
diff --git a/packages/scaffold/src/hooks/useDebounceCallback.ts b/packages/scaffold/src/hooks/useDebounceCallback.ts
index 8708750c1..70be71f31 100644
--- a/packages/scaffold/src/hooks/useDebounceCallback.ts
+++ b/packages/scaffold/src/hooks/useDebounceCallback.ts
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useRef } from 'react';
interface Props {
- callback: (args: any) => void;
+ callback: ((args: any) => any) | ((args: any) => Promise);
delay?: number;
}
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
index e7d75bfb6..d71df1740 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-details.tsx
@@ -35,7 +35,7 @@ export function PreviewSendDetails({
});
const formattedAddress = UiUtil.getTruncateString({
- string: address ? address : '',
+ string: address || '',
charsStart: 6,
charsEnd: 8,
truncate: 'middle'
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
index bb907f59a..8b9e7f41a 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/index.tsx
@@ -51,7 +51,7 @@ export function WalletSendPreviewView() {
truncate: 'end'
})
: UiUtil.getTruncateString({
- string: receiverAddress ? receiverAddress : '',
+ string: receiverAddress || '',
charsStart: 4,
charsEnd: 4,
truncate: 'middle'
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index e87b933e7..8be4dd217 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -109,7 +109,7 @@ export function WalletSendView() {
onTokenPress={() => RouterController.push('WalletSendSelectToken')}
/>
-
+
)}
- {loading ? (
-
- ) : typeof children === 'string' ? (
-
- {children}
-
- ) : (
- children
- )}
+ {loading && }
+ {!loading &&
+ (typeof children === 'string' ? (
+
+ {children}
+
+ ) : (
+ children
+ ))}
{iconRight && (
{
if (AppKitFrameHelpers.checkIfRequestExists(request)) {
if (!AppKitFrameHelpers.checkIfRequestIsAllowed(request)) {
- setIsWebviewOpen(true);
+ setIsWebviewVisible(true);
}
}
});
@@ -71,7 +71,7 @@ export function AuthWebview() {
} else {
RouterController?.popTransactionStack();
}
- setIsWebviewOpen(false);
+ setIsWebviewVisible(false);
});
provider.onRpcError(() => {
@@ -82,7 +82,7 @@ export function AuthWebview() {
RouterController?.popTransactionStack(true);
}
}
- setIsWebviewOpen(false);
+ setIsWebviewVisible(false);
});
provider.onIsConnected(event, () => {
From 48486f048b2d1bec40397c9bfcbda5224d67a79c Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 11:32:14 -0300
Subject: [PATCH 066/114] chore: added sendcontroller test
---
.../controllers/SendController.test.ts | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 packages/core/src/__tests__/controllers/SendController.test.ts
diff --git a/packages/core/src/__tests__/controllers/SendController.test.ts b/packages/core/src/__tests__/controllers/SendController.test.ts
new file mode 100644
index 000000000..4048144a1
--- /dev/null
+++ b/packages/core/src/__tests__/controllers/SendController.test.ts
@@ -0,0 +1,57 @@
+import { SendController } from '../../index';
+
+// -- Setup --------------------------------------------------------------------
+const token = {
+ name: 'Optimism',
+ address: 'eip155:10:0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
+ symbol: 'OP',
+ chainId: 'eip155:10',
+ value: 6.05441523113072,
+ price: 4.5340112,
+ quantity: {
+ decimals: '18',
+ numeric: '1.335333100000000000'
+ },
+ iconUrl: 'https://token-icons.s3.amazonaws.com/0x4200000000000000000000000000000000000042.png'
+};
+const sendTokenAmount = 0.1;
+const receiverAddress = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045';
+const receiverProfileName = 'john.eth';
+const receiverProfileImageUrl = 'https://ipfs.com/0x123.png';
+
+// -- Tests --------------------------------------------------------------------
+describe('SendController', () => {
+ it('should have valid default state', () => {
+ expect(SendController.state).toEqual({ loading: false });
+ });
+
+ it('should update state correctly on setToken()', () => {
+ SendController.setToken(token);
+ expect(SendController.state.token).toEqual(token);
+ });
+
+ it('should update state correctly on setTokenAmount()', () => {
+ SendController.setTokenAmount(sendTokenAmount);
+ expect(SendController.state.sendTokenAmount).toEqual(sendTokenAmount);
+ });
+
+ it('should update state correctly on receiverAddress()', () => {
+ SendController.setReceiverAddress(receiverAddress);
+ expect(SendController.state.receiverAddress).toEqual(receiverAddress);
+ });
+
+ it('should update state correctly on receiverProfileName()', () => {
+ SendController.setReceiverProfileName(receiverProfileName);
+ expect(SendController.state.receiverProfileName).toEqual(receiverProfileName);
+ });
+
+ it('should update state correctly on setReceiverProfileImageUrl()', () => {
+ SendController.setReceiverProfileImageUrl(receiverProfileImageUrl);
+ expect(SendController.state.receiverProfileImageUrl).toEqual(receiverProfileImageUrl);
+ });
+
+ it('should update state correctly on resetSend()', () => {
+ SendController.resetSend();
+ expect(SendController.state).toEqual({ loading: false });
+ });
+});
From d362037bca84c8c76278a44dcdff80e8d6507e16 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 25 Sep 2024 14:38:18 +0000
Subject: [PATCH 067/114] chore(deps): bump tar from 6.1.15 to 6.2.1
Bumps [tar](https://github.com/isaacs/node-tar) from 6.1.15 to 6.2.1.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v6.1.15...v6.2.1)
---
updated-dependencies:
- dependency-name: tar
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
yarn.lock | 22 ++++------------------
1 file changed, 4 insertions(+), 18 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index e2e5d86c9..36f60a489 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -21536,23 +21536,9 @@ __metadata:
languageName: node
linkType: hard
-"tar@npm:^6.0.5":
- version: 6.1.15
- resolution: "tar@npm:6.1.15"
- dependencies:
- chownr: "npm:^2.0.0"
- fs-minipass: "npm:^2.0.0"
- minipass: "npm:^5.0.0"
- minizlib: "npm:^2.1.1"
- mkdirp: "npm:^1.0.3"
- yallist: "npm:^4.0.0"
- checksum: bb2babe7b14442f690d83c2b2c571c9dd0bf802314773e05f4a3e4a241fdecd7fb560b8e4e7d6ea34533c8cd692e1b8418a3b8ba3b9687fe78a683dfbad7f82d
- languageName: node
- linkType: hard
-
-"tar@npm:^6.1.11, tar@npm:^6.1.2":
- version: 6.2.0
- resolution: "tar@npm:6.2.0"
+"tar@npm:^6.0.5, tar@npm:^6.1.11, tar@npm:^6.1.2":
+ version: 6.2.1
+ resolution: "tar@npm:6.2.1"
dependencies:
chownr: "npm:^2.0.0"
fs-minipass: "npm:^2.0.0"
@@ -21560,7 +21546,7 @@ __metadata:
minizlib: "npm:^2.1.1"
mkdirp: "npm:^1.0.3"
yallist: "npm:^4.0.0"
- checksum: 02ca064a1a6b4521fef88c07d389ac0936730091f8c02d30ea60d472e0378768e870769ab9e986d87807bfee5654359cf29ff4372746cc65e30cbddc352660d8
+ checksum: a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537
languageName: node
linkType: hard
From 69c850cc17011c07e95f773ad3b598f9ad1a4d29 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 25 Sep 2024 14:38:19 +0000
Subject: [PATCH 068/114] chore(deps): bump webpack from 5.88.2 to 5.95.0
Bumps [webpack](https://github.com/webpack/webpack) from 5.88.2 to 5.95.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.88.2...v5.95.0)
---
updated-dependencies:
- dependency-name: webpack
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
---
yarn.lock | 287 ++++++++++++++++++++++++++++++++----------------------
1 file changed, 172 insertions(+), 115 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index e2e5d86c9..6538209b1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5186,7 +5186,7 @@ __metadata:
languageName: node
linkType: hard
-"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25":
+"@jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25":
version: 0.3.25
resolution: "@jridgewell/trace-mapping@npm:0.3.25"
dependencies:
@@ -8080,37 +8080,24 @@ __metadata:
languageName: node
linkType: hard
-"@types/eslint-scope@npm:^3.7.3":
- version: 3.7.4
- resolution: "@types/eslint-scope@npm:3.7.4"
- dependencies:
- "@types/eslint": "npm:*"
- "@types/estree": "npm:*"
- checksum: f8a19cddf9d402f079bcc261958fff5ff2616465e4fb4cd423aa966a6a32bf5d3c65ca3ca0fbe824776b48c5cd525efbaf927b98b8eeef093aa68a1a2ba19359
- languageName: node
- linkType: hard
-
-"@types/eslint@npm:*":
- version: 8.44.2
- resolution: "@types/eslint@npm:8.44.2"
- dependencies:
- "@types/estree": "npm:*"
- "@types/json-schema": "npm:*"
- checksum: 3c402215f7f495f9267a51fecd6a6d056eb8b3b031a1c472286b7d23a397257327eb03712befa7da60614dd63d31235d27dbc5c586b6a408798dafb8ee0c5eb2
+"@types/estree@npm:^0.0.51":
+ version: 0.0.51
+ resolution: "@types/estree@npm:0.0.51"
+ checksum: a70c60d5e634e752fcd45b58c9c046ef22ad59ede4bc93ad5193c7e3b736ebd6bcd788ade59d9c3b7da6eeb0939235f011d4c59bb4fc04d8c346b76035099dd1
languageName: node
linkType: hard
-"@types/estree@npm:*, @types/estree@npm:^1.0.0":
+"@types/estree@npm:^1.0.0":
version: 1.0.1
resolution: "@types/estree@npm:1.0.1"
checksum: b4022067f834d86766f23074a1a7ac6c460e823b00cd8fe94c997bc491e7794615facd3e1520a934c42bd8c0689dbff81e5c643b01f1dee143fc758cac19669e
languageName: node
linkType: hard
-"@types/estree@npm:^0.0.51":
- version: 0.0.51
- resolution: "@types/estree@npm:0.0.51"
- checksum: a70c60d5e634e752fcd45b58c9c046ef22ad59ede4bc93ad5193c7e3b736ebd6bcd788ade59d9c3b7da6eeb0939235f011d4c59bb4fc04d8c346b76035099dd1
+"@types/estree@npm:^1.0.5":
+ version: 1.0.6
+ resolution: "@types/estree@npm:1.0.6"
+ checksum: cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a
languageName: node
linkType: hard
@@ -8205,7 +8192,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9":
+"@types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9":
version: 7.0.12
resolution: "@types/json-schema@npm:7.0.12"
checksum: 2c39946ae321fe42d085c61a85872a81bbee70f9b2054ad344e8811dfc478fdbaf1ebf5f2989bb87c895ba2dfc3b1dcba85db11e467bbcdc023708814207791c
@@ -9187,13 +9174,13 @@ __metadata:
languageName: node
linkType: hard
-"@webassemblyjs/ast@npm:1.11.6, @webassemblyjs/ast@npm:^1.11.5":
- version: 1.11.6
- resolution: "@webassemblyjs/ast@npm:1.11.6"
+"@webassemblyjs/ast@npm:1.12.1, @webassemblyjs/ast@npm:^1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/ast@npm:1.12.1"
dependencies:
"@webassemblyjs/helper-numbers": "npm:1.11.6"
"@webassemblyjs/helper-wasm-bytecode": "npm:1.11.6"
- checksum: e28476a183c8a1787adcf0e5df1d36ec4589467ab712c674fe4f6769c7fb19d1217bfb5856b3edd0f3e0a148ebae9e4bbb84110cee96664966dfef204d9c31fb
+ checksum: ba7f2b96c6e67e249df6156d02c69eb5f1bd18d5005303cdc42accb053bebbbde673826e54db0437c9748e97abd218366a1d13fa46859b23cde611b6b409998c
languageName: node
linkType: hard
@@ -9211,10 +9198,10 @@ __metadata:
languageName: node
linkType: hard
-"@webassemblyjs/helper-buffer@npm:1.11.6":
- version: 1.11.6
- resolution: "@webassemblyjs/helper-buffer@npm:1.11.6"
- checksum: 55b5d67db95369cdb2a505ae7ebdf47194d49dfc1aecb0f5403277dcc899c7d3e1f07e8d279646adf8eafd89959272db62ca66fbe803321661ab184176ddfd3a
+"@webassemblyjs/helper-buffer@npm:1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/helper-buffer@npm:1.12.1"
+ checksum: 0270724afb4601237410f7fd845ab58ccda1d5456a8783aadfb16eaaf3f2c9610c28e4a5bcb6ad880cde5183c82f7f116d5ccfc2310502439d33f14b6888b48a
languageName: node
linkType: hard
@@ -9236,15 +9223,15 @@ __metadata:
languageName: node
linkType: hard
-"@webassemblyjs/helper-wasm-section@npm:1.11.6":
- version: 1.11.6
- resolution: "@webassemblyjs/helper-wasm-section@npm:1.11.6"
+"@webassemblyjs/helper-wasm-section@npm:1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/helper-wasm-section@npm:1.12.1"
dependencies:
- "@webassemblyjs/ast": "npm:1.11.6"
- "@webassemblyjs/helper-buffer": "npm:1.11.6"
+ "@webassemblyjs/ast": "npm:1.12.1"
+ "@webassemblyjs/helper-buffer": "npm:1.12.1"
"@webassemblyjs/helper-wasm-bytecode": "npm:1.11.6"
- "@webassemblyjs/wasm-gen": "npm:1.11.6"
- checksum: b79b19a63181f32e5ee0e786fa8264535ea5360276033911fae597d2de15e1776f028091d08c5a813a3901fd2228e74cd8c7e958fded064df734f00546bef8ce
+ "@webassemblyjs/wasm-gen": "npm:1.12.1"
+ checksum: 0546350724d285ae3c26e6fc444be4c3b5fb824f3be0ec8ceb474179dc3f4430336dd2e36a44b3e3a1a6815960e5eec98cd9b3a8ec66dc53d86daedd3296a6a2
languageName: node
linkType: hard
@@ -9273,68 +9260,68 @@ __metadata:
languageName: node
linkType: hard
-"@webassemblyjs/wasm-edit@npm:^1.11.5":
- version: 1.11.6
- resolution: "@webassemblyjs/wasm-edit@npm:1.11.6"
+"@webassemblyjs/wasm-edit@npm:^1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/wasm-edit@npm:1.12.1"
dependencies:
- "@webassemblyjs/ast": "npm:1.11.6"
- "@webassemblyjs/helper-buffer": "npm:1.11.6"
+ "@webassemblyjs/ast": "npm:1.12.1"
+ "@webassemblyjs/helper-buffer": "npm:1.12.1"
"@webassemblyjs/helper-wasm-bytecode": "npm:1.11.6"
- "@webassemblyjs/helper-wasm-section": "npm:1.11.6"
- "@webassemblyjs/wasm-gen": "npm:1.11.6"
- "@webassemblyjs/wasm-opt": "npm:1.11.6"
- "@webassemblyjs/wasm-parser": "npm:1.11.6"
- "@webassemblyjs/wast-printer": "npm:1.11.6"
- checksum: 9a56b6bf635cf7aa5d6e926eaddf44c12fba050170e452a8e17ab4e1b937708678c03f5817120fb9de1e27167667ce693d16ce718d41e5a16393996a6017ab73
+ "@webassemblyjs/helper-wasm-section": "npm:1.12.1"
+ "@webassemblyjs/wasm-gen": "npm:1.12.1"
+ "@webassemblyjs/wasm-opt": "npm:1.12.1"
+ "@webassemblyjs/wasm-parser": "npm:1.12.1"
+ "@webassemblyjs/wast-printer": "npm:1.12.1"
+ checksum: 972f5e6c522890743999e0ed45260aae728098801c6128856b310dd21f1ee63435fc7b518e30e0ba1cdafd0d1e38275829c1e4451c3536a1d9e726e07a5bba0b
languageName: node
linkType: hard
-"@webassemblyjs/wasm-gen@npm:1.11.6":
- version: 1.11.6
- resolution: "@webassemblyjs/wasm-gen@npm:1.11.6"
+"@webassemblyjs/wasm-gen@npm:1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/wasm-gen@npm:1.12.1"
dependencies:
- "@webassemblyjs/ast": "npm:1.11.6"
+ "@webassemblyjs/ast": "npm:1.12.1"
"@webassemblyjs/helper-wasm-bytecode": "npm:1.11.6"
"@webassemblyjs/ieee754": "npm:1.11.6"
"@webassemblyjs/leb128": "npm:1.11.6"
"@webassemblyjs/utf8": "npm:1.11.6"
- checksum: ce9a39d3dab2eb4a5df991bc9f3609960daa4671d25d700f4617152f9f79da768547359f817bee10cd88532c3e0a8a1714d383438e0a54217eba53cb822bd5ad
+ checksum: 1e257288177af9fa34c69cab94f4d9036ebed611f77f3897c988874e75182eeeec759c79b89a7a49dd24624fc2d3d48d5580b62b67c4a1c9bfbdcd266b281c16
languageName: node
linkType: hard
-"@webassemblyjs/wasm-opt@npm:1.11.6":
- version: 1.11.6
- resolution: "@webassemblyjs/wasm-opt@npm:1.11.6"
+"@webassemblyjs/wasm-opt@npm:1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/wasm-opt@npm:1.12.1"
dependencies:
- "@webassemblyjs/ast": "npm:1.11.6"
- "@webassemblyjs/helper-buffer": "npm:1.11.6"
- "@webassemblyjs/wasm-gen": "npm:1.11.6"
- "@webassemblyjs/wasm-parser": "npm:1.11.6"
- checksum: 82788408054171688e9f12883b693777219366d6867003e34dccc21b4a0950ef53edc9d2b4d54cabdb6ee869cf37c8718401b4baa4f70a7f7dd3867c75637298
+ "@webassemblyjs/ast": "npm:1.12.1"
+ "@webassemblyjs/helper-buffer": "npm:1.12.1"
+ "@webassemblyjs/wasm-gen": "npm:1.12.1"
+ "@webassemblyjs/wasm-parser": "npm:1.12.1"
+ checksum: 992a45e1f1871033c36987459436ab4e6430642ca49328e6e32a13de9106fe69ae6c0ac27d7050efd76851e502d11cd1ac0e06b55655dfa889ad82f11a2712fb
languageName: node
linkType: hard
-"@webassemblyjs/wasm-parser@npm:1.11.6, @webassemblyjs/wasm-parser@npm:^1.11.5":
- version: 1.11.6
- resolution: "@webassemblyjs/wasm-parser@npm:1.11.6"
+"@webassemblyjs/wasm-parser@npm:1.12.1, @webassemblyjs/wasm-parser@npm:^1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/wasm-parser@npm:1.12.1"
dependencies:
- "@webassemblyjs/ast": "npm:1.11.6"
+ "@webassemblyjs/ast": "npm:1.12.1"
"@webassemblyjs/helper-api-error": "npm:1.11.6"
"@webassemblyjs/helper-wasm-bytecode": "npm:1.11.6"
"@webassemblyjs/ieee754": "npm:1.11.6"
"@webassemblyjs/leb128": "npm:1.11.6"
"@webassemblyjs/utf8": "npm:1.11.6"
- checksum: 7a97a5f34f98bdcfd812157845a06d53f3d3f67dbd4ae5d6bf66e234e17dc4a76b2b5e74e5dd70b4cab9778fc130194d50bbd6f9a1d23e15ed1ed666233d6f5f
+ checksum: e85cec1acad07e5eb65b92d37c8e6ca09c6ca50d7ca58803a1532b452c7321050a0328c49810c337cc2dfd100c5326a54d5ebd1aa5c339ebe6ef10c250323a0e
languageName: node
linkType: hard
-"@webassemblyjs/wast-printer@npm:1.11.6":
- version: 1.11.6
- resolution: "@webassemblyjs/wast-printer@npm:1.11.6"
+"@webassemblyjs/wast-printer@npm:1.12.1":
+ version: 1.12.1
+ resolution: "@webassemblyjs/wast-printer@npm:1.12.1"
dependencies:
- "@webassemblyjs/ast": "npm:1.11.6"
+ "@webassemblyjs/ast": "npm:1.12.1"
"@xtuc/long": "npm:4.2.2"
- checksum: 916b90fa3a8aadd95ca41c21d4316d0a7582cf6d0dcf6d9db86ab0de823914df513919fba60ac1edd227ff00e93a66b927b15cbddd36b69d8a34c8815752633c
+ checksum: 39bf746eb7a79aa69953f194943bbc43bebae98bd7cadd4d8bc8c0df470ca6bf9d2b789effaa180e900fab4e2691983c1f7d41571458bd2a26267f2f0c73705a
languageName: node
linkType: hard
@@ -9407,12 +9394,12 @@ __metadata:
languageName: node
linkType: hard
-"acorn-import-assertions@npm:^1.9.0":
- version: 1.9.0
- resolution: "acorn-import-assertions@npm:1.9.0"
+"acorn-import-attributes@npm:^1.9.5":
+ version: 1.9.5
+ resolution: "acorn-import-attributes@npm:1.9.5"
peerDependencies:
acorn: ^8
- checksum: 3b4a194e128efdc9b86c2b1544f623aba4c1aa70d638f8ab7dc3971a5b4aa4c57bd62f99af6e5325bb5973c55863b4112e708a6f408bad7a138647ca72283afe
+ checksum: 5926eaaead2326d5a86f322ff1b617b0f698aa61dc719a5baa0e9d955c9885cc71febac3fb5bacff71bbf2c4f9c12db2056883c68c53eb962c048b952e1e013d
languageName: node
linkType: hard
@@ -10440,20 +10427,6 @@ __metadata:
languageName: node
linkType: hard
-"browserslist@npm:^4.14.5, browserslist@npm:^4.21.9":
- version: 4.21.10
- resolution: "browserslist@npm:4.21.10"
- dependencies:
- caniuse-lite: "npm:^1.0.30001517"
- electron-to-chromium: "npm:^1.4.477"
- node-releases: "npm:^2.0.13"
- update-browserslist-db: "npm:^1.0.11"
- bin:
- browserslist: cli.js
- checksum: e8c98496e5f2a5128d0e2f1f186dc0416bfc49c811e568b19c9e07a56cccc1f7f415fa4f532488e6a13dfacbe3332a9b55b152082ff125402696a11a158a0894
- languageName: node
- linkType: hard
-
"browserslist@npm:^4.20.4, browserslist@npm:^4.22.1":
version: 4.22.1
resolution: "browserslist@npm:4.22.1"
@@ -10468,6 +10441,34 @@ __metadata:
languageName: node
linkType: hard
+"browserslist@npm:^4.21.10":
+ version: 4.24.0
+ resolution: "browserslist@npm:4.24.0"
+ dependencies:
+ caniuse-lite: "npm:^1.0.30001663"
+ electron-to-chromium: "npm:^1.5.28"
+ node-releases: "npm:^2.0.18"
+ update-browserslist-db: "npm:^1.1.0"
+ bin:
+ browserslist: cli.js
+ checksum: 95e76ad522753c4c470427f6e3c8a4bb5478ff448841e22b3d3e53f89ecaf17b6984666d6c7e715c370f1e7fa0cf684f42e34e554236a8b2fab38ea76b9e4c52
+ languageName: node
+ linkType: hard
+
+"browserslist@npm:^4.21.9":
+ version: 4.21.10
+ resolution: "browserslist@npm:4.21.10"
+ dependencies:
+ caniuse-lite: "npm:^1.0.30001517"
+ electron-to-chromium: "npm:^1.4.477"
+ node-releases: "npm:^2.0.13"
+ update-browserslist-db: "npm:^1.0.11"
+ bin:
+ browserslist: cli.js
+ checksum: e8c98496e5f2a5128d0e2f1f186dc0416bfc49c811e568b19c9e07a56cccc1f7f415fa4f532488e6a13dfacbe3332a9b55b152082ff125402696a11a158a0894
+ languageName: node
+ linkType: hard
+
"browserslist@npm:^4.22.2":
version: 4.22.2
resolution: "browserslist@npm:4.22.2"
@@ -10738,6 +10739,13 @@ __metadata:
languageName: node
linkType: hard
+"caniuse-lite@npm:^1.0.30001663":
+ version: 1.0.30001663
+ resolution: "caniuse-lite@npm:1.0.30001663"
+ checksum: 6508e27bf7fdec657f26f318b1ab64ace6e1208ef9fedaf0975bc89046e0c683bfba837f108840ada1686ff09b8ffd01e05ac791dcf598b8f16eefb636875cf2
+ languageName: node
+ linkType: hard
+
"case-sensitive-paths-webpack-plugin@npm:^2.4.0":
version: 2.4.0
resolution: "case-sensitive-paths-webpack-plugin@npm:2.4.0"
@@ -12123,6 +12131,13 @@ __metadata:
languageName: node
linkType: hard
+"electron-to-chromium@npm:^1.5.28":
+ version: 1.5.28
+ resolution: "electron-to-chromium@npm:1.5.28"
+ checksum: 6e2f4150ba03ce53ca128955c7d2da071d3774362a10c68848a85b71c29857915e2256cb53cd2de17fdbf0f56bf76ec174d24965abef7430d8c414ec733030b2
+ languageName: node
+ linkType: hard
+
"elliptic@npm:6.5.4":
version: 6.5.4
resolution: "elliptic@npm:6.5.4"
@@ -12259,13 +12274,13 @@ __metadata:
languageName: node
linkType: hard
-"enhanced-resolve@npm:^5.15.0":
- version: 5.15.0
- resolution: "enhanced-resolve@npm:5.15.0"
+"enhanced-resolve@npm:^5.17.1":
+ version: 5.17.1
+ resolution: "enhanced-resolve@npm:5.17.1"
dependencies:
graceful-fs: "npm:^4.2.4"
tapable: "npm:^2.2.0"
- checksum: 69984a7990913948b4150855aed26a84afb4cb1c5a94fb8e3a65bd00729a73fc2eaff6871fb8e345377f294831afe349615c93560f2f54d61b43cdfdf668f19a
+ checksum: 81a0515675eca17efdba2cf5bad87abc91a528fc1191aad50e275e74f045b41506167d420099022da7181c8d787170ea41e4a11a0b10b7a16f6237daecb15370
languageName: node
linkType: hard
@@ -14333,7 +14348,7 @@ __metadata:
languageName: node
linkType: hard
-"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9":
+"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9":
version: 4.2.11
resolution: "graceful-fs@npm:4.2.11"
checksum: 386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2
@@ -18112,6 +18127,13 @@ __metadata:
languageName: node
linkType: hard
+"node-releases@npm:^2.0.18":
+ version: 2.0.18
+ resolution: "node-releases@npm:2.0.18"
+ checksum: 786ac9db9d7226339e1dc84bbb42007cb054a346bd9257e6aa154d294f01bc6a6cddb1348fa099f079be6580acbb470e3c048effd5f719325abd0179e566fd27
+ languageName: node
+ linkType: hard
+
"node-stream-zip@npm:^1.9.1":
version: 1.15.0
resolution: "node-stream-zip@npm:1.15.0"
@@ -21637,7 +21659,7 @@ __metadata:
languageName: node
linkType: hard
-"terser-webpack-plugin@npm:^5.3.1, terser-webpack-plugin@npm:^5.3.7":
+"terser-webpack-plugin@npm:^5.3.1":
version: 5.3.9
resolution: "terser-webpack-plugin@npm:5.3.9"
dependencies:
@@ -21659,6 +21681,28 @@ __metadata:
languageName: node
linkType: hard
+"terser-webpack-plugin@npm:^5.3.10":
+ version: 5.3.10
+ resolution: "terser-webpack-plugin@npm:5.3.10"
+ dependencies:
+ "@jridgewell/trace-mapping": "npm:^0.3.20"
+ jest-worker: "npm:^27.4.5"
+ schema-utils: "npm:^3.1.1"
+ serialize-javascript: "npm:^6.0.1"
+ terser: "npm:^5.26.0"
+ peerDependencies:
+ webpack: ^5.1.0
+ peerDependenciesMeta:
+ "@swc/core":
+ optional: true
+ esbuild:
+ optional: true
+ uglify-js:
+ optional: true
+ checksum: 66d1ed3174542560911cf96f4716aeea8d60e7caab212291705d50072b6ba844c7391442541b13c848684044042bea9ec87512b8506528c12854943da05faf91
+ languageName: node
+ linkType: hard
+
"terser@npm:^5.10.0, terser@npm:^5.15.0, terser@npm:^5.16.8":
version: 5.19.2
resolution: "terser@npm:5.19.2"
@@ -21673,6 +21717,20 @@ __metadata:
languageName: node
linkType: hard
+"terser@npm:^5.26.0":
+ version: 5.33.0
+ resolution: "terser@npm:5.33.0"
+ dependencies:
+ "@jridgewell/source-map": "npm:^0.3.3"
+ acorn: "npm:^8.8.2"
+ commander: "npm:^2.20.0"
+ source-map-support: "npm:~0.5.20"
+ bin:
+ terser: bin/terser
+ checksum: 18a1cd33366dcd8fee7d6eef78c9c417cbe688e5153841e6a574f9d4937066dc40f67b1e96305f73f25bc6f2c458dbe442a056092c99619d4dbee8ad9fae4a3e
+ languageName: node
+ linkType: hard
+
"test-exclude@npm:^6.0.0":
version: 6.0.0
resolution: "test-exclude@npm:6.0.0"
@@ -22836,13 +22894,13 @@ __metadata:
languageName: node
linkType: hard
-"watchpack@npm:^2.4.0":
- version: 2.4.0
- resolution: "watchpack@npm:2.4.0"
+"watchpack@npm:^2.4.1":
+ version: 2.4.2
+ resolution: "watchpack@npm:2.4.2"
dependencies:
glob-to-regexp: "npm:^0.4.1"
graceful-fs: "npm:^4.1.2"
- checksum: c5e35f9fb9338d31d2141d9835643c0f49b5f9c521440bb648181059e5940d93dd8ed856aa8a33fbcdd4e121dad63c7e8c15c063cf485429cd9d427be197fe62
+ checksum: ec60a5f0e9efaeca0102fd9126346b3b2d523e01c34030d3fddf5813a7125765121ebdc2552981136dcd2c852deb1af0b39340f2fcc235f292db5399d0283577
languageName: node
linkType: hard
@@ -22944,39 +23002,38 @@ __metadata:
linkType: hard
"webpack@npm:5":
- version: 5.88.2
- resolution: "webpack@npm:5.88.2"
+ version: 5.95.0
+ resolution: "webpack@npm:5.95.0"
dependencies:
- "@types/eslint-scope": "npm:^3.7.3"
- "@types/estree": "npm:^1.0.0"
- "@webassemblyjs/ast": "npm:^1.11.5"
- "@webassemblyjs/wasm-edit": "npm:^1.11.5"
- "@webassemblyjs/wasm-parser": "npm:^1.11.5"
+ "@types/estree": "npm:^1.0.5"
+ "@webassemblyjs/ast": "npm:^1.12.1"
+ "@webassemblyjs/wasm-edit": "npm:^1.12.1"
+ "@webassemblyjs/wasm-parser": "npm:^1.12.1"
acorn: "npm:^8.7.1"
- acorn-import-assertions: "npm:^1.9.0"
- browserslist: "npm:^4.14.5"
+ acorn-import-attributes: "npm:^1.9.5"
+ browserslist: "npm:^4.21.10"
chrome-trace-event: "npm:^1.0.2"
- enhanced-resolve: "npm:^5.15.0"
+ enhanced-resolve: "npm:^5.17.1"
es-module-lexer: "npm:^1.2.1"
eslint-scope: "npm:5.1.1"
events: "npm:^3.2.0"
glob-to-regexp: "npm:^0.4.1"
- graceful-fs: "npm:^4.2.9"
+ graceful-fs: "npm:^4.2.11"
json-parse-even-better-errors: "npm:^2.3.1"
loader-runner: "npm:^4.2.0"
mime-types: "npm:^2.1.27"
neo-async: "npm:^2.6.2"
schema-utils: "npm:^3.2.0"
tapable: "npm:^2.1.1"
- terser-webpack-plugin: "npm:^5.3.7"
- watchpack: "npm:^2.4.0"
+ terser-webpack-plugin: "npm:^5.3.10"
+ watchpack: "npm:^2.4.1"
webpack-sources: "npm:^3.2.3"
peerDependenciesMeta:
webpack-cli:
optional: true
bin:
webpack: bin/webpack.js
- checksum: 743acf04cdb7f73ec059761d3921798014139005c88e136ab99fe158f544695eee2caf4be775cc06e7f481d84725d443df2c1c8e00ec24a130e8b8fd514ff7b9
+ checksum: b9e6d0f8ebcbf0632494ac0b90fe4acb8f4a9b83f7ace4a67a15545a36fe58599c912ab58e625e1bf58ab3b0916c75fe99da6196d412ee0cab0b5065edd84238
languageName: node
linkType: hard
From cf78f1dc4ff7d8ecf4531a8a5c085d5d040ec11a Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 25 Sep 2024 11:43:15 -0300
Subject: [PATCH 069/114] chore: enable wallet features for universal wallets
---
packages/core/src/controllers/ModalController.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/core/src/controllers/ModalController.ts b/packages/core/src/controllers/ModalController.ts
index 5b768354c..cb67edcad 100644
--- a/packages/core/src/controllers/ModalController.ts
+++ b/packages/core/src/controllers/ModalController.ts
@@ -5,6 +5,7 @@ import { RouterController } from './RouterController';
import { PublicStateController } from './PublicStateController';
import { EventsController } from './EventsController';
import { ApiController } from './ApiController';
+import { ConnectorController } from './ConnectorController';
// -- Types --------------------------------------------- //
export interface ModalControllerState {
@@ -34,7 +35,8 @@ export const ModalController = {
if (options?.view) {
RouterController.reset(options.view);
} else if (AccountController.state.isConnected) {
- RouterController.reset('AccountDefault');
+ const isUniversalWallet = ConnectorController.state.connectedConnector === 'AUTH';
+ RouterController.reset(isUniversalWallet ? 'Account' : 'AccountDefault');
} else {
RouterController.reset('Connect');
}
From 369fa55392c7ebe69ef28603d92831ae9aa3d74b Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 26 Sep 2024 16:13:25 -0300
Subject: [PATCH 070/114] chore: working on social UI
---
.../stories/composites/ListSocial.stories.tsx | 50 +++++++++++++
apps/gallery/utils/PresetUtils.ts | 6 +-
packages/common/src/utils/TypeUtil.ts | 2 +
.../core/src/controllers/OptionsController.ts | 18 ++++-
packages/core/src/utils/ConstantsUtil.ts | 12 ++-
packages/core/src/utils/TypeUtil.ts | 20 ++++-
packages/scaffold/src/client.ts | 8 +-
.../components/connect-email-input.tsx | 40 +++-------
.../components/social-login-list.tsx | 73 +++++++++++++++++++
.../src/views/w3m-connect-view/index.tsx | 19 +++--
.../src/views/w3m-connect-view/styles.ts | 3 +
packages/ui/src/assets/svg/More.tsx | 16 ++++
packages/ui/src/assets/svg/Twitter.tsx | 27 -------
packages/ui/src/assets/svg/TwitterIcon.tsx | 10 ---
packages/ui/src/assets/svg/X.tsx | 26 +++++++
packages/ui/src/components/wui-icon/index.tsx | 12 +--
.../src/composites/wui-list-social/index.tsx | 42 +++++++++++
.../src/composites/wui-list-social/styles.ts | 22 ++++++
.../src/composites/wui-logo-select/index.tsx | 7 +-
.../src/composites/wui-logo-select/styles.ts | 6 +-
packages/ui/src/index.ts | 1 +
packages/ui/src/utils/TypesUtil.ts | 9 ++-
packages/wallet/src/AppKitFrameConstants.ts | 9 ++-
packages/wallet/src/AppKitFrameProvider.ts | 37 ++++++++++
packages/wallet/src/AppKitFrameSchema.ts | 39 +++++++++-
packages/wallet/src/AppKitFrameTypes.ts | 12 ++-
26 files changed, 428 insertions(+), 98 deletions(-)
create mode 100644 apps/gallery/stories/composites/ListSocial.stories.tsx
create mode 100644 packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
create mode 100644 packages/ui/src/assets/svg/More.tsx
delete mode 100644 packages/ui/src/assets/svg/Twitter.tsx
delete mode 100644 packages/ui/src/assets/svg/TwitterIcon.tsx
create mode 100644 packages/ui/src/assets/svg/X.tsx
create mode 100644 packages/ui/src/composites/wui-list-social/index.tsx
create mode 100644 packages/ui/src/composites/wui-list-social/styles.ts
diff --git a/apps/gallery/stories/composites/ListSocial.stories.tsx b/apps/gallery/stories/composites/ListSocial.stories.tsx
new file mode 100644
index 000000000..14a0c9bcf
--- /dev/null
+++ b/apps/gallery/stories/composites/ListSocial.stories.tsx
@@ -0,0 +1,50 @@
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { ListSocial, Text } from '@reown/appkit-ui-react-native';
+import { logoOptions } from '../../utils/PresetUtils';
+import { GalleryContainer } from '../../components/GalleryContainer';
+import { StyleSheet } from 'react-native';
+
+const meta: Meta = {
+ component: ListSocial,
+ argTypes: {
+ logo: {
+ options: logoOptions,
+ control: { type: 'select' }
+ },
+ disabled: {
+ control: { type: 'boolean' }
+ }
+ },
+ args: {
+ logo: 'x',
+ disabled: false
+ }
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: (args: any) => (
+
+
+
+ Continue with{' '}
+
+ {args.logo}
+
+
+
+
+ )
+};
+
+const styles = StyleSheet.create({
+ text: {
+ textAlign: 'center'
+ },
+ social: {
+ textTransform: 'capitalize'
+ }
+});
diff --git a/apps/gallery/utils/PresetUtils.ts b/apps/gallery/utils/PresetUtils.ts
index 8e450efd8..8c36e3aea 100644
--- a/apps/gallery/utils/PresetUtils.ts
+++ b/apps/gallery/utils/PresetUtils.ts
@@ -156,6 +156,7 @@ export const iconOptions: IconType[] = [
'infoCircle',
'mail',
'mobile',
+ 'more',
'networkPlaceholder',
'nftPlaceholder',
'off',
@@ -166,8 +167,6 @@ export const iconOptions: IconType[] = [
'swapVertical',
'telegram',
'twitch',
- 'twitterIcon',
- 'twitter',
'wallet',
'walletSmall',
'walletConnect',
@@ -197,9 +196,10 @@ export const logoOptions: LogoType[] = [
'facebook',
'github',
'google',
+ 'more',
'telegram',
'twitch',
- 'twitter'
+ 'x'
];
export const cardSelectOptions: CardSelectType[] = ['wallet', 'network'];
diff --git a/packages/common/src/utils/TypeUtil.ts b/packages/common/src/utils/TypeUtil.ts
index b5f83c35c..1539688f1 100644
--- a/packages/common/src/utils/TypeUtil.ts
+++ b/packages/common/src/utils/TypeUtil.ts
@@ -85,3 +85,5 @@ export interface TransactionDetail {
export interface TransactionQuantity {
numeric: string;
}
+
+export type SocialProvider = 'google' | 'github' | 'apple' | 'facebook' | 'x' | 'discord';
diff --git a/packages/core/src/controllers/OptionsController.ts b/packages/core/src/controllers/OptionsController.ts
index bd9701d6a..acbaba1c6 100644
--- a/packages/core/src/controllers/OptionsController.ts
+++ b/packages/core/src/controllers/OptionsController.ts
@@ -1,5 +1,13 @@
import { proxy, ref } from 'valtio';
-import type { CustomWallet, Metadata, ProjectId, SdkVersion, Tokens } from '../utils/TypeUtil';
+import type {
+ CustomWallet,
+ Features,
+ Metadata,
+ ProjectId,
+ SdkVersion,
+ Tokens
+} from '../utils/TypeUtil';
+import { ConstantsUtil } from '../utils/ConstantsUtil';
// -- Types --------------------------------------------- //
export interface ClipboardClient {
@@ -19,13 +27,15 @@ export interface OptionsControllerState {
sdkVersion: SdkVersion;
metadata?: Metadata;
isSiweEnabled?: boolean;
+ features?: Features;
}
// -- State --------------------------------------------- //
const state = proxy({
projectId: '',
sdkType: 'appkit',
- sdkVersion: 'react-native-wagmi-undefined'
+ sdkVersion: 'react-native-wagmi-undefined',
+ features: ConstantsUtil.DEFAULT_FEATURES
});
// -- Controller ---------------------------------------- //
@@ -76,6 +86,10 @@ export const OptionsController = {
state.isSiweEnabled = isSiweEnabled;
},
+ setFeatures(features: OptionsControllerState['features']) {
+ state.features = { ...ConstantsUtil.DEFAULT_FEATURES, ...features };
+ },
+
isClipboardAvailable() {
return !!state._clipboardClient;
},
diff --git a/packages/core/src/utils/ConstantsUtil.ts b/packages/core/src/utils/ConstantsUtil.ts
index 288692aa1..b3396ecea 100644
--- a/packages/core/src/utils/ConstantsUtil.ts
+++ b/packages/core/src/utils/ConstantsUtil.ts
@@ -1,3 +1,11 @@
+import type { Features } from './TypeUtil';
+
+const defaultFeatures: Features = {
+ email: true,
+ emailShowWallets: true,
+ socials: ['x', 'discord', 'github', 'apple', 'facebook']
+};
+
export const ConstantsUtil = {
FOUR_MINUTES_MS: 240000,
@@ -9,5 +17,7 @@ export const ConstantsUtil = {
LINKING_ERROR: 'LINKING_ERROR',
- NATIVE_TOKEN_ADDRESS: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
+ NATIVE_TOKEN_ADDRESS: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
+
+ DEFAULT_FEATURES: defaultFeatures
};
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 4b380d0b9..808a65c77 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -1,4 +1,4 @@
-import type { Balance, Transaction } from '@reown/appkit-common-react-native';
+import type { Balance, SocialProvider, Transaction } from '@reown/appkit-common-react-native';
export interface BaseError {
message?: string;
@@ -60,6 +60,24 @@ export type SdkVersion =
| `react-native-ethers5-${string}`
| `react-native-ethers-${string}`;
+export type Features = {
+ /**
+ * @description Enable or disable the email feature. Enabled by default.
+ * @type {boolean}
+ */
+ email?: boolean;
+ /**
+ * @description Show or hide the regular wallet options when email is enabled. Enabled by default.
+ * @type {boolean}
+ */
+ emailShowWallets?: boolean;
+ /**
+ * @description Enable or disable the socials feature. Enabled by default.
+ * @type {FeaturesSocials[]}
+ */
+ socials?: SocialProvider[] | false;
+};
+
// -- ApiController Types -------------------------------------------------------
export interface WcWallet {
id: string;
diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts
index 66760372f..e51a234ed 100644
--- a/packages/scaffold/src/client.ts
+++ b/packages/scaffold/src/client.ts
@@ -13,7 +13,8 @@ import type {
ThemeMode,
ThemeVariables,
Connector,
- ConnectedWalletInfo
+ ConnectedWalletInfo,
+ Features
} from '@reown/appkit-core-react-native';
import type { SIWEControllerClient } from '@reown/appkit-siwe-react-native';
import {
@@ -48,6 +49,7 @@ export interface LibraryOptions {
enableAnalytics?: OptionsControllerState['enableAnalytics'];
_sdkVersion: OptionsControllerState['sdkVersion'];
metadata?: OptionsControllerState['metadata'];
+ features?: Features;
}
export interface ScaffoldOptions extends LibraryOptions {
@@ -262,6 +264,10 @@ export class AppKitScaffold {
SIWEController.setSIWEClient(options.siweControllerClient);
}
+
+ if (options.features) {
+ OptionsController.setFeatures(options.features);
+ }
}
private async setConnectorExcludedWallets(connectors: Connector[]) {
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/connect-email-input.tsx b/packages/scaffold/src/views/w3m-connect-view/components/connect-email-input.tsx
index 620c962fb..4ff60e7ab 100644
--- a/packages/scaffold/src/views/w3m-connect-view/components/connect-email-input.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/components/connect-email-input.tsx
@@ -1,6 +1,6 @@
import { useSnapshot } from 'valtio';
import { useState } from 'react';
-import { EmailInput, FlexView, Separator, Spacing } from '@reown/appkit-ui-react-native';
+import { EmailInput, FlexView } from '@reown/appkit-ui-react-native';
import {
ConnectorController,
CoreHelperUtil,
@@ -9,15 +9,12 @@ import {
SnackController,
type AppKitFrameProvider
} from '@reown/appkit-core-react-native';
-import { StyleSheet } from 'react-native';
interface Props {
- isEmailEnabled: boolean;
- showSeparator: boolean;
loading?: boolean;
}
-export function ConnectEmailInput({ isEmailEnabled, showSeparator, loading }: Props) {
+export function ConnectEmailInput({ loading }: Props) {
const { connectors } = useSnapshot(ConnectorController.state);
const [inputLoading, setInputLoading] = useState(false);
const [error, setError] = useState('');
@@ -57,29 +54,16 @@ export function ConnectEmailInput({ isEmailEnabled, showSeparator, loading }: Pr
}
};
- if (!isEmailEnabled) {
- return null;
- }
-
return (
- <>
-
-
-
- {showSeparator && }
- >
+
+
+
);
}
-
-const styles = StyleSheet.create({
- emailSeparator: {
- marginVertical: Spacing.xs
- }
-});
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
new file mode 100644
index 000000000..61c947fa7
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
@@ -0,0 +1,73 @@
+import { StyleSheet } from 'react-native';
+import { FlexView, ListSocial, LogoSelect, Spacing, Text } from '@reown/appkit-ui-react-native';
+import type { SocialProvider } from '@reown/appkit-common-react-native';
+
+export interface SocialLoginListProps {
+ options: readonly SocialProvider[];
+ disabled?: boolean;
+}
+
+const MAX_OPTIONS = 6;
+
+export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
+ const showBigSocial = options?.length > 2 || options?.length === 1;
+ const showMoreButton = options?.length > MAX_OPTIONS;
+ const topSocial = showBigSocial ? options[0] : null;
+ let bottomSocials = showBigSocial ? options.slice(1) : options;
+ bottomSocials = showMoreButton ? bottomSocials.slice(0, MAX_OPTIONS - 2) : bottomSocials;
+
+ return (
+
+ {topSocial && (
+
+
+ Continue with{' '}
+
+ {topSocial}
+
+
+
+ )}
+
+ {bottomSocials?.map((social: SocialProvider, index) => (
+
+ ))}
+ {showMoreButton && (
+
+ )}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ topDescription: {
+ textAlign: 'center'
+ },
+ topSocial: {
+ textTransform: 'capitalize'
+ },
+ socialItem: {
+ flex: 1,
+ marginHorizontal: Spacing['2xs']
+ },
+ socialItemFirst: {
+ marginLeft: 0
+ },
+ socialItemLast: {
+ marginRight: 0
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-connect-view/index.tsx b/packages/scaffold/src/views/w3m-connect-view/index.tsx
index a90abbeda..b68e303fa 100644
--- a/packages/scaffold/src/views/w3m-connect-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/index.tsx
@@ -4,10 +4,11 @@ import {
ConnectorController,
EventUtil,
EventsController,
+ OptionsController,
RouterController,
type WcWallet
} from '@reown/appkit-core-react-native';
-import { FlexView, Spacing } from '@reown/appkit-ui-react-native';
+import { FlexView, Separator, Spacing } from '@reown/appkit-ui-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import { ConnectEmailInput } from './components/connect-email-input';
import { useKeyboard } from '../../hooks/useKeyboard';
@@ -16,17 +17,25 @@ import { CustomWalletList } from './components/custom-wallet-list';
import { AllWalletsButton } from './components/all-wallets-button';
import { AllWalletList } from './components/all-wallet-list';
import { RecentWalletList } from './components/recent-wallet-list';
+import { SocialLoginList } from './components/social-login-list';
import styles from './styles';
export function ConnectView() {
const connectors = ConnectorController.state.connectors;
const { authLoading } = useSnapshot(ConnectorController.state);
+ const { features } = useSnapshot(OptionsController.state);
const { padding } = useCustomDimensions();
const { keyboardShown, keyboardHeight } = useKeyboard();
const isWalletConnectEnabled = connectors.some(c => c.type === 'WALLET_CONNECT');
const isAuthEnabled = connectors.some(c => c.type === 'AUTH');
const isCoinbaseEnabled = connectors.some(c => c.type === 'COINBASE');
+ const isEmailEnabled = isAuthEnabled && features?.email;
+ const isSocialEnabled = isAuthEnabled && features?.socials && features?.socials.length > 0;
+ const showSeparator =
+ isAuthEnabled &&
+ (isEmailEnabled || isSocialEnabled) &&
+ (isWalletConnectEnabled || isCoinbaseEnabled);
const paddingBottom = Platform.select({
android: keyboardShown ? keyboardHeight + Spacing['2xl'] : Spacing['2xl'],
@@ -61,11 +70,9 @@ export function ConnectView() {
return (
-
+ {isEmailEnabled && }
+ {isSocialEnabled && }
+ {showSeparator && }
(
+
+
+
+
+
+);
+export default SvgMore;
diff --git a/packages/ui/src/assets/svg/Twitter.tsx b/packages/ui/src/assets/svg/Twitter.tsx
deleted file mode 100644
index d54ecdd1d..000000000
--- a/packages/ui/src/assets/svg/Twitter.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import Svg, { G, Circle, Path, Defs, ClipPath, type SvgProps } from 'react-native-svg';
-const SvgTwitter = (props: SvgProps) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
-export default SvgTwitter;
diff --git a/packages/ui/src/assets/svg/TwitterIcon.tsx b/packages/ui/src/assets/svg/TwitterIcon.tsx
deleted file mode 100644
index 7762aa805..000000000
--- a/packages/ui/src/assets/svg/TwitterIcon.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import Svg, { Path, type SvgProps } from 'react-native-svg';
-const SvgTwitter = (props: SvgProps) => (
-
-
-
-);
-export default SvgTwitter;
diff --git a/packages/ui/src/assets/svg/X.tsx b/packages/ui/src/assets/svg/X.tsx
new file mode 100644
index 000000000..3abb020ea
--- /dev/null
+++ b/packages/ui/src/assets/svg/X.tsx
@@ -0,0 +1,26 @@
+import Svg, { G, Path, Defs, ClipPath, type SvgProps, Rect } from 'react-native-svg';
+const SvgX = (props: SvgProps) => (
+
+
+
+
+
+
+
+
+
+
+
+
+);
+export default SvgX;
diff --git a/packages/ui/src/components/wui-icon/index.tsx b/packages/ui/src/components/wui-icon/index.tsx
index f587e8628..11540ab21 100644
--- a/packages/ui/src/components/wui-icon/index.tsx
+++ b/packages/ui/src/components/wui-icon/index.tsx
@@ -37,6 +37,7 @@ import HelpCircleSvg from '../../assets/svg/HelpCircle';
import InfoCircleSvg from '../../assets/svg/InfoCircle';
import MailSvg from '../../assets/svg/Mail';
import MobileSvg from '../../assets/svg/Mobile';
+import MoreSvg from '../../assets/svg/More';
import NetworkPlaceholderSvg from '../../assets/svg/NetworkPlaceholder';
import NftPlaceholderSvg from '../../assets/svg/NftPlaceholder';
import OffSvg from '../../assets/svg/Off';
@@ -47,15 +48,14 @@ import SearchSvg from '../../assets/svg/Search';
import SwapHorizontalSvg from '../../assets/svg/SwapHorizontal';
import SwapVerticalSvg from '../../assets/svg/SwapVertical';
import TelegramSvg from '../../assets/svg/Telegram';
-import TwitterSvg from '../../assets/svg/Twitter';
+import TwitchSvg from '../../assets/svg/Twitch';
import VerifySvg from '../../assets/svg/Verify';
import WalletConnectSvg from '../../assets/svg/WalletConnect';
import WalletSvg from '../../assets/svg/Wallet';
import WalletSmallSvg from '../../assets/svg/WalletSmall';
import WarningCircleSvg from '../../assets/svg/WarningCircle';
-import TwitchSvg from '../../assets/svg/Twitch';
-import TwitterIconSvg from '../../assets/svg/TwitterIcon';
import WalletPlaceholderSvg from '../../assets/svg/WalletPlaceholder';
+import XSvg from '../../assets/svg/X';
import { useTheme } from '../../hooks/useTheme';
import { IconSize } from '../../utils/ThemeUtil';
@@ -95,6 +95,7 @@ const svgOptions: Record JSX.Element> = {
infoCircle: InfoCircleSvg,
mail: MailSvg,
mobile: MobileSvg,
+ more: MoreSvg,
networkPlaceholder: NetworkPlaceholderSvg,
nftPlaceholder: NftPlaceholderSvg,
off: OffSvg,
@@ -106,14 +107,13 @@ const svgOptions: Record JSX.Element> = {
swapVertical: SwapVerticalSvg,
telegram: TelegramSvg,
twitch: TwitchSvg,
- twitter: TwitterSvg,
- twitterIcon: TwitterIconSvg,
verify: VerifySvg,
wallet: WalletSvg,
walletSmall: WalletSmallSvg,
warningCircle: WarningCircleSvg,
walletConnect: WalletConnectSvg,
- walletPlaceholder: WalletPlaceholderSvg
+ walletPlaceholder: WalletPlaceholderSvg,
+ x: XSvg
};
export type IconProps = SvgProps & {
diff --git a/packages/ui/src/composites/wui-list-social/index.tsx b/packages/ui/src/composites/wui-list-social/index.tsx
new file mode 100644
index 000000000..7b8051d1a
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-social/index.tsx
@@ -0,0 +1,42 @@
+import { View, Pressable, Animated, type StyleProp, type ViewStyle } from 'react-native';
+import useAnimatedValue from '../../hooks/useAnimatedValue';
+import { useTheme } from '../../hooks/useTheme';
+import type { LogoType } from '../../utils/TypesUtil';
+
+import styles from './styles';
+import { Logo } from '../wui-logo';
+import type { ReactNode } from 'react';
+
+const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
+
+export interface ListSocialProps {
+ children?: ReactNode;
+ disabled?: boolean;
+ logo: LogoType;
+ onPress?: () => void;
+ style?: StyleProp;
+ testID?: string;
+}
+
+export function ListSocial({ logo, children, disabled, onPress, style, testID }: ListSocialProps) {
+ const Theme = useTheme();
+ const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
+ Theme['gray-glass-005'],
+ Theme['gray-glass-010']
+ );
+
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-list-social/styles.ts b/packages/ui/src/composites/wui-list-social/styles.ts
new file mode 100644
index 000000000..46eaad088
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-social/styles.ts
@@ -0,0 +1,22 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
+
+export default StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ height: 56,
+ width: '100%',
+ padding: Spacing.s,
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ borderRadius: BorderRadius.s
+ },
+ rightPlaceholder: {
+ width: 40,
+ height: 40,
+ borderRadius: 100
+ },
+ disabledLogo: {
+ opacity: 0.4
+ }
+});
diff --git a/packages/ui/src/composites/wui-logo-select/index.tsx b/packages/ui/src/composites/wui-logo-select/index.tsx
index 80cc00ebd..8bfe8c549 100644
--- a/packages/ui/src/composites/wui-logo-select/index.tsx
+++ b/packages/ui/src/composites/wui-logo-select/index.tsx
@@ -1,4 +1,4 @@
-import { Animated, Pressable } from 'react-native';
+import { Animated, Pressable, type StyleProp, type ViewStyle } from 'react-native';
import useAnimatedValue from '../../hooks/useAnimatedValue';
import { useTheme } from '../../hooks/useTheme';
import type { LogoType } from '../../utils/TypesUtil';
@@ -10,9 +10,10 @@ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
export interface LogoSelectProps {
logo: LogoType;
disabled?: boolean;
+ style?: StyleProp;
}
-export function LogoSelect({ logo, disabled }: LogoSelectProps) {
+export function LogoSelect({ logo, disabled, style }: LogoSelectProps) {
const Theme = useTheme();
const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
Theme['gray-glass-005'],
@@ -23,7 +24,7 @@ export function LogoSelect({ logo, disabled }: LogoSelectProps) {
diff --git a/packages/ui/src/composites/wui-logo-select/styles.ts b/packages/ui/src/composites/wui-logo-select/styles.ts
index 8f7f37131..fbffeaabb 100644
--- a/packages/ui/src/composites/wui-logo-select/styles.ts
+++ b/packages/ui/src/composites/wui-logo-select/styles.ts
@@ -3,9 +3,9 @@ import { BorderRadius } from '../../utils/ThemeUtil';
export default StyleSheet.create({
box: {
- height: 50,
- width: 50,
- borderRadius: BorderRadius.xs,
+ height: 56,
+ width: 56,
+ borderRadius: BorderRadius.s,
alignItems: 'center',
justifyContent: 'center'
},
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index e3c05c2c0..317211753 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -40,6 +40,7 @@ export { InputNumeric, type InputNumericProps } from './composites/wui-input-num
export { InputText, type InputTextProps } from './composites/wui-input-text';
export { Link, type LinkProps } from './composites/wui-link';
export { ListItem, type ListItemProps } from './composites/wui-list-item';
+export { ListSocial, type ListSocialProps } from './composites/wui-list-social';
export { ListToken, type ListTokenProps } from './composites/wui-list-token';
export { ListTransaction, type ListTransactionProps } from './composites/wui-list-transaction';
export { ListWallet, type ListWalletProps } from './composites/wui-list-wallet';
diff --git a/packages/ui/src/utils/TypesUtil.ts b/packages/ui/src/utils/TypesUtil.ts
index 01a88675d..4172f2fda 100644
--- a/packages/ui/src/utils/TypesUtil.ts
+++ b/packages/ui/src/utils/TypesUtil.ts
@@ -157,6 +157,7 @@ export type IconType =
| 'infoCircle'
| 'mail'
| 'mobile'
+ | 'more'
| 'networkPlaceholder'
| 'nftPlaceholder'
| 'off'
@@ -168,14 +169,13 @@ export type IconType =
| 'swapVertical'
| 'telegram'
| 'twitch'
- | 'twitter'
- | 'twitterIcon'
| 'verify'
| 'wallet'
| 'walletSmall'
| 'walletConnect'
| 'walletPlaceholder'
- | 'warningCircle';
+ | 'warningCircle'
+ | 'x';
export type VisualType =
| 'browser'
@@ -198,9 +198,10 @@ export type LogoType =
| 'facebook'
| 'github'
| 'google'
+ | 'more'
| 'telegram'
| 'twitch'
- | 'twitter';
+ | 'x';
export type TagType = 'main' | 'shade' | 'error' | 'success';
diff --git a/packages/wallet/src/AppKitFrameConstants.ts b/packages/wallet/src/AppKitFrameConstants.ts
index a0a13d0f3..273fc8bda 100644
--- a/packages/wallet/src/AppKitFrameConstants.ts
+++ b/packages/wallet/src/AppKitFrameConstants.ts
@@ -13,6 +13,7 @@ export const AppKitFrameConstants = {
LAST_USED_CHAIN_KEY: 'LAST_USED_CHAIN_KEY',
LAST_EMAIL_LOGIN_TIME: 'LAST_EMAIL_LOGIN_TIME', // Also present in core/src/utils/StorageUtil.ts
EMAIL: 'EMAIL',
+ SOCIAL_USERNAME: 'SOCIAL_USERNAME',
FRAME_MESSAGES_HANDLER: `
const iframe = document.getElementById("frame-mobile-sdk");
@@ -27,6 +28,8 @@ export const AppKitFrameConstants = {
APP_CONNECT_EMAIL: '@w3m-app/CONNECT_EMAIL',
APP_CONNECT_DEVICE: '@w3m-app/CONNECT_DEVICE',
APP_CONNECT_OTP: '@w3m-app/CONNECT_OTP',
+ APP_CONNECT_SOCIAL: '@w3m-app/CONNECT_SOCIAL',
+ APP_GET_SOCIAL_REDIRECT_URI: '@w3m-app/GET_SOCIAL_REDIRECT_URI',
APP_GET_USER: '@w3m-app/GET_USER',
APP_SIGN_OUT: '@w3m-app/SIGN_OUT',
APP_IS_CONNECTED: '@w3m-app/IS_CONNECTED',
@@ -118,5 +121,9 @@ export const AppKitFrameRpcConstants = {
],
GET_CHAIN_ID: 'eth_chainId',
RPC_METHOD_NOT_ALLOWED_MESSAGE: 'Requested RPC call is not allowed',
- RPC_METHOD_NOT_ALLOWED_UI_MESSAGE: 'Action not allowed'
+ RPC_METHOD_NOT_ALLOWED_UI_MESSAGE: 'Action not allowed',
+ ACCOUNT_TYPES: {
+ EOA: 'eoa',
+ SMART_ACCOUNT: 'smartAccount'
+ } as const
};
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index 41f336a7e..9feaf02ed 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -134,6 +134,23 @@ export class AppKitFrameProvider {
return response;
}
+ public async connectSocial(uri: string) {
+ try {
+ const response = await this.appEvent<'ConnectSocial'>({
+ type: AppKitFrameConstants.APP_CONNECT_SOCIAL,
+ payload: { uri }
+ } as AppKitFrameTypes.AppEvent);
+
+ if (response.userName) {
+ this.setSocialLoginSuccess(response.userName);
+ }
+
+ return response;
+ } catch (error) {
+ throw error;
+ }
+ }
+
public async connectOtp(payload: AppKitFrameTypes.Requests['AppConnectOtpRequest']) {
await this.webviewLoadPromise;
@@ -172,6 +189,19 @@ export class AppKitFrameProvider {
return response;
}
+ public async getSocialRedirectUri(
+ payload: AppKitFrameTypes.Requests['AppGetSocialRedirectUriRequest']
+ ) {
+ try {
+ return this.appEvent<'GetSocialRedirectUri'>({
+ type: AppKitFrameConstants.APP_GET_SOCIAL_REDIRECT_URI,
+ payload
+ } as AppKitFrameTypes.AppEvent);
+ } catch (error) {
+ throw error;
+ }
+ }
+
public async updateEmail(payload: AppKitFrameTypes.Requests['AppUpdateEmailRequest']) {
await this.webviewLoadPromise;
await AppKitFrameHelpers.checkIfAllowedToTriggerEmail();
@@ -348,6 +378,10 @@ export class AppKitFrameProvider {
AppKitFrameStorage.set(AppKitFrameConstants.LAST_EMAIL_LOGIN_TIME, Date.now().toString());
}
+ private setSocialLoginSuccess(username: string) {
+ AppKitFrameStorage.set(AppKitFrameConstants.SOCIAL_USERNAME, username);
+ }
+
private setEmailLoginSuccess(email: string) {
AppKitFrameStorage.set(AppKitFrameConstants.EMAIL, email);
AppKitFrameStorage.set(AppKitFrameConstants.EMAIL_LOGIN_USED_KEY, 'true');
@@ -359,6 +393,7 @@ export class AppKitFrameProvider {
AppKitFrameStorage.delete(AppKitFrameConstants.EMAIL_LOGIN_USED_KEY);
AppKitFrameStorage.delete(AppKitFrameConstants.EMAIL);
AppKitFrameStorage.delete(AppKitFrameConstants.LAST_USED_CHAIN_KEY);
+ AppKitFrameStorage.delete(AppKitFrameConstants.SOCIAL_USERNAME);
this.email = undefined;
}
@@ -492,6 +527,8 @@ export interface AppKitFrameProviderMethods {
// Social
connectDevice: AppKitFrameProvider['connectDevice'];
+ connectSocial: AppKitFrameProvider['connectSocial'];
+ getSocialRedirectUri: AppKitFrameProvider['getSocialRedirectUri'];
// Misc
syncTheme: AppKitFrameProvider['syncTheme'];
diff --git a/packages/wallet/src/AppKitFrameSchema.ts b/packages/wallet/src/AppKitFrameSchema.ts
index 552338641..3f381d63b 100644
--- a/packages/wallet/src/AppKitFrameSchema.ts
+++ b/packages/wallet/src/AppKitFrameSchema.ts
@@ -1,5 +1,5 @@
import { z } from 'zod';
-import { AppKitFrameConstants } from './AppKitFrameConstants';
+import { AppKitFrameConstants, AppKitFrameRpcConstants } from './AppKitFrameConstants';
// -- Helpers ----------------------------------------------------------------
const zError = z.object({ message: z.string() });
@@ -32,6 +32,10 @@ export const GetTransactionByHashResponse = z.object({
export const AppSwitchNetworkRequest = z.object({ chainId: z.string().or(z.number()) });
export const AppConnectEmailRequest = z.object({ email: z.string().email() });
export const AppConnectOtpRequest = z.object({ otp: z.string() });
+export const AppConnectSocialRequest = z.object({ uri: z.string() });
+export const AppGetSocialRedirectUriRequest = z.object({
+ provider: z.enum(['google', 'github', 'apple', 'facebook', 'x', 'discord'])
+});
export const AppGetUserRequest = z.object({ chainId: z.optional(z.string().or(z.number())) });
export const AppUpdateEmailRequest = z.object({ email: z.string().email() });
export const AppUpdateEmailPrimaryOtpRequest = z.object({ otp: z.string() });
@@ -74,6 +78,25 @@ export const FrameIsConnectedResponse = z.object({ isConnected: z.boolean() });
export const FrameGetChainIdResponse = z.object({ chainId: z.number() });
export const FrameSwitchNetworkResponse = z.object({ chainId: z.number() });
export const FrameUpdateEmailSecondaryOtpResponse = z.object({ newEmail: z.string().email() });
+export const FrameGetSocialRedirectUriResponse = z.object({ uri: z.string() });
+
+export const FrameConnectSocialResponse = z.object({
+ email: z.string(),
+ address: z.string(),
+ chainId: z.string().or(z.number()),
+ accounts: z
+ .array(
+ z.object({
+ address: z.string(),
+ type: z.enum([
+ AppKitFrameRpcConstants.ACCOUNT_TYPES.EOA,
+ AppKitFrameRpcConstants.ACCOUNT_TYPES.SMART_ACCOUNT
+ ])
+ })
+ )
+ .optional(),
+ userName: z.string().optional()
+});
export const RpcResponse = z.any();
@@ -277,8 +300,22 @@ export const AppKitFrameSchema = {
.or(EventSchema.extend({ type: zType('APP_CONNECT_OTP'), payload: AppConnectOtpRequest }))
+ .or(
+ EventSchema.extend({
+ type: zType('APP_CONNECT_SOCIAL'),
+ payload: AppConnectSocialRequest
+ })
+ )
+
.or(EventSchema.extend({ type: zType('APP_GET_USER'), payload: z.optional(AppGetUserRequest) }))
+ .or(
+ EventSchema.extend({
+ type: zType('APP_GET_SOCIAL_REDIRECT_URI'),
+ payload: AppGetSocialRedirectUriRequest
+ })
+ )
+
.or(EventSchema.extend({ type: zType('APP_SIGN_OUT') }))
.or(EventSchema.extend({ type: zType('APP_IS_CONNECTED'), payload: z.optional(FrameSession) }))
diff --git a/packages/wallet/src/AppKitFrameTypes.ts b/packages/wallet/src/AppKitFrameTypes.ts
index 256f9f137..79a74cf7a 100644
--- a/packages/wallet/src/AppKitFrameTypes.ts
+++ b/packages/wallet/src/AppKitFrameTypes.ts
@@ -55,7 +55,11 @@ import {
RpcEthChainId,
FrameSwitchNetworkResponse,
AppSyncDappDataRequest,
- FrameUpdateEmailResponse
+ FrameUpdateEmailResponse,
+ FrameGetSocialRedirectUriResponse,
+ FrameConnectSocialResponse,
+ AppGetSocialRedirectUriRequest,
+ AppConnectSocialRequest
} from './AppKitFrameSchema';
export namespace AppKitFrameTypes {
@@ -73,6 +77,8 @@ export namespace AppKitFrameTypes {
AppSyncDappDataRequest: z.infer;
AppUpdateEmailPrimaryOtpRequest: z.infer;
AppUpdateEmailSecondaryOtpRequest: z.infer;
+ AppGetSocialRedirectUriRequest: z.infer;
+ AppConnectSocialRequest: z.infer;
}
export interface Responses {
@@ -83,6 +89,8 @@ export namespace AppKitFrameTypes {
FrameSwitchNetworkResponse: z.infer;
FrameUpdateEmailResponse: z.infer;
FrameConnectOtpResponse: undefined;
+ FrameGetSocialRedirectUriResponse: z.infer;
+ FrameConnectSocialResponse: z.infer;
FrameSyncThemeResponse: undefined;
FrameSyncDappDataResponse: undefined;
FrameUpdateEmailPrimaryOtpResponse: undefined;
@@ -151,7 +159,9 @@ export namespace AppKitFrameTypes {
| 'GetUser'
| 'ConnectDevice'
| 'ConnectEmail'
+ | 'ConnectSocial'
| 'ConnectOtp'
+ | 'GetSocialRedirectUri'
| 'SwitchNetwork'
| 'UpdateEmail'
| 'SyncTheme'
From b11e9d7c1b732122b4d3deb50c6c939c39e40de2 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 26 Sep 2024 17:16:24 -0300
Subject: [PATCH 071/114] chore: working on social connecting screen
---
packages/common/src/index.ts | 1 +
packages/common/src/utils/StringUtil.ts | 9 ++++
.../core/src/controllers/RouterController.ts | 3 ++
.../scaffold/src/modal/w3m-router/index.tsx | 30 ++++++-----
.../src/partials/w3m-header/index.tsx | 3 ++
.../components/social-login-list.tsx | 18 +++----
.../w3m-connecting-social-view/index.tsx | 50 +++++++++++++++++++
.../w3m-connecting-social-view/styles.ts | 15 ++++++
.../w3m-what-is-a-network-view/index.tsx | 2 +-
.../src/composites/wui-list-social/index.tsx | 2 +-
.../src/composites/wui-logo-select/index.tsx | 6 ++-
packages/ui/src/composites/wui-logo/index.tsx | 6 ++-
12 files changed, 117 insertions(+), 28 deletions(-)
create mode 100644 packages/common/src/utils/StringUtil.ts
create mode 100644 packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-connecting-social-view/styles.ts
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 13f0e979b..8f77cbeb7 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -4,5 +4,6 @@ export { DateUtil } from './utils/DateUtil';
export { NamesUtil } from './utils/NamesUtil';
export { NetworkUtil } from './utils/NetworkUtil';
export { NumberUtil } from './utils/NumberUtil';
+export { StringUtil } from './utils/StringUtil';
export { erc20ABI } from './contracts/erc20';
export * from './utils/TypeUtil';
diff --git a/packages/common/src/utils/StringUtil.ts b/packages/common/src/utils/StringUtil.ts
new file mode 100644
index 000000000..024f725f8
--- /dev/null
+++ b/packages/common/src/utils/StringUtil.ts
@@ -0,0 +1,9 @@
+export const StringUtil = {
+ capitalize(value?: string) {
+ if (!value) {
+ return '';
+ }
+
+ return value.charAt(0).toUpperCase() + value.slice(1);
+ }
+};
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index 6d29bf004..adcdbbe41 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -1,5 +1,6 @@
import { proxy } from 'valtio';
import type { WcWallet, CaipNetwork, Connector } from '../utils/TypeUtil';
+import type { SocialProvider } from '@reown/appkit-common-react-native';
// -- Types --------------------------------------------- //
type TransactionAction = {
@@ -19,6 +20,7 @@ export interface RouterControllerState {
| 'Connect'
| 'ConnectingExternal'
| 'ConnectingSiwe'
+ | 'ConnectingSocial'
| 'ConnectingWalletConnect'
| 'EmailVerifyDevice'
| 'EmailVerifyOtp'
@@ -44,6 +46,7 @@ export interface RouterControllerState {
network?: CaipNetwork;
email?: string;
newEmail?: string;
+ socialProvider?: SocialProvider;
};
transactionStack: TransactionAction[];
}
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index f7c313e57..5ae5df623 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -1,32 +1,34 @@
import { useLayoutEffect, useMemo } from 'react';
import { useSnapshot } from 'valtio';
import { RouterController } from '@reown/appkit-core-react-native';
-import { ConnectingSiweView } from '@reown/appkit-siwe-react-native';
-import { ConnectView } from '../../views/w3m-connect-view';
+import { AccountDefaultView } from '../../views/w3m-account-default-view';
+import { AccountView } from '../../views/w3m-account-view';
import { AllWalletsView } from '../../views/w3m-all-wallets-view';
+import { ConnectView } from '../../views/w3m-connect-view';
import { ConnectingView } from '../../views/w3m-connecting-view';
-import { WhatIsAWalletView } from '../../views/w3m-what-is-a-wallet-view';
-import { GetWalletView } from '../../views/w3m-get-wallet-view';
-import { AccountDefaultView } from '../../views/w3m-account-default-view';
-import { NetworksView } from '../../views/w3m-networks-view';
-import { WhatIsNetworkView } from '../../views/w3m-what-is-a-network-view';
-import { NetworkSwitchView } from '../../views/w3m-network-switch-view';
-import { UiUtil } from '../../utils/UiUtil';
import { ConnectingExternalView } from '../../views/w3m-connecting-external-view';
+import { ConnectingSocialView } from '../../views/w3m-connecting-social-view';
+import { ConnectingSiweView } from '@reown/appkit-siwe-react-native';
import { EmailVerifyOtpView } from '../../views/w3m-email-verify-otp-view';
import { EmailVerifyDeviceView } from '../../views/w3m-email-verify-device-view';
+import { GetWalletView } from '../../views/w3m-get-wallet-view';
+import { NetworksView } from '../../views/w3m-networks-view';
+import { NetworkSwitchView } from '../../views/w3m-network-switch-view';
import { UpdateEmailWalletView } from '../../views/w3m-update-email-wallet-view';
import { UpdateEmailPrimaryOtpView } from '../../views/w3m-update-email-primary-otp-view';
import { UpdateEmailSecondaryOtpView } from '../../views/w3m-update-email-secondary-otp-view';
import { UpgradeEmailWalletView } from '../../views/w3m-upgrade-email-wallet-view';
-import { AccountView } from '../../views/w3m-account-view';
-import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
-import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-networks-view';
import { TransactionsView } from '../../views/w3m-transactions-view';
+import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-networks-view';
+import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
import { WalletSendView } from '../../views/w3m-wallet-send-view';
import { WalletSendPreviewView } from '../../views/w3m-wallet-send-preview-view';
import { WalletSendSelectTokenView } from '../../views/w3m-wallet-send-select-token-view';
+import { WhatIsANetworkView } from '../../views/w3m-what-is-a-network-view';
+import { WhatIsAWalletView } from '../../views/w3m-what-is-a-wallet-view';
+
+import { UiUtil } from '../../utils/UiUtil';
export function AppKitRouter() {
const { view } = useSnapshot(RouterController.state);
@@ -49,6 +51,8 @@ export function AppKitRouter() {
return ConnectingExternalView;
case 'ConnectingSiwe':
return ConnectingSiweView;
+ case 'ConnectingSocial':
+ return ConnectingSocialView;
case 'ConnectingWalletConnect':
return ConnectingView;
case 'EmailVerifyDevice':
@@ -82,7 +86,7 @@ export function AppKitRouter() {
case 'WalletSendSelectToken':
return WalletSendSelectTokenView;
case 'WhatIsANetwork':
- return WhatIsNetworkView;
+ return WhatIsANetworkView;
case 'WhatIsAWallet':
return WhatIsAWalletView;
default:
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index a8fb15f96..40cee19df 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -4,6 +4,7 @@ import {
EventsController
} from '@reown/appkit-core-react-native';
import { IconLink, Text, FlexView } from '@reown/appkit-ui-react-native';
+import { StringUtil } from '@reown/appkit-common-react-native';
export function Header() {
const onHelpPress = () => {
@@ -16,6 +17,7 @@ export function Header() {
const connectorName = data?.connector?.name;
const walletName = data?.wallet?.name;
const networkName = data?.network?.name;
+ const socialName = StringUtil.capitalize(data?.socialProvider);
return {
Account: undefined,
@@ -24,6 +26,7 @@ export function Header() {
Connect: 'Connect wallet',
ConnectingExternal: connectorName ?? 'Connect wallet',
ConnectingSiwe: 'Sign In',
+ ConnectingSocial: socialName ?? 'Connecting Social',
ConnectingWalletConnect: walletName ?? 'WalletConnect',
EmailVerifyDevice: ' ',
EmailVerifyOtp: 'Confirm email',
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
index 61c947fa7..bf9c0189d 100644
--- a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
@@ -1,6 +1,7 @@
import { StyleSheet } from 'react-native';
import { FlexView, ListSocial, LogoSelect, Spacing, Text } from '@reown/appkit-ui-react-native';
-import type { SocialProvider } from '@reown/appkit-common-react-native';
+import { type SocialProvider, StringUtil } from '@reown/appkit-common-react-native';
+import { RouterController } from '@reown/appkit-core-react-native';
export interface SocialLoginListProps {
options: readonly SocialProvider[];
@@ -16,15 +17,16 @@ export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
let bottomSocials = showBigSocial ? options.slice(1) : options;
bottomSocials = showMoreButton ? bottomSocials.slice(0, MAX_OPTIONS - 2) : bottomSocials;
+ const onItemPress = (social: SocialProvider) => {
+ RouterController.push('ConnectingSocial', { socialProvider: social });
+ };
+
return (
{topSocial && (
-
+ onItemPress(topSocial)}>
- Continue with{' '}
-
- {topSocial}
-
+ {`Continue with ${StringUtil.capitalize(topSocial)}`}
)}
@@ -34,6 +36,7 @@ export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
key={social}
disabled={disabled}
logo={social}
+ onPress={() => onItemPress(social)}
style={[
styles.socialItem,
index === 0 && styles.socialItemFirst,
@@ -57,9 +60,6 @@ const styles = StyleSheet.create({
topDescription: {
textAlign: 'center'
},
- topSocial: {
- textTransform: 'capitalize'
- },
socialItem: {
flex: 1,
marginHorizontal: Spacing['2xs']
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
new file mode 100644
index 000000000..849646b55
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
@@ -0,0 +1,50 @@
+import { useCallback, useEffect, useState } from 'react';
+import { RouterController } from '@reown/appkit-core-react-native';
+import { FlexView, LoadingThumbnail, IconBox, Logo, Text } from '@reown/appkit-ui-react-native';
+import { StringUtil } from '@reown/appkit-common-react-native';
+
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import styles from './styles';
+
+export function ConnectingSocialView() {
+ const { data } = RouterController.state;
+ const { maxWidth: width } = useCustomDimensions();
+ const [error, setError] = useState();
+ const provider = data?.socialProvider;
+
+ const onConnect = useCallback(async () => {}, []);
+
+ useEffect(() => {
+ onConnect();
+ }, [onConnect]);
+
+ return (
+
+
+
+ {error && (
+
+ )}
+
+
+ {`Continue with ${StringUtil.capitalize(provider)}`}
+
+
+ Connect in the provider window
+
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/styles.ts b/packages/scaffold/src/views/w3m-connecting-social-view/styles.ts
new file mode 100644
index 000000000..dcb555e83
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/styles.ts
@@ -0,0 +1,15 @@
+import { StyleSheet } from 'react-native';
+import { Spacing } from '@reown/appkit-ui-react-native';
+
+export default StyleSheet.create({
+ errorIcon: {
+ position: 'absolute',
+ bottom: 8,
+ right: 8,
+ zIndex: 2
+ },
+ continueText: {
+ marginTop: Spacing.m,
+ marginBottom: Spacing.xs
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-what-is-a-network-view/index.tsx b/packages/scaffold/src/views/w3m-what-is-a-network-view/index.tsx
index b201449f8..cb8cca52a 100644
--- a/packages/scaffold/src/views/w3m-what-is-a-network-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-what-is-a-network-view/index.tsx
@@ -3,7 +3,7 @@ import { Button, FlexView, Text, Visual } from '@reown/appkit-ui-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
-export function WhatIsNetworkView() {
+export function WhatIsANetworkView() {
const { padding } = useCustomDimensions();
const onLearnMorePress = () => {
Linking.openURL('https://ethereum.org/en/developers/docs/networks/');
diff --git a/packages/ui/src/composites/wui-list-social/index.tsx b/packages/ui/src/composites/wui-list-social/index.tsx
index 7b8051d1a..4845cd02b 100644
--- a/packages/ui/src/composites/wui-list-social/index.tsx
+++ b/packages/ui/src/composites/wui-list-social/index.tsx
@@ -21,7 +21,7 @@ export interface ListSocialProps {
export function ListSocial({ logo, children, disabled, onPress, style, testID }: ListSocialProps) {
const Theme = useTheme();
const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
- Theme['gray-glass-005'],
+ Theme['gray-glass-002'],
Theme['gray-glass-010']
);
diff --git a/packages/ui/src/composites/wui-logo-select/index.tsx b/packages/ui/src/composites/wui-logo-select/index.tsx
index 8bfe8c549..3a4c68f7f 100644
--- a/packages/ui/src/composites/wui-logo-select/index.tsx
+++ b/packages/ui/src/composites/wui-logo-select/index.tsx
@@ -11,17 +11,19 @@ export interface LogoSelectProps {
logo: LogoType;
disabled?: boolean;
style?: StyleProp;
+ onPress?: () => void;
}
-export function LogoSelect({ logo, disabled, style }: LogoSelectProps) {
+export function LogoSelect({ logo, disabled, style, onPress }: LogoSelectProps) {
const Theme = useTheme();
const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
- Theme['gray-glass-005'],
+ Theme['gray-glass-002'],
Theme['gray-glass-010']
);
return (
;
+export function Logo({ width = 40, height = 40, logo, style }: LogoProps) {
+ return ;
}
From 279b164f10744a18a237f58cc4290ead19483ecd Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 27 Sep 2024 13:06:37 -0300
Subject: [PATCH 072/114] chore: add missing events
---
packages/core/src/utils/TypeUtil.ts | 17 ++++++++++-
packages/wallet/src/AppKitFrameConstants.ts | 4 +++
packages/wallet/src/AppKitFrameSchema.ts | 31 +++++++++++++++++++++
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 808a65c77..6bade5013 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -475,7 +475,7 @@ export interface WriteContractArgs {
// -- Email Types ------------------------------------------------
/**
- * Matches type defined for packages/email/src/AppKitFrameProvider.ts
+ * Matches type defined for packages/wallet/src/AppKitFrameProvider.ts
* It's duplicated in order to decouple scaffold from email package
*/
export interface AppKitFrameProvider {
@@ -492,6 +492,21 @@ export interface AppKitFrameProvider {
action: 'VERIFY_DEVICE' | 'VERIFY_OTP';
}>;
connectDevice(): Promise;
+ connectSocial(uri: string): Promise<{
+ chainId: string | number;
+ email: string;
+ address: string;
+ accounts?:
+ | {
+ type: 'eoa' | 'smartAccount';
+ address: string;
+ }[]
+ | undefined;
+ userName?: string | undefined;
+ }>;
+ getSocialRedirectUri(payload: { provider: SocialProvider }): Promise<{
+ uri: string;
+ }>;
connectOtp(payload: { otp: string }): Promise;
isConnected(): Promise<{
isConnected: boolean;
diff --git a/packages/wallet/src/AppKitFrameConstants.ts b/packages/wallet/src/AppKitFrameConstants.ts
index 273fc8bda..7a3e56bea 100644
--- a/packages/wallet/src/AppKitFrameConstants.ts
+++ b/packages/wallet/src/AppKitFrameConstants.ts
@@ -50,8 +50,12 @@ export const AppKitFrameConstants = {
FRAME_CONNECT_DEVICE_SUCCESS: '@w3m-frame/CONNECT_DEVICE_SUCCESS',
FRAME_CONNECT_OTP_SUCCESS: '@w3m-frame/CONNECT_OTP_SUCCESS',
FRAME_CONNECT_OTP_ERROR: '@w3m-frame/CONNECT_OTP_ERROR',
+ FRAME_CONNECT_SOCIAL_SUCCESS: '@w3m-frame/CONNECT_SOCIAL_SUCCESS',
+ FRAME_CONNECT_SOCIAL_ERROR: '@w3m-frame/CONNECT_SOCIAL_ERROR',
FRAME_GET_USER_SUCCESS: '@w3m-frame/GET_USER_SUCCESS',
FRAME_GET_USER_ERROR: '@w3m-frame/GET_USER_ERROR',
+ FRAME_GET_SOCIAL_REDIRECT_URI_SUCCESS: '@w3m-frame/GET_SOCIAL_REDIRECT_URI_SUCCESS',
+ FRAME_GET_SOCIAL_REDIRECT_URI_ERROR: '@w3m-frame/GET_SOCIAL_REDIRECT_URI_ERROR',
FRAME_SIGN_OUT_SUCCESS: '@w3m-frame/SIGN_OUT_SUCCESS',
FRAME_SIGN_OUT_ERROR: '@w3m-frame/SIGN_OUT_ERROR',
FRAME_IS_CONNECTED_SUCCESS: '@w3m-frame/IS_CONNECTED_SUCCESS',
diff --git a/packages/wallet/src/AppKitFrameSchema.ts b/packages/wallet/src/AppKitFrameSchema.ts
index 3f381d63b..f66e4c066 100644
--- a/packages/wallet/src/AppKitFrameSchema.ts
+++ b/packages/wallet/src/AppKitFrameSchema.ts
@@ -435,6 +435,21 @@ export const AppKitFrameSchema = {
})
)
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_CONNECT_SOCIAL_SUCCESS'),
+ payload: FrameConnectSocialResponse,
+ origin: z.string()
+ })
+ )
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_CONNECT_SOCIAL_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
+
.or(EventSchema.extend({ type: zType('FRAME_CONNECT_DEVICE_SUCCESS'), origin: z.string() }))
.or(
@@ -453,6 +468,22 @@ export const AppKitFrameSchema = {
})
)
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_SOCIAL_REDIRECT_URI_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
+
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_SOCIAL_REDIRECT_URI_SUCCESS'),
+ payload: FrameGetSocialRedirectUriResponse,
+ origin: z.string()
+ })
+ )
+
.or(
EventSchema.extend({
type: zType('FRAME_SIGN_OUT_ERROR'),
From a34052b5defdd9b651ff39a2a8ce7e70e9610ef9 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 27 Sep 2024 17:27:43 -0300
Subject: [PATCH 073/114] chore: complete flow
---
.../core/src/controllers/WebviewController.ts | 41 +++++
packages/core/src/index.ts | 2 +
packages/core/src/utils/TypeUtil.ts | 1 +
.../scaffold/src/modal/w3m-modal/index.tsx | 12 +-
.../views/w3m-account-default-view/index.tsx | 9 +-
.../w3m-connecting-social-view/index.tsx | 40 ++++-
packages/wallet/src/AppKitAuthWebview.tsx | 26 +--
packages/wallet/src/AppKitFrameProvider.ts | 27 +---
packages/wallet/src/AppKitWebview.tsx | 148 ++++++++++++++++++
packages/wallet/src/index.ts | 2 +-
10 files changed, 258 insertions(+), 50 deletions(-)
create mode 100644 packages/core/src/controllers/WebviewController.ts
create mode 100644 packages/wallet/src/AppKitWebview.tsx
diff --git a/packages/core/src/controllers/WebviewController.ts b/packages/core/src/controllers/WebviewController.ts
new file mode 100644
index 000000000..0c3194899
--- /dev/null
+++ b/packages/core/src/controllers/WebviewController.ts
@@ -0,0 +1,41 @@
+import { proxy, subscribe as sub } from 'valtio';
+
+// -- Types --------------------------------------------- //
+export interface WebviewControllerState {
+ frameViewVisible: boolean;
+ webviewVisible: boolean;
+ webviewUrl?: string;
+ connecting?: boolean;
+}
+
+// -- State --------------------------------------------- //
+const state = proxy({
+ frameViewVisible: false,
+ webviewVisible: false,
+ connecting: false
+});
+
+// -- Controller ---------------------------------------- //
+export const WebviewController = {
+ state,
+
+ subscribe(callback: (newState: WebviewControllerState) => void) {
+ return sub(state, () => callback(state));
+ },
+
+ setFrameViewVisible(frameViewVisible: WebviewControllerState['frameViewVisible']) {
+ state.frameViewVisible = frameViewVisible;
+ },
+
+ setWebviewVisible(visible: WebviewControllerState['webviewVisible']) {
+ state.webviewVisible = visible;
+ },
+
+ setWebviewUrl(url: WebviewControllerState['webviewUrl']) {
+ state.webviewUrl = url;
+ },
+
+ setConnecting(connecting: WebviewControllerState['connecting']) {
+ state.connecting = connecting;
+ }
+};
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 3e0469362..236c2789e 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -56,6 +56,8 @@ export {
export { SendController, type SendControllerState } from './controllers/SendController';
+export { WebviewController, type WebviewControllerState } from './controllers/WebviewController';
+
// -- Utils -------------------------------------------------------------------
export { ApiUtil } from './utils/ApiUtil';
export { AssetUtil } from './utils/AssetUtil';
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 6bade5013..18bf977cb 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -541,4 +541,5 @@ export interface AppKitFrameProvider {
disconnect(): Promise;
request(req: any): Promise;
AuthView: () => JSX.Element | null;
+ Webview: () => JSX.Element | null;
}
diff --git a/packages/scaffold/src/modal/w3m-modal/index.tsx b/packages/scaffold/src/modal/w3m-modal/index.tsx
index c793a71e2..13b93def5 100644
--- a/packages/scaffold/src/modal/w3m-modal/index.tsx
+++ b/packages/scaffold/src/modal/w3m-modal/index.tsx
@@ -15,7 +15,8 @@ import {
RouterController,
TransactionsController,
type CaipAddress,
- type AppKitFrameProvider
+ type AppKitFrameProvider,
+ WebviewController
} from '@reown/appkit-core-react-native';
import { AppKitRouter } from '../w3m-router';
@@ -24,21 +25,19 @@ import { Snackbar } from '../../partials/w3m-snackbar';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
-const viewsAboveModal = ['ConnectingSiwe', 'WalletSendPreview'];
-
export function AppKit() {
const { open, loading } = useSnapshot(ModalController.state);
- const { view: activeView } = useSnapshot(RouterController.state);
const { connectors } = useSnapshot(ConnectorController.state);
const { caipAddress, isConnected } = useSnapshot(AccountController.state);
+ const { frameViewVisible, webviewVisible } = useSnapshot(WebviewController.state);
const { isSiweEnabled } = OptionsController.state;
const { height } = useWindowDimensions();
const { isLandscape } = useCustomDimensions();
const portraitHeight = height - 120;
const landScapeHeight = height * 0.95 - (StatusBar.currentHeight ?? 0);
const authProvider = connectors.find(c => c.type === 'AUTH')?.provider as AppKitFrameProvider;
- const enableCoverScreen = !viewsAboveModal.includes(activeView);
const AuthView = authProvider?.AuthView;
+ const SocialView = authProvider?.Webview;
const onBackButtonPress = () => {
if (RouterController.state.history.length > 1) {
@@ -121,7 +120,7 @@ export function AppKit() {
<>
{!!authProvider && AuthView && }
+ {!!authProvider && SocialView && }
>
);
}
diff --git a/packages/scaffold/src/views/w3m-account-default-view/index.tsx b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
index 7ea67c5f7..1dcee8bc3 100644
--- a/packages/scaffold/src/views/w3m-account-default-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
@@ -174,7 +174,14 @@ export function AccountDefaultView() {
testID="button-email"
style={styles.actionButton}
>
- {getUserEmail()}
+
+ {UiUtil.getTruncateString({
+ string: getUserEmail() || '',
+ charsStart: 30,
+ charsEnd: 0,
+ truncate: 'end'
+ })}
+
>
)}
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
index 849646b55..f23273a15 100644
--- a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
@@ -1,5 +1,12 @@
+import { useSnapshot } from 'valtio';
import { useCallback, useEffect, useState } from 'react';
-import { RouterController } from '@reown/appkit-core-react-native';
+import {
+ ConnectorController,
+ RouterController,
+ SnackController,
+ WebviewController,
+ type AppKitFrameProvider
+} from '@reown/appkit-core-react-native';
import { FlexView, LoadingThumbnail, IconBox, Logo, Text } from '@reown/appkit-ui-react-native';
import { StringUtil } from '@reown/appkit-common-react-native';
@@ -9,10 +16,29 @@ import styles from './styles';
export function ConnectingSocialView() {
const { data } = RouterController.state;
const { maxWidth: width } = useCustomDimensions();
- const [error, setError] = useState();
- const provider = data?.socialProvider;
+ const { connecting } = useSnapshot(WebviewController.state);
+ const authConnector = ConnectorController.getAuthConnector();
+ const [error, setError] = useState(false);
+ const socialProvider = data?.socialProvider;
+ const provider = authConnector?.provider as AppKitFrameProvider;
- const onConnect = useCallback(async () => {}, []);
+ const onConnect = useCallback(async () => {
+ try {
+ if (!WebviewController.state.connecting && provider && socialProvider) {
+ const { uri } = await provider.getSocialRedirectUri({
+ provider: socialProvider
+ });
+ WebviewController.setWebviewUrl(uri);
+ WebviewController.setWebviewVisible(true);
+ WebviewController.setConnecting(true);
+ }
+ } catch (e) {
+ WebviewController.setWebviewVisible(false);
+ WebviewController.setConnecting(false);
+ SnackController.showError('Something went wrong');
+ setError(true);
+ }
+ }, [provider, socialProvider]);
useEffect(() => {
onConnect();
@@ -26,7 +52,7 @@ export function ConnectingSocialView() {
style={{ width }}
>
-
+
{error && (
- {`Continue with ${StringUtil.capitalize(provider)}`}
+ {`Continue with ${StringUtil.capitalize(socialProvider)}`}
- Connect in the provider window
+ {connecting ? 'Connecting...' : 'Connect in the provider window'}
);
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index 307bc76cd..2279e9744 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -9,7 +9,8 @@ import {
ModalController,
type OptionsControllerState,
StorageUtil,
- RouterController
+ RouterController,
+ WebviewController
} from '@reown/appkit-core-react-native';
import { useTheme, BorderRadius } from '@reown/appkit-ui-react-native';
import type { AppKitFrameProvider } from './AppKitFrameProvider';
@@ -22,14 +23,13 @@ const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
export function AuthWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
- const { connectors } = useSnapshot(ConnectorController.state);
+ const authConnector = ConnectorController.getAuthConnector();
const { projectId, sdkVersion } = useSnapshot(OptionsController.state) as OptionsControllerState;
- const [isWebviewVisibile, setIsWebviewVisible] = useState(false);
+ const { frameViewVisible } = useSnapshot(WebviewController.state);
const [isBackdropVisible, setIsBackdropVisible] = useState(false);
const animatedHeight = useRef(new Animated.Value(0));
const backdropOpacity = useRef(new Animated.Value(0));
const webviewOpacity = useRef(new Animated.Value(0));
- const authConnector = connectors.find(c => c.type === 'AUTH');
const provider = authConnector?.provider as AppKitFrameProvider;
const parseMessage = (event: WebViewMessageEvent) => {
@@ -55,7 +55,7 @@ export function AuthWebview() {
provider.onRpcRequest((request: AppKitFrameTypes.RPCRequest) => {
if (AppKitFrameHelpers.checkIfRequestExists(request)) {
if (!AppKitFrameHelpers.checkIfRequestIsAllowed(request)) {
- setIsWebviewVisible(true);
+ WebviewController.setFrameViewVisible(true);
}
}
});
@@ -71,7 +71,7 @@ export function AuthWebview() {
} else {
RouterController?.popTransactionStack();
}
- setIsWebviewVisible(false);
+ WebviewController.setFrameViewVisible(false);
});
provider.onRpcError(() => {
@@ -82,7 +82,7 @@ export function AuthWebview() {
RouterController?.popTransactionStack(true);
}
}
- setIsWebviewVisible(false);
+ WebviewController.setFrameViewVisible(false);
});
provider.onIsConnected(event, () => {
@@ -104,27 +104,27 @@ export function AuthWebview() {
useEffect(() => {
Animated.timing(animatedHeight.current, {
- toValue: isWebviewVisibile ? 1 : 0,
+ toValue: frameViewVisible ? 1 : 0,
duration: 200,
useNativeDriver: false
}).start();
Animated.timing(webviewOpacity.current, {
- toValue: isWebviewVisibile ? 1 : 0,
+ toValue: frameViewVisible ? 1 : 0,
duration: 300,
useNativeDriver: false
}).start();
- if (isWebviewVisibile) {
+ if (frameViewVisible) {
setIsBackdropVisible(true);
}
Animated.timing(backdropOpacity.current, {
- toValue: isWebviewVisibile ? 0.7 : 0,
+ toValue: frameViewVisible ? 0.7 : 0,
duration: 300,
useNativeDriver: false
- }).start(() => setIsBackdropVisible(isWebviewVisibile));
- }, [animatedHeight, backdropOpacity, isWebviewVisibile, setIsBackdropVisible]);
+ }).start(() => setIsBackdropVisible(frameViewVisible));
+ }, [animatedHeight, backdropOpacity, frameViewVisible, setIsBackdropVisible]);
useEffect(() => {
provider?.setWebviewRef(webviewRef);
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index 9feaf02ed..ed135c6e3 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -1,6 +1,6 @@
import { EventEmitter } from 'events';
import type { RefObject } from 'react';
-import type WebView from 'react-native-webview';
+import WebView from 'react-native-webview';
import { CoreHelperUtil } from '@reown/appkit-core-react-native';
import type { AppKitFrameTypes } from './AppKitFrameTypes';
import { AppKitFrameConstants, AppKitFrameRpcConstants } from './AppKitFrameConstants';
@@ -8,6 +8,7 @@ import { AppKitFrameStorage } from './AppKitFrameStorage';
import { AppKitFrameHelpers } from './AppKitFrameHelpers';
import { AppKitFrameSchema } from './AppKitFrameSchema';
import { AuthWebview } from './AppKitAuthWebview';
+import { AppKitWebview } from './AppKitWebview';
// -- Provider --------------------------------------------------------
export class AppKitFrameProvider {
@@ -37,6 +38,8 @@ export class AppKitFrameProvider {
public AuthView = AuthWebview;
+ public Webview = AppKitWebview;
+
private openRpcRequests: Array<
AppKitFrameTypes.RPCRequest & { abortController: AbortController }
> = [];
@@ -60,7 +63,7 @@ export class AppKitFrameProvider {
}
public onMessage(event: AppKitFrameTypes.FrameEvent) {
- // console.log('💻 received', e); // eslint-disable-line no-console
+ // console.log('💻 received', event); // eslint-disable-line no-console
this.events.emit('message', event);
}
@@ -515,23 +518,3 @@ export class AppKitFrameProvider {
return email;
}
}
-
-export interface AppKitFrameProviderMethods {
- // Email
- connectEmail: AppKitFrameProvider['connectEmail'];
- connectOtp: AppKitFrameProvider['connectOtp'];
- updateEmail: AppKitFrameProvider['updateEmail'];
- updateEmailPrimaryOtp: AppKitFrameProvider['updateEmailPrimaryOtp'];
- updateEmailSecondaryOtp: AppKitFrameProvider['updateEmailSecondaryOtp'];
- getEmail: AppKitFrameProvider['getEmail'];
-
- // Social
- connectDevice: AppKitFrameProvider['connectDevice'];
- connectSocial: AppKitFrameProvider['connectSocial'];
- getSocialRedirectUri: AppKitFrameProvider['getSocialRedirectUri'];
-
- // Misc
- syncTheme: AppKitFrameProvider['syncTheme'];
- syncDappData: AppKitFrameProvider['syncDappData'];
- switchNetwork: AppKitFrameProvider['switchNetwork'];
-}
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
new file mode 100644
index 000000000..208967de7
--- /dev/null
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -0,0 +1,148 @@
+import { useSnapshot } from 'valtio';
+import { useEffect, useRef, useState } from 'react';
+import { Animated, SafeAreaView, StyleSheet } from 'react-native';
+import { WebView } from 'react-native-webview';
+
+import {
+ ConnectionController,
+ ConnectorController,
+ ModalController,
+ RouterController,
+ SnackController,
+ WebviewController
+} from '@reown/appkit-core-react-native';
+import { useTheme, BorderRadius, IconLink, Spacing } from '@reown/appkit-ui-react-native';
+import type { AppKitFrameProvider } from './AppKitFrameProvider';
+
+const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
+
+export function AppKitWebview() {
+ const webviewRef = useRef(null);
+ const Theme = useTheme();
+ const authConnector = ConnectorController.getAuthConnector();
+ const { webviewVisible, webviewUrl } = useSnapshot(WebviewController.state);
+ const [isBackdropVisible, setIsBackdropVisible] = useState(false);
+ const animatedHeight = useRef(new Animated.Value(0));
+ const backdropOpacity = useRef(new Animated.Value(0));
+ const webviewOpacity = useRef(new Animated.Value(0));
+ const provider = authConnector?.provider as AppKitFrameProvider;
+
+ const show = animatedHeight.current.interpolate({
+ inputRange: [0, 1],
+ outputRange: ['0%', '80%']
+ });
+
+ const onClose = () => {
+ WebviewController.setWebviewVisible(false);
+ WebviewController.setConnecting(false);
+ RouterController.goBack();
+ };
+
+ useEffect(() => {
+ Animated.timing(animatedHeight.current, {
+ toValue: webviewVisible ? 1 : 0,
+ duration: 200,
+ useNativeDriver: false
+ }).start();
+
+ Animated.timing(webviewOpacity.current, {
+ toValue: webviewVisible ? 1 : 0,
+ duration: 300,
+ useNativeDriver: false
+ }).start(({ finished }) => {
+ if (finished && !webviewVisible) {
+ WebviewController.setWebviewUrl('');
+ }
+ });
+
+ if (webviewVisible) {
+ setIsBackdropVisible(true);
+ }
+
+ Animated.timing(backdropOpacity.current, {
+ toValue: webviewVisible ? 0.7 : 0,
+ duration: 300,
+ useNativeDriver: false
+ }).start(() => setIsBackdropVisible(webviewVisible));
+ }, [animatedHeight, backdropOpacity, webviewVisible, setIsBackdropVisible]);
+
+ if (!webviewUrl) return null;
+
+ return provider ? (
+ <>
+
+
+
+ {
+ try {
+ if (authConnector && navState.url.includes('/sdk/oauth')) {
+ WebviewController.setWebviewVisible(false);
+ const parsedUrl = new URL(navState.url);
+ await provider?.connectSocial(parsedUrl.search);
+ await ConnectionController.connectExternal(authConnector);
+ WebviewController.setConnecting(false);
+ ModalController.close();
+ }
+ } catch (e) {
+ onClose();
+ SnackController.showError('Something went wrong');
+ }
+ }}
+ />
+
+ >
+ ) : null;
+}
+
+const styles = StyleSheet.create({
+ backdrop: {
+ position: 'absolute',
+ width: '100%',
+ height: '100%',
+ top: 0
+ },
+ container: {
+ bottom: 0,
+ position: 'absolute',
+ width: '100%',
+ borderTopLeftRadius: BorderRadius.l,
+ borderTopRightRadius: BorderRadius.l,
+ zIndex: 999
+ },
+ hidden: {
+ display: 'none'
+ },
+ webview: {
+ borderTopLeftRadius: BorderRadius.l,
+ borderTopRightRadius: BorderRadius.l
+ },
+ closeButton: {
+ alignSelf: 'flex-end',
+ margin: Spacing.m
+ }
+});
diff --git a/packages/wallet/src/index.ts b/packages/wallet/src/index.ts
index f77b09495..c2c9f6d54 100644
--- a/packages/wallet/src/index.ts
+++ b/packages/wallet/src/index.ts
@@ -1,5 +1,5 @@
export { AppKitFrameHelpers } from './AppKitFrameHelpers';
-export { AppKitFrameProvider, type AppKitFrameProviderMethods } from './AppKitFrameProvider';
+export { AppKitFrameProvider } from './AppKitFrameProvider';
export { AppKitFrameSchema } from './AppKitFrameSchema';
export { AppKitFrameConstants, AppKitFrameRpcConstants } from './AppKitFrameConstants';
export { AppKitFrameStorage } from './AppKitFrameStorage';
From 6dca48d1162c70f2e27884347a410fa9380d812a Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 30 Sep 2024 10:25:11 -0300
Subject: [PATCH 074/114] chore: removed what is a wallet link
---
packages/scaffold/src/partials/w3m-header/index.tsx | 2 +-
.../src/views/w3m-what-is-a-wallet-view/index.tsx | 13 +++----------
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index 40cee19df..2a9a2dede 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -17,7 +17,7 @@ export function Header() {
const connectorName = data?.connector?.name;
const walletName = data?.wallet?.name;
const networkName = data?.network?.name;
- const socialName = StringUtil.capitalize(data?.socialProvider);
+ const socialName = undefined;
return {
Account: undefined,
diff --git a/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx b/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx
index 92100124a..953af32ce 100644
--- a/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx
@@ -1,5 +1,5 @@
-import { Linking, ScrollView } from 'react-native';
-import { Button, FlexView, Link, Text, Visual } from '@reown/appkit-ui-react-native';
+import { ScrollView } from 'react-native';
+import { Button, FlexView, Text, Visual } from '@reown/appkit-ui-react-native';
import { EventsController, RouterController } from '@reown/appkit-core-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
@@ -12,13 +12,9 @@ export function WhatIsAWalletView() {
EventsController.sendEvent({ type: 'track', event: 'CLICK_GET_WALLET' });
};
- const onHelpPress = () => {
- Linking.openURL('https://secure.walletconnect.com/dashboard/faq');
- };
-
return (
-
+
@@ -60,9 +56,6 @@ export function WhatIsAWalletView() {
>
Get a wallet
-
- What is an email wallet?
-
);
From 3bab13e3206e0a92d73014d437aafdfa4e2edfe0 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 30 Sep 2024 10:34:38 -0300
Subject: [PATCH 075/114] chore: header title change
---
.../src/partials/w3m-header/index.tsx | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index 2a9a2dede..245f3b06c 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -1,23 +1,27 @@
+import { useSnapshot } from 'valtio';
import {
RouterController,
ModalController,
- EventsController
+ EventsController,
+ type RouterControllerState
} from '@reown/appkit-core-react-native';
import { IconLink, Text, FlexView } from '@reown/appkit-ui-react-native';
import { StringUtil } from '@reown/appkit-common-react-native';
export function Header() {
+ const { data, view } = useSnapshot(RouterController.state);
const onHelpPress = () => {
RouterController.push('WhatIsAWallet');
EventsController.sendEvent({ type: 'track', event: 'CLICK_WALLET_HELP' });
};
- const headings = () => {
- const { data } = RouterController.state;
- const connectorName = data?.connector?.name;
- const walletName = data?.wallet?.name;
- const networkName = data?.network?.name;
- const socialName = undefined;
+ const headings = (_data: RouterControllerState['data'], _view: RouterControllerState['view']) => {
+ const connectorName = _data?.connector?.name;
+ const walletName = _data?.wallet?.name;
+ const networkName = _data?.network?.name;
+ const socialName = _data?.socialProvider
+ ? StringUtil.capitalize(_data?.socialProvider)
+ : undefined;
return {
Account: undefined,
@@ -45,10 +49,10 @@ export function Header() {
WalletSendSelectToken: 'Select token',
WhatIsANetwork: 'What is a network?',
WhatIsAWallet: 'What is a wallet?'
- };
+ }[_view];
};
- const header = headings()[RouterController.state.view];
+ const header = headings(data, view);
const dynamicButtonTemplate = () => {
const hideBackViews = ['ConnectingSiwe'];
From 1204ead13bf1797d47e6d3eee235171e2bc58232 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 30 Sep 2024 15:55:06 -0300
Subject: [PATCH 076/114] chore: added farcaster
---
apps/gallery/utils/PresetUtils.ts | 3 +
packages/common/src/utils/TypeUtil.ts | 9 ++-
.../core/src/controllers/RouterController.ts | 2 +
packages/core/src/utils/ConstantsUtil.ts | 2 +-
packages/core/src/utils/TypeUtil.ts | 2 +
.../scaffold/src/modal/w3m-router/index.tsx | 6 ++
.../src/partials/w3m-header/index.tsx | 2 +
.../views/w3m-connect-socials-view/index.tsx | 41 ++++++++++
.../views/w3m-connect-socials-view/styles.ts | 12 +++
.../components/social-login-list.tsx | 11 ++-
.../w3m-connecting-farcaster-view/index.tsx | 75 +++++++++++++++++++
.../w3m-connecting-farcaster-view/styles.ts | 15 ++++
packages/ui/src/assets/svg/Farcaster.tsx | 15 ++++
.../ui/src/assets/svg/FarcasterSquare.tsx | 15 ++++
packages/ui/src/components/wui-icon/index.tsx | 4 +
.../ui/src/composites/wui-qr-code/index.tsx | 6 +-
packages/ui/src/utils/TypesUtil.ts | 4 +
packages/wallet/src/AppKitFrameConstants.ts | 6 ++
packages/wallet/src/AppKitFrameProvider.ts | 28 +++++++
packages/wallet/src/AppKitFrameSchema.ts | 46 +++++++++++-
packages/wallet/src/AppKitFrameTypes.ts | 8 +-
21 files changed, 305 insertions(+), 7 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-connect-socials-view/styles.ts
create mode 100644 packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts
create mode 100644 packages/ui/src/assets/svg/Farcaster.tsx
create mode 100644 packages/ui/src/assets/svg/FarcasterSquare.tsx
diff --git a/apps/gallery/utils/PresetUtils.ts b/apps/gallery/utils/PresetUtils.ts
index 8c36e3aea..b792514e9 100644
--- a/apps/gallery/utils/PresetUtils.ts
+++ b/apps/gallery/utils/PresetUtils.ts
@@ -149,6 +149,8 @@ export const iconOptions: IconType[] = [
'extension',
'externalLink',
'facebook',
+ 'farcaster',
+ 'farcasterSquare',
'filters',
'github',
'google',
@@ -194,6 +196,7 @@ export const logoOptions: LogoType[] = [
'apple',
'discord',
'facebook',
+ 'farcaster',
'github',
'google',
'more',
diff --git a/packages/common/src/utils/TypeUtil.ts b/packages/common/src/utils/TypeUtil.ts
index 1539688f1..ba09aaa26 100644
--- a/packages/common/src/utils/TypeUtil.ts
+++ b/packages/common/src/utils/TypeUtil.ts
@@ -86,4 +86,11 @@ export interface TransactionQuantity {
numeric: string;
}
-export type SocialProvider = 'google' | 'github' | 'apple' | 'facebook' | 'x' | 'discord';
+export type SocialProvider =
+ | 'google'
+ | 'github'
+ | 'apple'
+ | 'facebook'
+ | 'x'
+ | 'discord'
+ | 'farcaster';
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index adcdbbe41..7fbbd8513 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -18,9 +18,11 @@ export interface RouterControllerState {
| 'AccountDefault'
| 'AllWallets'
| 'Connect'
+ | 'ConnectSocials'
| 'ConnectingExternal'
| 'ConnectingSiwe'
| 'ConnectingSocial'
+ | 'ConnectingFarcaster'
| 'ConnectingWalletConnect'
| 'EmailVerifyDevice'
| 'EmailVerifyOtp'
diff --git a/packages/core/src/utils/ConstantsUtil.ts b/packages/core/src/utils/ConstantsUtil.ts
index b3396ecea..a4f7ea25f 100644
--- a/packages/core/src/utils/ConstantsUtil.ts
+++ b/packages/core/src/utils/ConstantsUtil.ts
@@ -3,7 +3,7 @@ import type { Features } from './TypeUtil';
const defaultFeatures: Features = {
email: true,
emailShowWallets: true,
- socials: ['x', 'discord', 'github', 'apple', 'facebook']
+ socials: ['x', 'discord', 'github', 'apple', 'facebook', 'farcaster']
};
export const ConstantsUtil = {
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 18bf977cb..3837bd3ca 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -508,6 +508,8 @@ export interface AppKitFrameProvider {
uri: string;
}>;
connectOtp(payload: { otp: string }): Promise;
+ connectFarcaster: () => Promise<{ username: string }>;
+ getFarcasterUri(): Promise<{ url: string }>;
isConnected(): Promise<{
isConnected: boolean;
}>;
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index 5ae5df623..325a07f3e 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -29,6 +29,8 @@ import { WhatIsANetworkView } from '../../views/w3m-what-is-a-network-view';
import { WhatIsAWalletView } from '../../views/w3m-what-is-a-wallet-view';
import { UiUtil } from '../../utils/UiUtil';
+import { ConnectingFarcasterView } from '../../views/w3m-connecting-farcaster-view';
+import { ConnectSocialsView } from '../../views/w3m-connect-socials-view';
export function AppKitRouter() {
const { view } = useSnapshot(RouterController.state);
@@ -47,12 +49,16 @@ export function AppKitRouter() {
return AllWalletsView;
case 'Connect':
return ConnectView;
+ case 'ConnectSocials':
+ return ConnectSocialsView;
case 'ConnectingExternal':
return ConnectingExternalView;
case 'ConnectingSiwe':
return ConnectingSiweView;
case 'ConnectingSocial':
return ConnectingSocialView;
+ case 'ConnectingFarcaster':
+ return ConnectingFarcasterView;
case 'ConnectingWalletConnect':
return ConnectingView;
case 'EmailVerifyDevice':
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index 245f3b06c..49cddef65 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -28,8 +28,10 @@ export function Header() {
AccountDefault: undefined,
AllWallets: 'All wallets',
Connect: 'Connect wallet',
+ ConnectSocials: 'All socials',
ConnectingExternal: connectorName ?? 'Connect wallet',
ConnectingSiwe: 'Sign In',
+ ConnectingFarcaster: socialName ?? 'Connecting Social',
ConnectingSocial: socialName ?? 'Connecting Social',
ConnectingWalletConnect: walletName ?? 'WalletConnect',
EmailVerifyDevice: ' ',
diff --git a/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx b/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
new file mode 100644
index 000000000..d5aecad29
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
@@ -0,0 +1,41 @@
+import { useSnapshot } from 'valtio';
+import { ScrollView } from 'react-native';
+import { StringUtil, type SocialProvider } from '@reown/appkit-common-react-native';
+import { OptionsController, RouterController } from '@reown/appkit-core-react-native';
+import { FlexView, ListSocial, Text } from '@reown/appkit-ui-react-native';
+
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import styles from './styles';
+
+export function ConnectSocialsView() {
+ const { features } = useSnapshot(OptionsController.state);
+ const { padding } = useCustomDimensions();
+ const socialProviders = (features?.socials ?? []) as SocialProvider[];
+
+ const onItemPress = (provider: SocialProvider) => {
+ if (provider === 'farcaster') {
+ RouterController.push('ConnectingFarcaster', { socialProvider: provider });
+ } else {
+ RouterController.push('ConnectingSocial', { socialProvider: provider });
+ }
+ };
+
+ return (
+
+
+ {socialProviders.map(provider => (
+ onItemPress(provider)}
+ style={styles.item}
+ >
+
+ {StringUtil.capitalize(provider)}
+
+
+ ))}
+
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-connect-socials-view/styles.ts b/packages/scaffold/src/views/w3m-connect-socials-view/styles.ts
new file mode 100644
index 000000000..be837b83c
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connect-socials-view/styles.ts
@@ -0,0 +1,12 @@
+import { StyleSheet } from 'react-native';
+import { Spacing } from '@reown/appkit-ui-react-native';
+
+export default StyleSheet.create({
+ item: {
+ marginVertical: Spacing['3xs'],
+ justifyContent: 'flex-start'
+ },
+ text: {
+ marginLeft: Spacing.s
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
index bf9c0189d..8af95e8f1 100644
--- a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
@@ -18,7 +18,15 @@ export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
bottomSocials = showMoreButton ? bottomSocials.slice(0, MAX_OPTIONS - 2) : bottomSocials;
const onItemPress = (social: SocialProvider) => {
- RouterController.push('ConnectingSocial', { socialProvider: social });
+ if (social === 'farcaster') {
+ RouterController.push('ConnectingFarcaster', { socialProvider: social });
+ } else {
+ RouterController.push('ConnectingSocial', { socialProvider: social });
+ }
+ };
+
+ const onMorePress = () => {
+ RouterController.push('ConnectSocials');
};
return (
@@ -49,6 +57,7 @@ export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
logo="more"
disabled={disabled}
style={[styles.socialItem, styles.socialItemLast]}
+ onPress={onMorePress}
/>
)}
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
new file mode 100644
index 000000000..9f4dc02ee
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
@@ -0,0 +1,75 @@
+import { Linking } from 'react-native';
+import { useCallback, useEffect, useState } from 'react';
+import {
+ ConnectionController,
+ ConnectorController,
+ ModalController,
+ RouterController,
+ SnackController,
+ WebviewController,
+ type AppKitFrameProvider
+} from '@reown/appkit-core-react-native';
+import { FlexView, LoadingThumbnail, IconBox, Logo, Text } from '@reown/appkit-ui-react-native';
+import { StringUtil } from '@reown/appkit-common-react-native';
+
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import styles from './styles';
+
+export function ConnectingFarcasterView() {
+ const { data } = RouterController.state;
+ const { maxWidth: width } = useCustomDimensions();
+ const authConnector = ConnectorController.getAuthConnector();
+ const [error, setError] = useState(false);
+ const socialProvider = data?.socialProvider;
+ const provider = authConnector?.provider as AppKitFrameProvider;
+
+ const onConnect = useCallback(async () => {
+ try {
+ if (!WebviewController.state.connecting && provider && socialProvider && authConnector) {
+ setError(false);
+ const { url } = await provider.getFarcasterUri();
+ await Linking.openURL(url);
+ await provider.connectFarcaster();
+ await ConnectionController.connectExternal(authConnector);
+ WebviewController.setConnecting(false);
+ ModalController.close();
+ }
+ } catch (e) {
+ SnackController.showError('Something went wrong');
+ setError(true);
+ }
+ }, [provider, socialProvider, authConnector]);
+
+ useEffect(() => {
+ onConnect();
+ }, [onConnect]);
+
+ return (
+
+ <>
+
+
+ {error && (
+
+ )}
+
+
+ {`Continue with ${StringUtil.capitalize(socialProvider)}`}
+
+ >
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts b/packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts
new file mode 100644
index 000000000..dcb555e83
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts
@@ -0,0 +1,15 @@
+import { StyleSheet } from 'react-native';
+import { Spacing } from '@reown/appkit-ui-react-native';
+
+export default StyleSheet.create({
+ errorIcon: {
+ position: 'absolute',
+ bottom: 8,
+ right: 8,
+ zIndex: 2
+ },
+ continueText: {
+ marginTop: Spacing.m,
+ marginBottom: Spacing.xs
+ }
+});
diff --git a/packages/ui/src/assets/svg/Farcaster.tsx b/packages/ui/src/assets/svg/Farcaster.tsx
new file mode 100644
index 000000000..323478cca
--- /dev/null
+++ b/packages/ui/src/assets/svg/Farcaster.tsx
@@ -0,0 +1,15 @@
+import Svg, { Path, type SvgProps, Rect } from 'react-native-svg';
+const SvgFarcaster = (props: SvgProps) => (
+
+
+
+
+
+);
+export default SvgFarcaster;
diff --git a/packages/ui/src/assets/svg/FarcasterSquare.tsx b/packages/ui/src/assets/svg/FarcasterSquare.tsx
new file mode 100644
index 000000000..e6b7062b0
--- /dev/null
+++ b/packages/ui/src/assets/svg/FarcasterSquare.tsx
@@ -0,0 +1,15 @@
+import Svg, { Path, type SvgProps, Rect } from 'react-native-svg';
+const SvgFarcaster = (props: SvgProps) => (
+
+
+
+
+
+);
+export default SvgFarcaster;
diff --git a/packages/ui/src/components/wui-icon/index.tsx b/packages/ui/src/components/wui-icon/index.tsx
index 11540ab21..7b1656e9a 100644
--- a/packages/ui/src/components/wui-icon/index.tsx
+++ b/packages/ui/src/components/wui-icon/index.tsx
@@ -30,6 +30,8 @@ import EtherscanSvg from '../../assets/svg/Etherscan';
import ExtensionSvg from '../../assets/svg/Extension';
import ExternalLinkSvg from '../../assets/svg/ExternalLink';
import FacebookSvg from '../../assets/svg/Facebook';
+import FarcasterSvg from '../../assets/svg/Farcaster';
+import FarcasterSquareSvg from '../../assets/svg/FarcasterSquare';
import FiltersSvg from '../../assets/svg/Filters';
import GithubSvg from '../../assets/svg/Github';
import GoogleSvg from '../../assets/svg/Google';
@@ -88,6 +90,8 @@ const svgOptions: Record JSX.Element> = {
extension: ExtensionSvg,
externalLink: ExternalLinkSvg,
facebook: FacebookSvg,
+ farcaster: FarcasterSvg,
+ farcasterSquare: FarcasterSquareSvg,
filters: FiltersSvg,
github: GithubSvg,
google: GoogleSvg,
diff --git a/packages/ui/src/composites/wui-qr-code/index.tsx b/packages/ui/src/composites/wui-qr-code/index.tsx
index f65ee57ff..8f49da5e2 100644
--- a/packages/ui/src/composites/wui-qr-code/index.tsx
+++ b/packages/ui/src/composites/wui-qr-code/index.tsx
@@ -8,18 +8,20 @@ import { Text } from '../../components/wui-text';
import { FlexView } from '../../layout/wui-flex';
import { QRCodeUtil } from '../../utils/QRCodeUtil';
import { BorderRadius, LightTheme, Spacing } from '../../utils/ThemeUtil';
+import type { IconType } from '../../utils/TypesUtil';
import styles from './styles';
export interface QrCodeProps {
size: number;
uri?: string;
imageSrc?: string;
+ icon?: IconType;
testID?: string;
arenaClear?: boolean;
style?: StyleProp;
}
-export function QrCode({ size, uri, imageSrc, testID, arenaClear, style }: QrCodeProps) {
+export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }: QrCodeProps) {
const Theme = LightTheme;
const containerPadding = Spacing.l;
const qrSize = size - containerPadding * 2;
@@ -49,7 +51,7 @@ export function QrCode({ size, uri, imageSrc, testID, arenaClear, style }: QrCod
return (
({
+ type: AppKitFrameConstants.APP_GET_FARCASTER_URI
+ } as AppKitFrameTypes.AppEvent);
+
+ return response;
+ } catch (error) {
+ throw error;
+ }
+ }
+
+ public async connectFarcaster() {
+ try {
+ const response = await this.appEvent<'ConnectFarcaster'>({
+ type: AppKitFrameConstants.APP_CONNECT_FARCASTER
+ } as AppKitFrameTypes.AppEvent);
+
+ if (response.userName) {
+ this.setSocialLoginSuccess(response.userName);
+ }
+
+ return response;
+ } catch (error) {
+ throw error;
+ }
+ }
+
public async connectOtp(payload: AppKitFrameTypes.Requests['AppConnectOtpRequest']) {
await this.webviewLoadPromise;
diff --git a/packages/wallet/src/AppKitFrameSchema.ts b/packages/wallet/src/AppKitFrameSchema.ts
index f66e4c066..70c15c36c 100644
--- a/packages/wallet/src/AppKitFrameSchema.ts
+++ b/packages/wallet/src/AppKitFrameSchema.ts
@@ -34,7 +34,7 @@ export const AppConnectEmailRequest = z.object({ email: z.string().email() });
export const AppConnectOtpRequest = z.object({ otp: z.string() });
export const AppConnectSocialRequest = z.object({ uri: z.string() });
export const AppGetSocialRedirectUriRequest = z.object({
- provider: z.enum(['google', 'github', 'apple', 'facebook', 'x', 'discord'])
+ provider: z.enum(['google', 'github', 'apple', 'facebook', 'x', 'discord', 'farcaster'])
});
export const AppGetUserRequest = z.object({ chainId: z.optional(z.string().or(z.number())) });
export const AppUpdateEmailRequest = z.object({ email: z.string().email() });
@@ -98,6 +98,14 @@ export const FrameConnectSocialResponse = z.object({
userName: z.string().optional()
});
+export const FrameGetFarcasterUriResponse = z.object({
+ url: z.string()
+});
+
+export const FrameConnectFarcasterResponse = z.object({
+ userName: z.string()
+});
+
export const RpcResponse = z.any();
export const RpcEthAccountsRequest = z.object({
@@ -316,6 +324,10 @@ export const AppKitFrameSchema = {
})
)
+ .or(EventSchema.extend({ type: zType('APP_GET_FARCASTER_URI') }))
+
+ .or(EventSchema.extend({ type: zType('APP_CONNECT_FARCASTER') }))
+
.or(EventSchema.extend({ type: zType('APP_SIGN_OUT') }))
.or(EventSchema.extend({ type: zType('APP_IS_CONNECTED'), payload: z.optional(FrameSession) }))
@@ -450,6 +462,38 @@ export const AppKitFrameSchema = {
})
)
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_FARCASTER_URI_SUCCESS'),
+ payload: FrameGetFarcasterUriResponse,
+ origin: z.string()
+ })
+ )
+
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_FARCASTER_URI_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
+
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_CONNECT_FARCASTER_SUCCESS'),
+ payload: FrameConnectFarcasterResponse,
+ origin: z.string()
+ })
+ )
+
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_CONNECT_FARCASTER_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
+
.or(EventSchema.extend({ type: zType('FRAME_CONNECT_DEVICE_SUCCESS'), origin: z.string() }))
.or(
diff --git a/packages/wallet/src/AppKitFrameTypes.ts b/packages/wallet/src/AppKitFrameTypes.ts
index 79a74cf7a..c4e4104e3 100644
--- a/packages/wallet/src/AppKitFrameTypes.ts
+++ b/packages/wallet/src/AppKitFrameTypes.ts
@@ -59,7 +59,9 @@ import {
FrameGetSocialRedirectUriResponse,
FrameConnectSocialResponse,
AppGetSocialRedirectUriRequest,
- AppConnectSocialRequest
+ AppConnectSocialRequest,
+ FrameGetFarcasterUriResponse,
+ FrameConnectFarcasterResponse
} from './AppKitFrameSchema';
export namespace AppKitFrameTypes {
@@ -91,6 +93,8 @@ export namespace AppKitFrameTypes {
FrameConnectOtpResponse: undefined;
FrameGetSocialRedirectUriResponse: z.infer;
FrameConnectSocialResponse: z.infer;
+ FrameGetFarcasterUriResponse: z.infer;
+ FrameConnectFarcasterResponse: z.infer;
FrameSyncThemeResponse: undefined;
FrameSyncDappDataResponse: undefined;
FrameUpdateEmailPrimaryOtpResponse: undefined;
@@ -159,8 +163,10 @@ export namespace AppKitFrameTypes {
| 'GetUser'
| 'ConnectDevice'
| 'ConnectEmail'
+ | 'ConnectFarcaster'
| 'ConnectSocial'
| 'ConnectOtp'
+ | 'GetFarcasterUri'
| 'GetSocialRedirectUri'
| 'SwitchNetwork'
| 'UpdateEmail'
From c4a60d2ab7e1a7e59123cb7fa7e762ccbedd240f Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 30 Sep 2024 18:27:06 -0300
Subject: [PATCH 077/114] chore: show username in account view
---
.../controllers/OptionsController.test.ts | 5 +-
.../src/controllers/ConnectionController.ts | 12 ++++
.../core/src/controllers/WebviewController.ts | 9 ++-
packages/core/src/utils/StorageUtil.ts | 30 +++++++++
packages/core/src/utils/TypeUtil.ts | 2 +-
packages/scaffold/src/client.ts | 6 ++
.../components/auth-buttons.tsx | 61 +++++++++++++++++++
.../views/w3m-account-default-view/index.tsx | 43 +++++++------
.../w3m-connecting-farcaster-view/index.tsx | 1 +
.../w3m-connecting-social-view/index.tsx | 3 +
.../src/composites/wui-list-social/index.tsx | 27 +++++++-
.../src/composites/wui-list-social/styles.ts | 6 ++
packages/wallet/src/AppKitFrameProvider.ts | 30 ++++++---
packages/wallet/src/AppKitWebview.tsx | 4 +-
14 files changed, 203 insertions(+), 36 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-account-default-view/components/auth-buttons.tsx
diff --git a/packages/core/src/__tests__/controllers/OptionsController.test.ts b/packages/core/src/__tests__/controllers/OptionsController.test.ts
index cdcba49d6..712d52c65 100644
--- a/packages/core/src/__tests__/controllers/OptionsController.test.ts
+++ b/packages/core/src/__tests__/controllers/OptionsController.test.ts
@@ -1,4 +1,4 @@
-import { OptionsController } from '../../index';
+import { ConstantsUtil, OptionsController } from '../../index';
const MOCK_WALLET_IDS = [
'1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369',
@@ -15,7 +15,8 @@ describe('OptionsController', () => {
expect(OptionsController.state).toEqual({
projectId: '',
sdkType: 'appkit',
- sdkVersion: 'react-native-wagmi-undefined'
+ sdkVersion: 'react-native-wagmi-undefined',
+ features: ConstantsUtil.DEFAULT_FEATURES
});
});
diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts
index 62faa4539..18255554a 100644
--- a/packages/core/src/controllers/ConnectionController.ts
+++ b/packages/core/src/controllers/ConnectionController.ts
@@ -10,6 +10,7 @@ import type {
} from '../utils/TypeUtil';
import { RouterController } from './RouterController';
import { ConnectorController } from './ConnectorController';
+import type { SocialProvider } from '@reown/appkit-common-react-native';
// -- Types --------------------------------------------- //
export interface ConnectExternalOptions {
@@ -48,6 +49,7 @@ export interface ConnectionControllerState {
pressedWallet?: WcWallet;
recentWallets?: WcWallet[];
connectedWalletImageUrl?: string;
+ connectedSocialProvider?: SocialProvider;
}
type StateKey = keyof ConnectionControllerState;
@@ -133,6 +135,16 @@ export const ConnectionController = {
}
},
+ setConnectedSocialProvider(provider: ConnectionControllerState['connectedSocialProvider']) {
+ state.connectedSocialProvider = provider;
+
+ if (provider) {
+ StorageUtil.setConnectedSocialProvider(provider);
+ } else {
+ StorageUtil.removeConnectedSocialProvider();
+ }
+ },
+
parseUnits(value: string, decimals: number) {
return this._getClient().parseUnits(value, decimals);
},
diff --git a/packages/core/src/controllers/WebviewController.ts b/packages/core/src/controllers/WebviewController.ts
index 0c3194899..f11cf7f66 100644
--- a/packages/core/src/controllers/WebviewController.ts
+++ b/packages/core/src/controllers/WebviewController.ts
@@ -1,3 +1,4 @@
+import type { SocialProvider } from '@reown/appkit-common-react-native';
import { proxy, subscribe as sub } from 'valtio';
// -- Types --------------------------------------------- //
@@ -6,13 +7,15 @@ export interface WebviewControllerState {
webviewVisible: boolean;
webviewUrl?: string;
connecting?: boolean;
+ connectingProvider?: SocialProvider;
}
// -- State --------------------------------------------- //
const state = proxy({
frameViewVisible: false,
webviewVisible: false,
- connecting: false
+ connecting: false,
+ connectingProvider: undefined
});
// -- Controller ---------------------------------------- //
@@ -37,5 +40,9 @@ export const WebviewController = {
setConnecting(connecting: WebviewControllerState['connecting']) {
state.connecting = connecting;
+ },
+
+ setConnectingProvider(provider: WebviewControllerState['connectingProvider']) {
+ state.connectingProvider = provider;
}
};
diff --git a/packages/core/src/utils/StorageUtil.ts b/packages/core/src/utils/StorageUtil.ts
index 36ae23a69..6bf3218d2 100644
--- a/packages/core/src/utils/StorageUtil.ts
+++ b/packages/core/src/utils/StorageUtil.ts
@@ -1,12 +1,14 @@
/* eslint-disable no-console */
import AsyncStorage from '@react-native-async-storage/async-storage';
import type { ConnectorType, WcWallet } from './TypeUtil';
+import type { SocialProvider } from '@reown/appkit-common-react-native';
// -- Helpers -----------------------------------------------------------------
const WC_DEEPLINK = 'WALLETCONNECT_DEEPLINK_CHOICE';
const RECENT_WALLET = '@w3m/recent';
const CONNECTED_WALLET_IMAGE_URL = '@w3m/connected_wallet_image_url';
const CONNECTED_CONNECTOR = '@w3m/connected_connector';
+const CONNECTED_SOCIAL = '@appkit/connected_social';
// -- Utility -----------------------------------------------------------------
export const StorageUtil = {
@@ -134,5 +136,33 @@ export const StorageUtil = {
} catch {
console.info('Unable to remove Connected Wallet Image URL');
}
+ },
+
+ async setConnectedSocialProvider(provider: SocialProvider) {
+ try {
+ await AsyncStorage.setItem(CONNECTED_SOCIAL, JSON.stringify(provider));
+ } catch {
+ console.info('Unable to set Connected Social Provider');
+ }
+ },
+
+ async getConnectedSocialProvider() {
+ try {
+ const provider = (await AsyncStorage.getItem(CONNECTED_SOCIAL)) as SocialProvider;
+
+ return provider ? JSON.parse(provider) : undefined;
+ } catch {
+ console.info('Unable to get Connected Social Provider');
+ }
+
+ return undefined;
+ },
+
+ async removeConnectedSocialProvider() {
+ try {
+ await AsyncStorage.removeItem(CONNECTED_SOCIAL);
+ } catch {
+ console.info('Unable to remove Connected Social Provider');
+ }
}
};
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 3837bd3ca..84d96f1f3 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -485,8 +485,8 @@ export interface AppKitFrameProvider {
getSecureSiteDashboardURL(): string;
getSecureSiteIconURL(): string;
getSecureSiteHeaders(): Record;
- getLoginEmailUsed(): Promise;
getEmail(): string | undefined;
+ getUsername(): string | undefined;
rejectRpcRequest(): void;
connectEmail(payload: { email: string }): Promise<{
action: 'VERIFY_DEVICE' | 'VERIFY_OTP';
diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts
index e51a234ed..0878c85df 100644
--- a/packages/scaffold/src/client.ts
+++ b/packages/scaffold/src/client.ts
@@ -315,8 +315,14 @@ export class AppKitScaffold {
}
}
+ private async initSocial() {
+ const connectedSocialProvider = await StorageUtil.getConnectedSocialProvider();
+ ConnectionController.setConnectedSocialProvider(connectedSocialProvider);
+ }
+
private async initAsyncValues(options: ScaffoldOptions) {
await this.initConnectedConnector();
await this.initRecentWallets(options);
+ await this.initSocial();
}
}
diff --git a/packages/scaffold/src/views/w3m-account-default-view/components/auth-buttons.tsx b/packages/scaffold/src/views/w3m-account-default-view/components/auth-buttons.tsx
new file mode 100644
index 000000000..7a1d903b2
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-account-default-view/components/auth-buttons.tsx
@@ -0,0 +1,61 @@
+import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
+import { UpgradeWalletButton } from './upgrade-wallet-button';
+import { ListItem, ListSocial, Spacing, Text } from '@reown/appkit-ui-react-native';
+import type { SocialProvider } from '@reown/appkit-common-react-native';
+
+export interface AuthButtonsProps {
+ onUpgradePress: () => void;
+ onPress: () => void;
+ socialProvider?: SocialProvider;
+ text: string;
+ style?: StyleProp;
+}
+
+export function AuthButtons({
+ onUpgradePress,
+ onPress,
+ socialProvider,
+ text,
+ style
+}: AuthButtonsProps) {
+ return (
+ <>
+
+ {socialProvider ? (
+
+
+ {text}
+
+
+ ) : (
+
+
+ {text}
+
+
+ )}
+ >
+ );
+}
+
+const styles = StyleSheet.create({
+ actionButton: {
+ marginBottom: Spacing.xs
+ },
+ upgradeButton: {
+ marginBottom: Spacing.s
+ },
+ socialContainer: {
+ justifyContent: 'flex-start',
+ width: '100%'
+ },
+ socialText: {
+ flex: 1,
+ marginLeft: Spacing.s
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-account-default-view/index.tsx b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
index 1dcee8bc3..b3e6805dc 100644
--- a/packages/scaffold/src/views/w3m-account-default-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
@@ -27,8 +27,9 @@ import {
ListItem
} from '@reown/appkit-ui-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
-import { UpgradeWalletButton } from './components/upgrade-wallet-button';
+
import styles from './styles';
+import { AuthButtons } from './components/auth-buttons';
export function AccountDefaultView() {
const { address, profileName, profileImage, balance, balanceSymbol, addressExplorerUrl } =
@@ -36,6 +37,7 @@ export function AccountDefaultView() {
const [disconnecting, setDisconnecting] = useState(false);
const { caipNetwork } = useSnapshot(NetworkController.state);
const { connectedConnector } = useSnapshot(ConnectorController.state);
+ const { connectedSocialProvider } = useSnapshot(ConnectionController.state);
const { history } = useSnapshot(RouterController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
const showCopy = OptionsController.isClipboardAvailable();
@@ -71,6 +73,13 @@ export function AccountDefaultView() {
return provider.getEmail();
};
+ const getUsername = () => {
+ const provider = ConnectorController.getAuthConnector()?.provider as AppKitFrameProvider;
+ if (!provider) return '';
+
+ return provider.getUsername();
+ };
+
const onExplorerPress = () => {
if (AccountController.state.addressExplorerUrl) {
Linking.openURL(AccountController.state.addressExplorerUrl);
@@ -108,6 +117,7 @@ export function AccountDefaultView() {
};
const onEmailPress = () => {
+ if (ConnectionController.state.connectedSocialProvider) return;
RouterController.push('UpdateEmailWallet', { email: getUserEmail() });
};
@@ -165,25 +175,18 @@ export function AccountDefaultView() {
)}
{isAuth && (
- <>
-
-
-
- {UiUtil.getTruncateString({
- string: getUserEmail() || '',
- charsStart: 30,
- charsEnd: 0,
- truncate: 'end'
- })}
-
-
- >
+
)}
void;
style?: StyleProp;
testID?: string;
+ logoWidth?: number;
+ logoHeight?: number;
}
-export function ListSocial({ logo, children, disabled, onPress, style, testID }: ListSocialProps) {
+export function ListSocial({
+ logo,
+ children,
+ disabled,
+ onPress,
+ style,
+ testID,
+ logoHeight = 40,
+ logoWidth = 40
+}: ListSocialProps) {
const Theme = useTheme();
const { animatedValue, setStartValue, setEndValue } = useAnimatedValue(
Theme['gray-glass-002'],
@@ -34,7 +45,19 @@ export function ListSocial({ logo, children, disabled, onPress, style, testID }:
onPressOut={setStartValue}
testID={testID}
>
-
+
+
+
{children}
diff --git a/packages/ui/src/composites/wui-list-social/styles.ts b/packages/ui/src/composites/wui-list-social/styles.ts
index 46eaad088..83d6f63c3 100644
--- a/packages/ui/src/composites/wui-list-social/styles.ts
+++ b/packages/ui/src/composites/wui-list-social/styles.ts
@@ -18,5 +18,11 @@ export default StyleSheet.create({
},
disabledLogo: {
opacity: 0.4
+ },
+ border: {
+ borderRadius: BorderRadius.full,
+ borderWidth: 2,
+ alignItems: 'center',
+ justifyContent: 'center'
}
});
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index d7f2ea32e..5ec259a74 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -20,6 +20,8 @@ export class AppKitFrameProvider {
private email: string | undefined;
+ private username: string | undefined;
+
private rpcRequestHandler?: (request: AppKitFrameTypes.RPCRequest) => void;
private rpcSuccessHandler?: (
response: AppKitFrameTypes.RPCResponse,
@@ -56,6 +58,10 @@ export class AppKitFrameProvider {
this.getAsyncEmail().then(email => {
this.email = email;
});
+
+ this.getAsyncUsername().then(username => {
+ this.username = username;
+ });
}
public setWebviewRef(webviewRef: RefObject) {
@@ -92,16 +98,14 @@ export class AppKitFrameProvider {
return { 'X-Bundle-Id': CoreHelperUtil.getBundleId() };
}
- public async getLoginEmailUsed() {
- const email = await AppKitFrameStorage.get(AppKitFrameConstants.EMAIL_LOGIN_USED_KEY);
-
- return Boolean(email);
- }
-
public getEmail() {
return this.email;
}
+ public getUsername() {
+ return this.username;
+ }
+
public rejectRpcRequest() {
try {
this.openRpcRequests.forEach(({ abortController, method }) => {
@@ -202,7 +206,7 @@ export class AppKitFrameProvider {
} as AppKitFrameTypes.AppEvent);
if (!response.isConnected) {
- this.deleteEmailLoginCache();
+ this.deleteLoginCache();
}
return response;
@@ -335,7 +339,7 @@ export class AppKitFrameProvider {
type: AppKitFrameConstants.APP_SIGN_OUT
});
- this.deleteEmailLoginCache();
+ this.deleteLoginCache();
return response;
}
@@ -411,6 +415,7 @@ export class AppKitFrameProvider {
private setSocialLoginSuccess(username: string) {
AppKitFrameStorage.set(AppKitFrameConstants.SOCIAL_USERNAME, username);
+ this.username = username;
}
private setEmailLoginSuccess(email: string) {
@@ -420,12 +425,13 @@ export class AppKitFrameProvider {
this.email = email;
}
- private deleteEmailLoginCache() {
+ private deleteLoginCache() {
AppKitFrameStorage.delete(AppKitFrameConstants.EMAIL_LOGIN_USED_KEY);
AppKitFrameStorage.delete(AppKitFrameConstants.EMAIL);
AppKitFrameStorage.delete(AppKitFrameConstants.LAST_USED_CHAIN_KEY);
AppKitFrameStorage.delete(AppKitFrameConstants.SOCIAL_USERNAME);
this.email = undefined;
+ this.username = undefined;
}
private setLastUsedChainId(chainId: number) {
@@ -545,4 +551,10 @@ export class AppKitFrameProvider {
return email;
}
+
+ private async getAsyncUsername() {
+ const username = await AppKitFrameStorage.get(AppKitFrameConstants.SOCIAL_USERNAME);
+
+ return username;
+ }
}
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index 208967de7..e6e6046a6 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -20,7 +20,7 @@ export function AppKitWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
const authConnector = ConnectorController.getAuthConnector();
- const { webviewVisible, webviewUrl } = useSnapshot(WebviewController.state);
+ const { webviewVisible, webviewUrl, connectingProvider } = useSnapshot(WebviewController.state);
const [isBackdropVisible, setIsBackdropVisible] = useState(false);
const animatedHeight = useRef(new Animated.Value(0));
const backdropOpacity = useRef(new Animated.Value(0));
@@ -35,6 +35,7 @@ export function AppKitWebview() {
const onClose = () => {
WebviewController.setWebviewVisible(false);
WebviewController.setConnecting(false);
+ WebviewController.setConnectingProvider(undefined);
RouterController.goBack();
};
@@ -105,6 +106,7 @@ export function AppKitWebview() {
const parsedUrl = new URL(navState.url);
await provider?.connectSocial(parsedUrl.search);
await ConnectionController.connectExternal(authConnector);
+ ConnectionController.setConnectedSocialProvider(connectingProvider);
WebviewController.setConnecting(false);
ModalController.close();
}
From 69e5b86c17ddf1d0903c29af6f29fa5135e5a7d7 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 1 Oct 2024 16:03:28 -0300
Subject: [PATCH 078/114] chore: changes for farcaster login
---
.../w3m-connecting-farcaster-view/index.tsx | 36 ++++++++++++++++---
.../w3m-connecting-farcaster-view/styles.ts | 3 ++
packages/wallet/src/AppKitFrameProvider.ts | 7 ++--
packages/wallet/src/AppKitFrameSchema.ts | 4 +--
packages/wallet/src/AppKitWebview.tsx | 10 ++++--
5 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
index 0196d3bda..6a9ade1bb 100644
--- a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
@@ -4,13 +4,20 @@ import {
ConnectionController,
ConnectorController,
ModalController,
+ OptionsController,
RouterController,
SnackController,
WebviewController,
type AppKitFrameProvider
} from '@reown/appkit-core-react-native';
-import { FlexView, LoadingThumbnail, IconBox, Logo, Text } from '@reown/appkit-ui-react-native';
-import { StringUtil } from '@reown/appkit-common-react-native';
+import {
+ FlexView,
+ LoadingThumbnail,
+ IconBox,
+ Logo,
+ Text,
+ Link
+} from '@reown/appkit-ui-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
@@ -20,6 +27,8 @@ export function ConnectingFarcasterView() {
const { maxWidth: width } = useCustomDimensions();
const authConnector = ConnectorController.getAuthConnector();
const [error, setError] = useState(false);
+ const [_url, setUrl] = useState();
+ const showCopy = OptionsController.isClipboardAvailable();
const socialProvider = data?.socialProvider;
const provider = authConnector?.provider as AppKitFrameProvider;
@@ -28,7 +37,8 @@ export function ConnectingFarcasterView() {
if (!WebviewController.state.connecting && provider && socialProvider && authConnector) {
setError(false);
const { url } = await provider.getFarcasterUri();
- await Linking.openURL(url);
+ setUrl(url);
+ Linking.openURL(url);
await provider.connectFarcaster();
await ConnectionController.connectExternal(authConnector);
ConnectionController.setConnectedSocialProvider(socialProvider);
@@ -41,6 +51,13 @@ export function ConnectingFarcasterView() {
}
}, [provider, socialProvider, authConnector]);
+ const onCopyUrl = () => {
+ if (_url) {
+ OptionsController.copyToClipboard(_url);
+ SnackController.showSuccess('Link copied');
+ }
+ };
+
useEffect(() => {
onConnect();
}, [onConnect]);
@@ -68,8 +85,19 @@ export function ConnectingFarcasterView() {
)}
- {`Continue with ${StringUtil.capitalize(socialProvider)}`}
+ Continue in Farcaster
+ {showCopy && (
+
+ Copy link
+
+ )}
>
);
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts b/packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts
index dcb555e83..542a8ad28 100644
--- a/packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/styles.ts
@@ -11,5 +11,8 @@ export default StyleSheet.create({
continueText: {
marginTop: Spacing.m,
marginBottom: Spacing.xs
+ },
+ copyButton: {
+ marginTop: Spacing.m
}
});
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index 5ec259a74..1f7f99f18 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -313,8 +313,11 @@ export class AppKitFrameProvider {
payload: { ...payload, chainId }
} as AppKitFrameTypes.AppEvent);
- this.setEmailLoginSuccess(response.email);
- this.setLastUsedChainId(response.chainId);
+ if (response.email) {
+ this.setEmailLoginSuccess(response.email);
+ }
+
+ this.setLastUsedChainId(Number(response.chainId));
return response;
}
diff --git a/packages/wallet/src/AppKitFrameSchema.ts b/packages/wallet/src/AppKitFrameSchema.ts
index 70c15c36c..329a26c75 100644
--- a/packages/wallet/src/AppKitFrameSchema.ts
+++ b/packages/wallet/src/AppKitFrameSchema.ts
@@ -70,9 +70,9 @@ export const FrameUpdateEmailResponse = z.object({
action: z.enum(['VERIFY_PRIMARY_OTP', 'VERIFY_SECONDARY_OTP'])
});
export const FrameGetUserResponse = z.object({
- email: z.string().email(),
+ email: z.string().email().optional().nullable(),
address: z.string(),
- chainId: z.number()
+ chainId: z.string().or(z.number())
});
export const FrameIsConnectedResponse = z.object({ isConnected: z.boolean() });
export const FrameGetChainIdResponse = z.object({ chainId: z.number() });
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index e6e6046a6..4bc73b600 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -90,6 +90,9 @@ export function AppKitWebview() {
onPress={onClose}
testID="button-close"
style={styles.closeButton}
+ iconColor="inverse-100"
+ backgroundColor="gray-glass-030"
+ pressedColor="gray-glass-080"
/>
Date: Wed, 2 Oct 2024 10:54:10 -0300
Subject: [PATCH 079/114] chore: added condition in webview so connect is
called once
---
packages/wallet/src/AppKitWebview.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index 4bc73b600..fd74e8291 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -104,7 +104,7 @@ export function AppKitWebview() {
ref={webviewRef}
onNavigationStateChange={async navState => {
try {
- if (authConnector && navState.url.includes('/sdk/oauth')) {
+ if (authConnector && webviewVisible && navState.url.includes('/sdk/oauth')) {
WebviewController.setWebviewVisible(false);
const parsedUrl = new URL(navState.url);
await provider?.connectSocial(parsedUrl.search);
From 1dcbd2f0db92b4578a8711068cbe73948fc1371e Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Fri, 4 Oct 2024 12:05:26 -0300
Subject: [PATCH 080/114] chore: clean social provider on disconnect
---
packages/core/src/controllers/ConnectionController.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts
index 18255554a..a7b2d1b61 100644
--- a/packages/core/src/controllers/ConnectionController.ts
+++ b/packages/core/src/controllers/ConnectionController.ts
@@ -180,10 +180,12 @@ export const ConnectionController = {
this.clearUri();
state.pressedWallet = undefined;
state.connectedWalletImageUrl = undefined;
+ state.connectedSocialProvider = undefined;
ConnectorController.setConnectedConnector(undefined);
StorageUtil.removeWalletConnectDeepLink();
StorageUtil.removeConnectedWalletImageUrl();
StorageUtil.removeConnectedConnector();
+ StorageUtil.removeConnectedSocialProvider();
},
async disconnect() {
From a13a336f77bbae11aa9d8f0dc4e7545b4d1deaa0 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 7 Oct 2024 17:51:00 -0300
Subject: [PATCH 081/114] chore: added emailShowWallets prop functionality
---
apps/native/App.tsx | 7 ++-
.../src/views/w3m-connect-view/index.tsx | 62 ++++++++++++-------
.../src/views/w3m-connect-view/styles.ts | 7 +++
3 files changed, 52 insertions(+), 24 deletions(-)
diff --git a/apps/native/App.tsx b/apps/native/App.tsx
index 79f1db3aa..d5ba189e4 100644
--- a/apps/native/App.tsx
+++ b/apps/native/App.tsx
@@ -62,7 +62,12 @@ createAppKit({
clipboardClient,
customWallets,
enableAnalytics: true,
- metadata
+ metadata,
+ features: {
+ email: true,
+ socials: ['x', 'discord', 'apple', 'farcaster', 'facebook'],
+ emailShowWallets: true
+ }
});
export default function Native() {
diff --git a/packages/scaffold/src/views/w3m-connect-view/index.tsx b/packages/scaffold/src/views/w3m-connect-view/index.tsx
index b68e303fa..9ab0ee53d 100644
--- a/packages/scaffold/src/views/w3m-connect-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/index.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { Platform, ScrollView } from 'react-native';
+import { Platform, ScrollView, View } from 'react-native';
import {
ConnectorController,
EventUtil,
@@ -8,7 +8,7 @@ import {
RouterController,
type WcWallet
} from '@reown/appkit-core-react-native';
-import { FlexView, Separator, Spacing } from '@reown/appkit-ui-react-native';
+import { FlexView, Icon, ListItem, Separator, Spacing, Text } from '@reown/appkit-ui-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import { ConnectEmailInput } from './components/connect-email-input';
import { useKeyboard } from '../../hooks/useKeyboard';
@@ -32,6 +32,8 @@ export function ConnectView() {
const isCoinbaseEnabled = connectors.some(c => c.type === 'COINBASE');
const isEmailEnabled = isAuthEnabled && features?.email;
const isSocialEnabled = isAuthEnabled && features?.socials && features?.socials.length > 0;
+ const showConnectWalletsButton =
+ isWalletConnectEnabled && isAuthEnabled && !features?.emailShowWallets;
const showSeparator =
isAuthEnabled &&
(isEmailEnabled || isSocialEnabled) &&
@@ -73,28 +75,42 @@ export function ConnectView() {
{isEmailEnabled && }
{isSocialEnabled && }
{showSeparator && }
+
-
-
-
-
-
+ {showConnectWalletsButton ? (
+
+
+ Connect wallet
+
+
+ ) : (
+ <>
+
+
+
+
+
+ >
+ )}
diff --git a/packages/scaffold/src/views/w3m-connect-view/styles.ts b/packages/scaffold/src/views/w3m-connect-view/styles.ts
index 271762bda..819b007df 100644
--- a/packages/scaffold/src/views/w3m-connect-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-connect-view/styles.ts
@@ -7,5 +7,12 @@ export default StyleSheet.create({
},
socialSeparator: {
marginVertical: Spacing.xs
+ },
+ connectWalletButton: {
+ justifyContent: 'space-between'
+ },
+ connectWalletEmpty: {
+ height: 20,
+ width: 20
}
});
From 826e28ad91ef3baf67ea0110399f4bcc7d1231f8 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 7 Oct 2024 18:32:14 -0300
Subject: [PATCH 082/114] chore: clean loading status before entering social
screen
---
.../views/w3m-connect-view/components/social-login-list.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
index 8af95e8f1..c36406f65 100644
--- a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
@@ -1,7 +1,7 @@
import { StyleSheet } from 'react-native';
import { FlexView, ListSocial, LogoSelect, Spacing, Text } from '@reown/appkit-ui-react-native';
import { type SocialProvider, StringUtil } from '@reown/appkit-common-react-native';
-import { RouterController } from '@reown/appkit-core-react-native';
+import { RouterController, WebviewController } from '@reown/appkit-core-react-native';
export interface SocialLoginListProps {
options: readonly SocialProvider[];
@@ -18,6 +18,7 @@ export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
bottomSocials = showMoreButton ? bottomSocials.slice(0, MAX_OPTIONS - 2) : bottomSocials;
const onItemPress = (social: SocialProvider) => {
+ WebviewController.setConnecting(false);
if (social === 'farcaster') {
RouterController.push('ConnectingFarcaster', { socialProvider: social });
} else {
From a1b042f9bbf15a4e8b1ae40bb1d4833baa4c59be Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Mon, 7 Oct 2024 19:17:55 -0300
Subject: [PATCH 083/114] chore: added create wallet view
---
.../stories/composites/Chip.stories.tsx | 6 +--
apps/gallery/utils/PresetUtils.ts | 1 +
packages/auth-wagmi/src/index.ts | 4 +-
.../core/src/controllers/RouterController.ts | 1 +
.../scaffold/src/modal/w3m-router/index.tsx | 3 ++
.../src/partials/w3m-header/index.tsx | 1 +
.../components/wallet-guide.tsx | 50 +++++++++++++++++++
.../src/views/w3m-connect-view/index.tsx | 2 +
.../src/views/w3m-create-view/index.tsx | 35 +++++++++++++
.../w3m-upgrade-email-wallet-view/index.tsx | 2 +-
.../views/w3m-wallet-receive-view/index.tsx | 2 +-
packages/ui/src/assets/svg/WalletConnect.tsx | 25 +++++++++-
packages/ui/src/components/wui-icon/index.tsx | 3 +-
packages/ui/src/composites/wui-chip/index.tsx | 11 ++--
packages/ui/src/utils/TypesUtil.ts | 1 +
15 files changed, 134 insertions(+), 13 deletions(-)
create mode 100644 packages/scaffold/src/views/w3m-connect-view/components/wallet-guide.tsx
create mode 100644 packages/scaffold/src/views/w3m-create-view/index.tsx
diff --git a/apps/gallery/stories/composites/Chip.stories.tsx b/apps/gallery/stories/composites/Chip.stories.tsx
index fcef69462..23419deed 100644
--- a/apps/gallery/stories/composites/Chip.stories.tsx
+++ b/apps/gallery/stories/composites/Chip.stories.tsx
@@ -23,7 +23,7 @@ const meta: Meta = {
imageSrc: {
control: { type: 'text' }
},
- icon: {
+ rightIcon: {
options: iconOptions,
control: { type: 'select' }
}
@@ -32,7 +32,7 @@ const meta: Meta = {
variant: 'fill',
size: 'md',
disabled: false,
- icon: 'disconnect',
+ rightIcon: 'disconnect',
label: externalLabel,
imageSrc: walletImageSrc
}
@@ -50,7 +50,7 @@ export const Default: Story = {
onPress={() => {}}
label={args.label}
imageSrc={args.imageSrc}
- icon={args.icon}
+ rightIcon={args.rightIcon}
/>
)
};
diff --git a/apps/gallery/utils/PresetUtils.ts b/apps/gallery/utils/PresetUtils.ts
index b792514e9..038fc6fd3 100644
--- a/apps/gallery/utils/PresetUtils.ts
+++ b/apps/gallery/utils/PresetUtils.ts
@@ -172,6 +172,7 @@ export const iconOptions: IconType[] = [
'wallet',
'walletSmall',
'walletConnect',
+ 'walletConnectLightBrown',
'walletPlaceholder',
'warningCircle'
];
diff --git a/packages/auth-wagmi/src/index.ts b/packages/auth-wagmi/src/index.ts
index 287aba48b..934b8bb72 100644
--- a/packages/auth-wagmi/src/index.ts
+++ b/packages/auth-wagmi/src/index.ts
@@ -45,9 +45,9 @@ export function authConnector(parameters: AuthConnectorOptions) {
return {
accounts: [address as Address],
account: address as Address,
- chainId,
+ chainId: chainId as number,
chain: {
- id: chainId,
+ id: chainId as number,
unsuported: false
}
};
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index 7fbbd8513..92fd80a73 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -24,6 +24,7 @@ export interface RouterControllerState {
| 'ConnectingSocial'
| 'ConnectingFarcaster'
| 'ConnectingWalletConnect'
+ | 'Create'
| 'EmailVerifyDevice'
| 'EmailVerifyOtp'
| 'GetWallet'
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index 325a07f3e..ff7f694e8 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -31,6 +31,7 @@ import { WhatIsAWalletView } from '../../views/w3m-what-is-a-wallet-view';
import { UiUtil } from '../../utils/UiUtil';
import { ConnectingFarcasterView } from '../../views/w3m-connecting-farcaster-view';
import { ConnectSocialsView } from '../../views/w3m-connect-socials-view';
+import { CreateView } from '../../views/w3m-create-view';
export function AppKitRouter() {
const { view } = useSnapshot(RouterController.state);
@@ -61,6 +62,8 @@ export function AppKitRouter() {
return ConnectingFarcasterView;
case 'ConnectingWalletConnect':
return ConnectingView;
+ case 'Create':
+ return CreateView;
case 'EmailVerifyDevice':
return EmailVerifyDeviceView;
case 'EmailVerifyOtp':
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index 49cddef65..3a7f5fd5a 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -34,6 +34,7 @@ export function Header() {
ConnectingFarcaster: socialName ?? 'Connecting Social',
ConnectingSocial: socialName ?? 'Connecting Social',
ConnectingWalletConnect: walletName ?? 'WalletConnect',
+ Create: 'Create wallet',
EmailVerifyDevice: ' ',
EmailVerifyOtp: 'Confirm email',
GetWallet: 'Get a wallet',
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/wallet-guide.tsx b/packages/scaffold/src/views/w3m-connect-view/components/wallet-guide.tsx
new file mode 100644
index 000000000..92fdcc2de
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-connect-view/components/wallet-guide.tsx
@@ -0,0 +1,50 @@
+import { RouterController } from '@reown/appkit-core-react-native';
+import { Chip, FlexView, Link, Separator, Spacing, Text } from '@reown/appkit-ui-react-native';
+import { Linking, StyleSheet } from 'react-native';
+
+export interface WalletGuideProps {
+ guide: 'explore' | 'get-started';
+}
+
+export function WalletGuide({ guide }: WalletGuideProps) {
+ const onExplorerPress = () => {
+ Linking.openURL('https://explorer.walletconnect.com');
+ };
+
+ const onGetStartedPress = () => {
+ RouterController.push('Create');
+ };
+
+ return guide === 'explore' ? (
+
+
+
+ Looking for a self-custody wallet?
+
+
+
+ ) : (
+
+ Haven't got a wallet?
+
+ Get started
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ text: {
+ marginBottom: Spacing.xs
+ },
+ socialSeparator: {
+ marginVertical: Spacing.l
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-connect-view/index.tsx b/packages/scaffold/src/views/w3m-connect-view/index.tsx
index 9ab0ee53d..7b3fd4d2d 100644
--- a/packages/scaffold/src/views/w3m-connect-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/index.tsx
@@ -19,6 +19,7 @@ import { AllWalletList } from './components/all-wallet-list';
import { RecentWalletList } from './components/recent-wallet-list';
import { SocialLoginList } from './components/social-login-list';
import styles from './styles';
+import { WalletGuide } from './components/wallet-guide';
export function ConnectView() {
const connectors = ConnectorController.state.connectors;
@@ -111,6 +112,7 @@ export function ConnectView() {
/>
>
)}
+ {isAuthEnabled && }
diff --git a/packages/scaffold/src/views/w3m-create-view/index.tsx b/packages/scaffold/src/views/w3m-create-view/index.tsx
new file mode 100644
index 000000000..dcfa09654
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-create-view/index.tsx
@@ -0,0 +1,35 @@
+import { Platform, ScrollView } from 'react-native';
+import { useSnapshot } from 'valtio';
+import { FlexView, Spacing } from '@reown/appkit-ui-react-native';
+import { ConnectEmailInput } from '../w3m-connect-view/components/connect-email-input';
+import { SocialLoginList } from '../w3m-connect-view/components/social-login-list';
+import { WalletGuide } from '../w3m-connect-view/components/wallet-guide';
+import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import { ConnectorController, OptionsController } from '@reown/appkit-core-react-native';
+import { useKeyboard } from '../../hooks/useKeyboard';
+
+export function CreateView() {
+ const connectors = ConnectorController.state.connectors;
+ const { authLoading } = useSnapshot(ConnectorController.state);
+ const { features } = useSnapshot(OptionsController.state);
+ const { padding } = useCustomDimensions();
+ const { keyboardShown, keyboardHeight } = useKeyboard();
+ const isAuthEnabled = connectors.some(c => c.type === 'AUTH');
+ const isEmailEnabled = isAuthEnabled && features?.email;
+ const isSocialEnabled = isAuthEnabled && features?.socials && features?.socials.length > 0;
+
+ const paddingBottom = Platform.select({
+ android: keyboardShown ? keyboardHeight + Spacing.xl : Spacing.xl,
+ default: Spacing.xl
+ });
+
+ return (
+
+
+ {isEmailEnabled && }
+ {isSocialEnabled && }
+ {isAuthEnabled && }
+
+
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx b/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
index 425d9729b..d3239180a 100644
--- a/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
@@ -19,7 +19,7 @@ export function UpgradeEmailWalletView() {
Follow the instructions on
(
(
);
export default SvgWalletConnect;
+
+export const WalletConnectLightBrownSvg = (props: SvgProps) => (
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/packages/ui/src/components/wui-icon/index.tsx b/packages/ui/src/components/wui-icon/index.tsx
index 7b1656e9a..56f010f5f 100644
--- a/packages/ui/src/components/wui-icon/index.tsx
+++ b/packages/ui/src/components/wui-icon/index.tsx
@@ -52,7 +52,7 @@ import SwapVerticalSvg from '../../assets/svg/SwapVertical';
import TelegramSvg from '../../assets/svg/Telegram';
import TwitchSvg from '../../assets/svg/Twitch';
import VerifySvg from '../../assets/svg/Verify';
-import WalletConnectSvg from '../../assets/svg/WalletConnect';
+import WalletConnectSvg, { WalletConnectLightBrownSvg } from '../../assets/svg/WalletConnect';
import WalletSvg from '../../assets/svg/Wallet';
import WalletSmallSvg from '../../assets/svg/WalletSmall';
import WarningCircleSvg from '../../assets/svg/WarningCircle';
@@ -116,6 +116,7 @@ const svgOptions: Record JSX.Element> = {
walletSmall: WalletSmallSvg,
warningCircle: WarningCircleSvg,
walletConnect: WalletConnectSvg,
+ walletConnectLightBrown: WalletConnectLightBrownSvg,
walletPlaceholder: WalletPlaceholderSvg,
x: XSvg
};
diff --git a/packages/ui/src/composites/wui-chip/index.tsx b/packages/ui/src/composites/wui-chip/index.tsx
index ed3764545..e8ab92e47 100644
--- a/packages/ui/src/composites/wui-chip/index.tsx
+++ b/packages/ui/src/composites/wui-chip/index.tsx
@@ -12,7 +12,8 @@ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
export interface ChipProps {
label?: string;
imageSrc?: string;
- icon?: IconType;
+ leftIcon?: IconType;
+ rightIcon?: IconType;
variant?: ChipType;
size?: Exclude;
disabled?: boolean;
@@ -23,7 +24,8 @@ export interface ChipProps {
export function Chip({
onPress,
imageSrc,
- icon,
+ leftIcon,
+ rightIcon,
variant = 'fill',
size = 'md',
disabled,
@@ -89,15 +91,16 @@ export function Chip({
source={imageSrc}
/>
)}
+ {leftIcon && }
{label}
- {icon && (
+ {rightIcon && (
Date: Tue, 8 Oct 2024 10:14:08 -0300
Subject: [PATCH 084/114] chore: added social events
---
packages/core/src/utils/TypeUtil.ts | 21 +++++++++++++++++++
.../views/w3m-connect-socials-view/index.tsx | 17 ++++++++++++++-
.../components/social-login-list.tsx | 12 ++++++++++-
.../w3m-connecting-farcaster-view/index.tsx | 11 ++++++++++
packages/wallet/src/AppKitWebview.tsx | 20 +++++++++++++++++-
5 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 84d96f1f3..9981f4fab 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -451,6 +451,27 @@ export type Event =
token: string;
amount: number;
};
+ }
+ | {
+ type: 'track';
+ event: 'SOCIAL_LOGIN_STARTED';
+ properties: {
+ provider: SocialProvider;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'SOCIAL_LOGIN_SUCCESS';
+ properties: {
+ provider: SocialProvider;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'SOCIAL_LOGIN_ERROR';
+ properties: {
+ provider: SocialProvider;
+ };
};
// -- Send Controller Types -------------------------------------
diff --git a/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx b/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
index d5aecad29..668123d88 100644
--- a/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
@@ -1,7 +1,13 @@
+import { useEffect } from 'react';
import { useSnapshot } from 'valtio';
import { ScrollView } from 'react-native';
import { StringUtil, type SocialProvider } from '@reown/appkit-common-react-native';
-import { OptionsController, RouterController } from '@reown/appkit-core-react-native';
+import {
+ EventsController,
+ OptionsController,
+ RouterController,
+ WebviewController
+} from '@reown/appkit-core-react-native';
import { FlexView, ListSocial, Text } from '@reown/appkit-ui-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
@@ -13,6 +19,11 @@ export function ConnectSocialsView() {
const socialProviders = (features?.socials ?? []) as SocialProvider[];
const onItemPress = (provider: SocialProvider) => {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_STARTED',
+ properties: { provider }
+ });
if (provider === 'farcaster') {
RouterController.push('ConnectingFarcaster', { socialProvider: provider });
} else {
@@ -20,6 +31,10 @@ export function ConnectSocialsView() {
}
};
+ useEffect(() => {
+ WebviewController.setConnecting(false);
+ }, []);
+
return (
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
index c36406f65..cc1e45a2b 100644
--- a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
@@ -1,7 +1,11 @@
import { StyleSheet } from 'react-native';
import { FlexView, ListSocial, LogoSelect, Spacing, Text } from '@reown/appkit-ui-react-native';
import { type SocialProvider, StringUtil } from '@reown/appkit-common-react-native';
-import { RouterController, WebviewController } from '@reown/appkit-core-react-native';
+import {
+ EventsController,
+ RouterController,
+ WebviewController
+} from '@reown/appkit-core-react-native';
export interface SocialLoginListProps {
options: readonly SocialProvider[];
@@ -18,7 +22,13 @@ export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
bottomSocials = showMoreButton ? bottomSocials.slice(0, MAX_OPTIONS - 2) : bottomSocials;
const onItemPress = (social: SocialProvider) => {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_STARTED',
+ properties: { provider: social }
+ });
WebviewController.setConnecting(false);
+
if (social === 'farcaster') {
RouterController.push('ConnectingFarcaster', { socialProvider: social });
} else {
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
index 6a9ade1bb..469f9297c 100644
--- a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useState } from 'react';
import {
ConnectionController,
ConnectorController,
+ EventsController,
ModalController,
OptionsController,
RouterController,
@@ -42,10 +43,20 @@ export function ConnectingFarcasterView() {
await provider.connectFarcaster();
await ConnectionController.connectExternal(authConnector);
ConnectionController.setConnectedSocialProvider(socialProvider);
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_SUCCESS',
+ properties: { provider: socialProvider }
+ });
WebviewController.setConnecting(false);
ModalController.close();
}
} catch (e) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_ERROR',
+ properties: { provider: socialProvider! }
+ });
SnackController.showError('Something went wrong');
setError(true);
}
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index fd74e8291..90978abac 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -6,6 +6,7 @@ import { WebView } from 'react-native-webview';
import {
ConnectionController,
ConnectorController,
+ EventsController,
ModalController,
RouterController,
SnackController,
@@ -104,16 +105,33 @@ export function AppKitWebview() {
ref={webviewRef}
onNavigationStateChange={async navState => {
try {
- if (authConnector && webviewVisible && navState.url.includes('/sdk/oauth')) {
+ if (
+ authConnector &&
+ connectingProvider &&
+ webviewVisible &&
+ navState.url.includes('/sdk/oauth')
+ ) {
WebviewController.setWebviewVisible(false);
const parsedUrl = new URL(navState.url);
await provider?.connectSocial(parsedUrl.search);
await ConnectionController.connectExternal(authConnector);
ConnectionController.setConnectedSocialProvider(connectingProvider);
WebviewController.setConnecting(false);
+
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_SUCCESS',
+ properties: { provider: connectingProvider }
+ });
+
ModalController.close();
}
} catch (e) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_ERROR',
+ properties: { provider: connectingProvider! }
+ });
onClose();
SnackController.showError('Something went wrong');
}
From 973554e44690e65b99484867f86a765e3ee887ed Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 8 Oct 2024 10:52:40 -0300
Subject: [PATCH 085/114] chore: code improvements - emit social event
---
packages/core/src/utils/TypeUtil.ts | 2 +
.../w3m-connecting-social-view/index.tsx | 50 ++++++++++++++++++-
packages/wallet/src/AppKitFrameProvider.ts | 4 ++
packages/wallet/src/AppKitWebview.tsx | 38 ++------------
4 files changed, 58 insertions(+), 36 deletions(-)
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 9981f4fab..03ddc6f84 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -1,3 +1,4 @@
+import { type EventEmitter } from 'events';
import type { Balance, SocialProvider, Transaction } from '@reown/appkit-common-react-native';
export interface BaseError {
@@ -502,6 +503,7 @@ export interface WriteContractArgs {
export interface AppKitFrameProvider {
readonly id: string;
readonly name: string;
+ getEventEmitter(): EventEmitter;
getSecureSiteURL(): string;
getSecureSiteDashboardURL(): string;
getSecureSiteIconURL(): string;
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
index 2a4b970f5..50a8af39d 100644
--- a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
@@ -1,7 +1,10 @@
import { useSnapshot } from 'valtio';
import { useCallback, useEffect, useState } from 'react';
import {
+ ConnectionController,
ConnectorController,
+ EventsController,
+ ModalController,
RouterController,
SnackController,
WebviewController,
@@ -43,10 +46,55 @@ export function ConnectingSocialView() {
}
}, [provider, socialProvider]);
+ const socialMessageHandler = useCallback(
+ async (url: string) => {
+ try {
+ if (url.includes('/sdk/oauth') && socialProvider && authConnector) {
+ WebviewController.setWebviewVisible(false);
+ const parsedUrl = new URL(url);
+ await provider?.connectSocial(parsedUrl.search);
+ await ConnectionController.connectExternal(authConnector);
+ ConnectionController.setConnectedSocialProvider(socialProvider);
+ WebviewController.setConnecting(false);
+
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_SUCCESS',
+ properties: { provider: socialProvider }
+ });
+
+ ModalController.close();
+ }
+ } catch (e) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_ERROR',
+ properties: { provider: socialProvider! }
+ });
+ WebviewController.setWebviewVisible(false);
+ WebviewController.setConnecting(false);
+ WebviewController.setConnectingProvider(undefined);
+ RouterController.goBack();
+ SnackController.showError('Something went wrong');
+ }
+ },
+ [socialProvider, authConnector, provider]
+ );
+
useEffect(() => {
onConnect();
}, [onConnect]);
+ useEffect(() => {
+ if (!provider) return;
+
+ const unsubscribe = provider?.getEventEmitter().addListener('social', socialMessageHandler);
+
+ return () => {
+ unsubscribe.removeListener('social', socialMessageHandler);
+ };
+ }, [socialMessageHandler, provider]);
+
return (
- {connecting ? 'Connecting...' : 'Connect in the provider window'}
+ {connecting ? 'Retrieving user data' : 'Connect in the provider window'}
);
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index 1f7f99f18..7b26dedc2 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -117,6 +117,10 @@ export class AppKitFrameProvider {
} catch (e) {}
}
+ public getEventEmitter() {
+ return this.events;
+ }
+
public async connectEmail(payload: AppKitFrameTypes.Requests['AppConnectEmailRequest']) {
await this.webviewLoadPromise;
await AppKitFrameHelpers.checkIfAllowedToTriggerEmail();
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index 90978abac..536ad48cc 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -4,12 +4,8 @@ import { Animated, SafeAreaView, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
import {
- ConnectionController,
ConnectorController,
- EventsController,
- ModalController,
RouterController,
- SnackController,
WebviewController
} from '@reown/appkit-core-react-native';
import { useTheme, BorderRadius, IconLink, Spacing } from '@reown/appkit-ui-react-native';
@@ -21,7 +17,7 @@ export function AppKitWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
const authConnector = ConnectorController.getAuthConnector();
- const { webviewVisible, webviewUrl, connectingProvider } = useSnapshot(WebviewController.state);
+ const { webviewVisible, webviewUrl } = useSnapshot(WebviewController.state);
const [isBackdropVisible, setIsBackdropVisible] = useState(false);
const animatedHeight = useRef(new Animated.Value(0));
const backdropOpacity = useRef(new Animated.Value(0));
@@ -104,36 +100,8 @@ export function AppKitWebview() {
containerStyle={styles.webview}
ref={webviewRef}
onNavigationStateChange={async navState => {
- try {
- if (
- authConnector &&
- connectingProvider &&
- webviewVisible &&
- navState.url.includes('/sdk/oauth')
- ) {
- WebviewController.setWebviewVisible(false);
- const parsedUrl = new URL(navState.url);
- await provider?.connectSocial(parsedUrl.search);
- await ConnectionController.connectExternal(authConnector);
- ConnectionController.setConnectedSocialProvider(connectingProvider);
- WebviewController.setConnecting(false);
-
- EventsController.sendEvent({
- type: 'track',
- event: 'SOCIAL_LOGIN_SUCCESS',
- properties: { provider: connectingProvider }
- });
-
- ModalController.close();
- }
- } catch (e) {
- EventsController.sendEvent({
- type: 'track',
- event: 'SOCIAL_LOGIN_ERROR',
- properties: { provider: connectingProvider! }
- });
- onClose();
- SnackController.showError('Something went wrong');
+ if (webviewVisible) {
+ provider.events.emit('social', navState.url);
}
}}
/>
From b7abd353cd87e9eae39574a69a7921289331bc0e Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 8 Oct 2024 11:19:46 -0300
Subject: [PATCH 086/114] chore: ui improvement
---
.../src/partials/w3m-account-activity/index.tsx | 13 ++++++-------
.../src/partials/w3m-account-placeholder/index.tsx | 10 ++++++----
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index f2ee5cb8a..6c5f2a89b 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -68,13 +68,12 @@ export function AccountActivity({ style }: Props) {
if (!Object.keys(transactionsByYear).length) {
return (
-
-
-
+
);
}
diff --git a/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx b/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
index 63db85b11..666d19773 100644
--- a/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
@@ -1,15 +1,16 @@
-import { StyleSheet } from 'react-native';
+import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
import { IconBox, Text, FlexView, Spacing, type IconType } from '@reown/appkit-ui-react-native';
interface Props {
icon: IconType;
title: string;
description: string;
+ style?: StyleProp;
}
-export function AccountPlaceholder({ icon, title, description }: Props) {
+export function AccountPlaceholder({ icon, title, description, style }: Props) {
return (
-
+
{title}
@@ -23,7 +24,8 @@ export function AccountPlaceholder({ icon, title, description }: Props) {
const styles = StyleSheet.create({
container: {
- flex: 1
+ flex: 1,
+ minHeight: 200
},
title: {
marginTop: Spacing.xl,
From ea5ed38accfdfc3498a3ca676840976d8406890c Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 9 Oct 2024 12:59:54 -0300
Subject: [PATCH 087/114] chore: removed textContentType from otp input
---
packages/ui/src/composites/wui-otp/index.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/ui/src/composites/wui-otp/index.tsx b/packages/ui/src/composites/wui-otp/index.tsx
index 713d0d21d..868101c5b 100644
--- a/packages/ui/src/composites/wui-otp/index.tsx
+++ b/packages/ui/src/composites/wui-otp/index.tsx
@@ -90,7 +90,6 @@ export function Otp({ length, style, onChangeText, autoFocus }: OtpProps) {
inputRef={refArray[index]}
onChangeText={text => _onChangeText(text, index)}
onKeyPress={(e: any) => onKeyPress(e, index)}
- textContentType="oneTimeCode"
autoComplete={Platform.OS === 'android' ? 'sms-otp' : 'one-time-code'}
/>
))}
From 8e0117195f34a22f6407252e95d7adcc0f2a94a7 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 10 Oct 2024 16:05:15 -0300
Subject: [PATCH 088/114] chore: changed button
---
packages/scaffold/src/views/w3m-connect-view/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/scaffold/src/views/w3m-connect-view/index.tsx b/packages/scaffold/src/views/w3m-connect-view/index.tsx
index 7b3fd4d2d..4a52eca79 100644
--- a/packages/scaffold/src/views/w3m-connect-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/index.tsx
@@ -81,7 +81,7 @@ export function ConnectView() {
{showConnectWalletsButton ? (
- Connect wallet
+ Continue with a wallet
) : (
From 726b82ae4eb8fdf6d4bdaa2289ab4af3e33c7827 Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 17 Oct 2024 17:02:17 -0300
Subject: [PATCH 089/114] fix: use custom token to get balance if provided
---
packages/common/src/contracts/erc20.ts | 47 ++++++++++++++++++++++++++
packages/ethers/src/client.ts | 22 +++++++++---
packages/ethers5/src/client.ts | 21 +++++++++---
packages/wagmi/src/client.ts | 3 +-
4 files changed, 84 insertions(+), 9 deletions(-)
diff --git a/packages/common/src/contracts/erc20.ts b/packages/common/src/contracts/erc20.ts
index cf48b5c1e..744983257 100644
--- a/packages/common/src/contracts/erc20.ts
+++ b/packages/common/src/contracts/erc20.ts
@@ -44,5 +44,52 @@ export const erc20ABI = [
type: 'bool'
}
]
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'symbol',
+ outputs: [
+ {
+ name: '',
+ type: 'string'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'decimals',
+ outputs: [
+ {
+ name: '',
+ type: 'uint8'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_owner',
+ type: 'address'
+ }
+ ],
+ name: 'balanceOf',
+ outputs: [
+ {
+ name: 'balance',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
}
];
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 284585ba2..6f6659de9 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -26,7 +26,7 @@ import {
AppKitScaffold,
type WriteContractArgs
} from '@reown/appkit-scaffold-react-native';
-import { NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
+import { erc20ABI, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import {
ConstantsUtil,
PresetsUtil,
@@ -775,16 +775,30 @@ export class AppKit extends AppKitScaffold {
const chainId = EthersStoreUtil.state.chainId;
if (chainId && this.chains) {
const chain = this.chains.find(c => c.chainId === chainId);
+ const token = this.options?.tokens?.[chainId];
if (chain) {
const jsonRpcProvider = new JsonRpcProvider(chain.rpcUrl, {
chainId,
name: chain.name
});
+
if (jsonRpcProvider) {
- const balance = await jsonRpcProvider.getBalance(address);
- const formattedBalance = formatEther(balance);
- this.setBalance(formattedBalance, chain.currency);
+ if (token) {
+ // Get balance from custom token address
+ const erc20 = new Contract(token.address, erc20ABI, jsonRpcProvider);
+ // @ts-expect-error
+ const decimals = await erc20.decimals();
+ // @ts-expect-error
+ const symbol = await erc20.symbol();
+ // @ts-expect-error
+ const balanceOf = await erc20.balanceOf(address);
+ this.setBalance(formatUnits(balanceOf, decimals), symbol);
+ } else {
+ const balance = await jsonRpcProvider.getBalance(address);
+ const formattedBalance = formatEther(balance);
+ this.setBalance(formattedBalance, chain.currency);
+ }
}
}
}
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index 2b0af1c3b..cb38f6a79 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -30,7 +30,7 @@ import {
type CombinedProviderType,
type AppKitFrameProvider
} from '@reown/appkit-scaffold-utils-react-native';
-import { NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
+import { erc20ABI, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import EthereumProvider, { OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
import type { EthereumProviderOptions } from '@walletconnect/ethereum-provider';
@@ -755,6 +755,7 @@ export class AppKit extends AppKitScaffold {
const chainId = EthersStoreUtil.state.chainId;
if (chainId && this.chains) {
const chain = this.chains.find(c => c.chainId === chainId);
+ const token = this.options?.tokens?.[chainId];
if (chain) {
const jsonRpcProvider = new ethers.providers.JsonRpcProvider(chain.rpcUrl, {
@@ -762,9 +763,21 @@ export class AppKit extends AppKitScaffold {
name: chain.name
});
if (jsonRpcProvider) {
- const balance = await jsonRpcProvider.getBalance(address);
- const formattedBalance = utils.formatEther(balance);
- this.setBalance(formattedBalance, chain.currency);
+ if (token) {
+ // Get balance from custom token address
+ const erc20 = new Contract(token.address, erc20ABI, jsonRpcProvider);
+ // @ts-expect-error
+ const decimals = await erc20.decimals();
+ // @ts-expect-error
+ const symbol = await erc20.symbol();
+ // @ts-expect-error
+ const balanceOf = await erc20.balanceOf(address);
+ this.setBalance(utils.formatUnits(balanceOf, decimals), symbol);
+ } else {
+ const balance = await jsonRpcProvider.getBalance(address);
+ const formattedBalance = utils.formatEther(balance);
+ this.setBalance(formattedBalance, chain.currency);
+ }
}
}
}
diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts
index 804ab2561..0f45eb838 100644
--- a/packages/wagmi/src/client.ts
+++ b/packages/wagmi/src/client.ts
@@ -486,7 +486,8 @@ export class AppKit extends AppKitScaffold {
if (chain) {
const balance = await getBalance(this.wagmiConfig, {
address,
- chainId: chain.id
+ chainId: chain.id,
+ token: this.options?.tokens?.[chainId]?.address as Hex
});
const formattedBalance = formatUnits(balance.value, balance.decimals);
this.setBalance(formattedBalance, balance.symbol);
From 19bbffde847b8d962d30e7dedacd93a4ef0c543c Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 17 Oct 2024 17:02:49 -0300
Subject: [PATCH 090/114] chore: changeset
---
.changeset/pretty-taxis-type.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 .changeset/pretty-taxis-type.md
diff --git a/.changeset/pretty-taxis-type.md b/.changeset/pretty-taxis-type.md
new file mode 100644
index 000000000..9f56a5164
--- /dev/null
+++ b/.changeset/pretty-taxis-type.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: get custom token balance if provided
From fb85422e0d544efc21a686287d91b16a638cf99c Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 5 Nov 2024 11:30:26 -0300
Subject: [PATCH 091/114] chore: added changeset file
---
.changeset/bright-points-burn.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 .changeset/bright-points-burn.md
diff --git a/.changeset/bright-points-burn.md b/.changeset/bright-points-burn.md
new file mode 100644
index 000000000..cc251e262
--- /dev/null
+++ b/.changeset/bright-points-burn.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': minor
+'@reown/appkit-coinbase-wagmi-react-native': minor
+'@reown/appkit-scaffold-utils-react-native': minor
+'@reown/appkit-auth-ethers-react-native': minor
+'@reown/appkit-auth-wagmi-react-native': minor
+'@reown/appkit-scaffold-react-native': minor
+'@reown/appkit-ethers5-react-native': minor
+'@reown/appkit-common-react-native': minor
+'@reown/appkit-ethers-react-native': minor
+'@reown/appkit-wallet-react-native': minor
+'@reown/appkit-wagmi-react-native': minor
+'@reown/appkit-core-react-native': minor
+'@reown/appkit-siwe-react-native': minor
+'@reown/appkit-ui-react-native': minor
+---
+
+feat: social login
From 3193c6fac3a2d7f83f53bf982180469e23f156c4 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 5 Nov 2024 14:19:12 -0300
Subject: [PATCH 092/114] feat: smart accounts (#266)
---
.changeset/serious-tables-compare.md | 18 +
apps/native/App.tsx | 4 +-
apps/native/babel.config.js | 28 +-
apps/native/package.json | 6 +-
apps/native/src/utils/WagmiUtils.ts | 4 +-
apps/native/src/views/ActionsView.tsx | 4 +-
package.json | 4 +-
packages/auth-wagmi/package.json | 1 +
packages/auth-wagmi/src/index.ts | 71 ++-
packages/common/src/utils/TypeUtil.ts | 9 +-
.../controllers/AccountController.test.ts | 4 +-
.../controllers/NetworkController.test.ts | 13 +-
.../core/src/controllers/AccountController.ts | 18 +-
.../src/controllers/ConnectionController.ts | 15 +-
.../src/controllers/ConnectorController.ts | 14 +-
.../core/src/controllers/NetworkController.ts | 22 +-
.../core/src/controllers/OptionsController.ts | 3 +-
.../core/src/controllers/RouterController.ts | 1 +
.../core/src/controllers/SendController.ts | 8 +-
.../src/controllers/TransactionsController.ts | 3 +-
packages/core/src/utils/ConstantsUtil.ts | 2 +-
packages/core/src/utils/StorageUtil.ts | 2 +-
packages/core/src/utils/TypeUtil.ts | 59 +-
packages/ethers/src/client.ts | 41 +-
packages/ethers5/src/client.ts | 37 +-
packages/scaffold/src/client.ts | 7 +-
.../scaffold/src/modal/w3m-modal/index.tsx | 9 +-
.../scaffold/src/modal/w3m-router/index.tsx | 9 +-
.../partials/w3m-account-activity/index.tsx | 2 +-
.../src/partials/w3m-account-tokens/index.tsx | 31 +-
.../w3m-account-wallet-features/index.tsx | 4 +-
.../partials/w3m-all-wallets-list/index.tsx | 6 +-
.../src/partials/w3m-header/index.tsx | 16 +-
.../src/partials/w3m-header/styles.ts | 7 +-
.../src/partials/w3m-input-address/styles.ts | 2 +-
.../src/partials/w3m-input-token/styles.ts | 2 +-
.../views/w3m-account-default-view/index.tsx | 50 +-
.../src/views/w3m-account-view/index.tsx | 16 +-
.../src/views/w3m-account-view/styles.ts | 5 +
.../src/views/w3m-all-wallets-view/styles.ts | 2 +-
.../w3m-connecting-external-view/index.tsx | 4 +-
.../w3m-connecting-farcaster-view/index.tsx | 12 +-
.../w3m-connecting-social-view/index.tsx | 1 +
.../src/views/w3m-connecting-view/index.tsx | 4 +-
.../views/w3m-network-switch-view/index.tsx | 10 +
.../src/views/w3m-networks-view/index.tsx | 8 +-
.../w3m-upgrade-email-wallet-view/index.tsx | 2 +-
.../index.tsx | 106 ++++
.../styles.ts | 29 +
.../index.tsx | 22 +-
.../views/w3m-wallet-receive-view/index.tsx | 8 +-
.../components/preview-send-pill.tsx | 2 +-
.../index.tsx | 31 +-
.../src/views/w3m-wallet-send-view/styles.ts | 6 -
.../views/w3m-connecting-siwe-view/index.tsx | 37 +-
.../views/w3m-connecting-siwe-view/styles.ts | 8 +
packages/ui/src/__tests__/wui-text.test.tsx | 9 +
packages/ui/src/assets/visual/Google.tsx | 43 ++
packages/ui/src/assets/visual/Lightbulb.tsx | 54 ++
packages/ui/src/assets/visual/Pencil.tsx | 80 +++
packages/ui/src/components/wui-card/styles.ts | 2 +-
.../ui/src/components/wui-lean-text/index.tsx | 10 +
.../ui/src/components/wui-lean-view/index.tsx | 10 +
packages/ui/src/components/wui-text/index.tsx | 7 +-
.../ui/src/components/wui-visual/index.tsx | 6 +
.../composites/wui-account-button/styles.ts | 4 +-
.../src/composites/wui-account-pill/index.tsx | 8 +-
.../src/composites/wui-account-pill/styles.ts | 5 +-
.../ui/src/composites/wui-button/styles.ts | 2 +-
packages/ui/src/composites/wui-chip/styles.ts | 4 +-
.../wui-compatible-network/index.tsx | 8 +-
.../composites/wui-connect-button/styles.ts | 2 +-
.../src/composites/wui-input-text/styles.ts | 2 +-
.../src/composites/wui-list-wallet/index.tsx | 13 +-
.../composites/wui-network-button/styles.ts | 2 +-
packages/ui/src/composites/wui-otp/index.tsx | 5 +-
.../ui/src/composites/wui-promo/index.tsx | 42 ++
.../ui/src/composites/wui-snackbar/styles.ts | 2 +-
packages/ui/src/composites/wui-tabs/styles.ts | 2 +-
.../src/composites/wui-wallet-image/styles.ts | 2 +-
packages/ui/src/index.ts | 1 +
packages/ui/src/layout/wui-flex/index.tsx | 6 +-
.../ui/src/layout/wui-separator/index.tsx | 11 +-
packages/ui/src/utils/TypesUtil.ts | 12 +
packages/wagmi/src/client.ts | 24 +-
packages/wallet/src/AppKitAuthWebview.tsx | 127 +++--
packages/wallet/src/AppKitFrameConstants.ts | 15 +-
packages/wallet/src/AppKitFrameProvider.ts | 192 ++++---
packages/wallet/src/AppKitFrameSchema.ts | 68 ++-
packages/wallet/src/AppKitFrameTypes.ts | 17 +-
packages/wallet/src/AppKitWebview.tsx | 6 +-
yarn.lock | 520 ++++++++++++------
92 files changed, 1626 insertions(+), 546 deletions(-)
create mode 100644 .changeset/serious-tables-compare.md
create mode 100644 packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/index.tsx
create mode 100644 packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/styles.ts
create mode 100644 packages/ui/src/assets/visual/Google.tsx
create mode 100644 packages/ui/src/assets/visual/Lightbulb.tsx
create mode 100644 packages/ui/src/assets/visual/Pencil.tsx
create mode 100644 packages/ui/src/components/wui-lean-text/index.tsx
create mode 100644 packages/ui/src/components/wui-lean-view/index.tsx
create mode 100644 packages/ui/src/composites/wui-promo/index.tsx
diff --git a/.changeset/serious-tables-compare.md b/.changeset/serious-tables-compare.md
new file mode 100644
index 000000000..167a81ac8
--- /dev/null
+++ b/.changeset/serious-tables-compare.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': minor
+'@reown/appkit-coinbase-wagmi-react-native': minor
+'@reown/appkit-scaffold-utils-react-native': minor
+'@reown/appkit-auth-ethers-react-native': minor
+'@reown/appkit-auth-wagmi-react-native': minor
+'@reown/appkit-scaffold-react-native': minor
+'@reown/appkit-ethers5-react-native': minor
+'@reown/appkit-common-react-native': minor
+'@reown/appkit-ethers-react-native': minor
+'@reown/appkit-wallet-react-native': minor
+'@reown/appkit-wagmi-react-native': minor
+'@reown/appkit-core-react-native': minor
+'@reown/appkit-siwe-react-native': minor
+'@reown/appkit-ui-react-native': minor
+---
+
+feat: smart accounts for social login
diff --git a/apps/native/App.tsx b/apps/native/App.tsx
index d5ba189e4..d8036e3f8 100644
--- a/apps/native/App.tsx
+++ b/apps/native/App.tsx
@@ -65,8 +65,8 @@ createAppKit({
metadata,
features: {
email: true,
- socials: ['x', 'discord', 'apple', 'farcaster', 'facebook'],
- emailShowWallets: true
+ socials: ['x', 'farcaster', 'discord', 'apple'],
+ emailShowWallets: false
}
});
diff --git a/apps/native/babel.config.js b/apps/native/babel.config.js
index 98ae29e0e..425262ac6 100644
--- a/apps/native/babel.config.js
+++ b/apps/native/babel.config.js
@@ -1,8 +1,11 @@
const path = require('path');
-const uipak = require('../../packages/ui/package.json');
-const corepak = require('../../packages/core/package.json');
-const scaffoldpak = require('../../packages/scaffold/package.json');
-const wagmipak = require('../../packages/wagmi/package.json');
+const uipack = require('../../packages/ui/package.json');
+const corepack = require('../../packages/core/package.json');
+const scaffoldpack = require('../../packages/scaffold/package.json');
+const wagmipack = require('../../packages/wagmi/package.json');
+const authpack = require('../../packages/auth-wagmi/package.json');
+const commonpack = require('../../packages/common/package.json');
+const siwepack = require('../../packages/siwe/package.json');
module.exports = function (api) {
api.cache(true);
@@ -15,11 +18,18 @@ module.exports = function (api) {
{
extensions: ['.tsx', '.ts', '.js', '.json'],
alias: {
- // For development, we want to alias the ui library to the source
- [uipak.name]: path.join(__dirname, '../../packages/ui', uipak.source),
- [corepak.name]: path.join(__dirname, '../../packages/core', corepak.source),
- [scaffoldpak.name]: path.join(__dirname, '../../packages/scaffold', scaffoldpak.source),
- [wagmipak.name]: path.join(__dirname, '../../packages/wagmi', wagmipak.source)
+ // For development, we want to alias the packages to the source
+ [uipack.name]: path.join(__dirname, '../../packages/ui', uipack.source),
+ [corepack.name]: path.join(__dirname, '../../packages/core', corepack.source),
+ [scaffoldpack.name]: path.join(
+ __dirname,
+ '../../packages/scaffold',
+ scaffoldpack.source
+ ),
+ [wagmipack.name]: path.join(__dirname, '../../packages/wagmi', wagmipack.source),
+ [authpack.name]: path.join(__dirname, '../../packages/auth-wagmi', authpack.source),
+ [commonpack.name]: path.join(__dirname, '../../packages/common', commonpack.source),
+ [siwepack.name]: path.join(__dirname, '../../packages/siwe', siwepack.source)
}
}
]
diff --git a/apps/native/package.json b/apps/native/package.json
index 1116eecfb..835192799 100644
--- a/apps/native/package.json
+++ b/apps/native/package.json
@@ -22,7 +22,7 @@
"@tanstack/query-async-storage-persister": "^5.40.0",
"@tanstack/react-query": "5.56.2",
"@tanstack/react-query-persist-client": "5.56.2",
- "@walletconnect/react-native-compat": "2.16.1",
+ "@walletconnect/react-native-compat": "2.17.1",
"expo": "~51.0.24",
"expo-application": "~5.9.1",
"expo-clipboard": "~6.0.3",
@@ -37,8 +37,8 @@
"react-native-web": "~0.19.10",
"react-native-webview": "13.8.6",
"uuid": "3.4.0",
- "viem": "2.21.6",
- "wagmi": "2.12.11"
+ "viem": "2.21.37",
+ "wagmi": "2.12.25"
},
"devDependencies": {
"@babel/core": "^7.24.0",
diff --git a/apps/native/src/utils/WagmiUtils.ts b/apps/native/src/utils/WagmiUtils.ts
index ef523b153..f2b1da93c 100644
--- a/apps/native/src/utils/WagmiUtils.ts
+++ b/apps/native/src/utils/WagmiUtils.ts
@@ -14,7 +14,7 @@ import {
sepolia
} from 'wagmi/chains';
-export const chains = [
+export const chains: CreateConfigParameters['chains'] = [
mainnet,
polygon,
avalanche,
@@ -27,4 +27,4 @@ export const chains = [
celo,
aurora,
sepolia
-] as CreateConfigParameters['chains'];
+];
diff --git a/apps/native/src/views/ActionsView.tsx b/apps/native/src/views/ActionsView.tsx
index 84b68d819..39cb70c22 100644
--- a/apps/native/src/views/ActionsView.tsx
+++ b/apps/native/src/views/ActionsView.tsx
@@ -26,14 +26,14 @@ export function ActionsView() {
signMessage({ message: 'Hello AppKit!' })}>
Sign
- {isSuccess && Signature: {data}}
+ {isSuccess && Signature: {data}}
{isGasError && Error estimating gas}
{isError && Error signing message}
sendTransaction({ ...TX, gas })}>
Send
{isSending && Check Wallet}
- {isSendSuccess && Transaction: {JSON.stringify(sendData)}}
+ {isSendSuccess && Transaction: {JSON.stringify(sendData)}}
) : null;
}
diff --git a/package.json b/package.json
index 85e3c61ab..a837e27cc 100644
--- a/package.json
+++ b/package.json
@@ -69,8 +69,8 @@
"tsconfig": "*",
"turbo": "2.1.1",
"typescript": "5.2.2",
- "viem": "2.21.6",
- "wagmi": "2.12.11"
+ "viem": "2.21.37",
+ "wagmi": "2.12.25"
},
"packageManager": "yarn@4.0.2"
}
diff --git a/packages/auth-wagmi/package.json b/packages/auth-wagmi/package.json
index db5386a65..23546060d 100644
--- a/packages/auth-wagmi/package.json
+++ b/packages/auth-wagmi/package.json
@@ -36,6 +36,7 @@
"access": "public"
},
"dependencies": {
+ "@reown/appkit-core-react-native": "1.0.2",
"@reown/appkit-wallet-react-native": "1.0.2"
},
"peerDependencies": {
diff --git a/packages/auth-wagmi/src/index.ts b/packages/auth-wagmi/src/index.ts
index 934b8bb72..b9859d6ab 100644
--- a/packages/auth-wagmi/src/index.ts
+++ b/packages/auth-wagmi/src/index.ts
@@ -1,7 +1,8 @@
import { createConnector, ChainNotConfiguredError } from 'wagmi';
-import { SwitchChainError, getAddress, type Address } from 'viem';
+import { SwitchChainError, getAddress, type Address, type Hex } from 'viem';
import { AppKitFrameProvider } from '@reown/appkit-wallet-react-native';
+import { StorageUtil } from '@reown/appkit-core-react-native';
export type Metadata = {
name: string;
@@ -22,13 +23,15 @@ type AuthConnectorOptions = {
type Provider = AppKitFrameProvider;
type StorageItemMap = {
- '@w3m/connected_connector'?: string;
+ recentConnectorId?: string;
};
authConnector.type = 'appKitAuth' as const;
authConnector.id = 'appKitAuth' as const;
export function authConnector(parameters: AuthConnectorOptions) {
let _provider: AppKitFrameProvider = {} as AppKitFrameProvider;
+ let _currentAddress: Address | null = null;
+ let _chainId: number | null = null;
return createConnector(config => ({
id: authConnector.id,
@@ -39,15 +42,27 @@ export function authConnector(parameters: AuthConnectorOptions) {
},
async connect(options = {}) {
const provider = await this.getProvider();
+ let chainId = options.chainId;
await provider.webviewLoadPromise;
- const { address, chainId } = await provider.connect({ chainId: options.chainId });
+
+ if (options.isReconnecting) {
+ chainId = await provider.getLastUsedChainId();
+ if (!chainId) {
+ throw new Error('ChainId not found in provider');
+ }
+ }
+
+ const { address, chainId: frameChainId } = await provider.connect({ chainId });
+
+ _chainId = frameChainId as number;
+ _currentAddress = address as Address;
return {
- accounts: [address as Address],
- account: address as Address,
- chainId: chainId as number,
+ accounts: [_currentAddress as Address],
+ account: _currentAddress as Address,
+ chainId: frameChainId as number,
chain: {
- id: chainId as number,
+ id: frameChainId as number,
unsuported: false
}
};
@@ -56,6 +71,8 @@ export function authConnector(parameters: AuthConnectorOptions) {
const provider = await this.getProvider();
await provider.webviewLoadPromise;
await provider.disconnect();
+ _chainId = null;
+ _currentAddress = null;
},
async switchChain({ chainId }) {
try {
@@ -64,8 +81,15 @@ export function authConnector(parameters: AuthConnectorOptions) {
const provider = await this.getProvider();
await provider.webviewLoadPromise;
- await provider.switchNetwork(chainId);
- config.emitter.emit('change', { chainId: Number(chainId) });
+
+ // We connect instead, since changing the chain may cause the address to change as well
+ const response = await provider.connect({ chainId });
+
+ config.emitter.emit('change', {
+ chainId: Number(chainId),
+ accounts: [response.address as Hex]
+ });
+ _chainId = chainId;
return chain;
} catch (error) {
@@ -76,6 +100,8 @@ export function authConnector(parameters: AuthConnectorOptions) {
}
},
async getAccounts() {
+ if (_currentAddress) return [_currentAddress];
+
const provider = await this.getProvider();
await provider.webviewLoadPromise;
@@ -86,6 +112,8 @@ export function authConnector(parameters: AuthConnectorOptions) {
).map(getAddress);
},
async getChainId() {
+ if (_chainId) return _chainId;
+
const provider = await this.getProvider();
await provider.webviewLoadPromise;
const { chainId } = await provider.getChainId();
@@ -97,31 +125,32 @@ export function authConnector(parameters: AuthConnectorOptions) {
},
async isAuthorized() {
try {
+ const connectedConnector = await StorageUtil.getConnectedConnector();
+ if (connectedConnector && connectedConnector !== 'AUTH') {
+ return false;
+ }
+
const provider = await this.getProvider();
await provider.webviewLoadPromise;
- const connectedConnector = await config.storage?.getItem('recentConnectorId');
-
- if (connectedConnector !== authConnector.id) {
- // isConnected still needs to be called to disable email input loader
- provider.isConnected();
+ const { isConnected } = await provider.isConnected();
- return false;
- } else {
- const { isConnected } = await provider.isConnected();
-
- return isConnected;
- }
+ return isConnected;
} catch (error) {
return false;
}
},
onAccountsChanged(accounts) {
if (accounts.length === 0) config.emitter.emit('disconnect');
- else config.emitter.emit('change', { accounts: accounts.map(getAddress) });
+ else {
+ const account = accounts[0] ? getAddress(accounts[0]) : null;
+ config.emitter.emit('change', { accounts: account ? [account] : undefined });
+ _currentAddress = account;
+ }
},
onChainChanged(chain) {
const chainId = Number(chain);
config.emitter.emit('change', { chainId });
+ _chainId = chainId;
},
async onDisconnect() {
const provider = await this.getProvider();
diff --git a/packages/common/src/utils/TypeUtil.ts b/packages/common/src/utils/TypeUtil.ts
index ba09aaa26..208e8fee2 100644
--- a/packages/common/src/utils/TypeUtil.ts
+++ b/packages/common/src/utils/TypeUtil.ts
@@ -86,11 +86,4 @@ export interface TransactionQuantity {
numeric: string;
}
-export type SocialProvider =
- | 'google'
- | 'github'
- | 'apple'
- | 'facebook'
- | 'x'
- | 'discord'
- | 'farcaster';
+export type SocialProvider = 'apple' | 'x' | 'discord' | 'farcaster';
diff --git a/packages/core/src/__tests__/controllers/AccountController.test.ts b/packages/core/src/__tests__/controllers/AccountController.test.ts
index 2398d562a..4783f804c 100644
--- a/packages/core/src/__tests__/controllers/AccountController.test.ts
+++ b/packages/core/src/__tests__/controllers/AccountController.test.ts
@@ -9,7 +9,9 @@ const profileImage = 'https://ipfs.com/0x123.png';
const initialState = {
isConnected: false,
- tokenBalance: []
+ tokenBalance: [],
+ preferredAccountType: 'eoa',
+ smartAccountDeployed: false
};
// -- Tests --------------------------------------------------------------------
diff --git a/packages/core/src/__tests__/controllers/NetworkController.test.ts b/packages/core/src/__tests__/controllers/NetworkController.test.ts
index 5018c0657..9202383c5 100644
--- a/packages/core/src/__tests__/controllers/NetworkController.test.ts
+++ b/packages/core/src/__tests__/controllers/NetworkController.test.ts
@@ -16,6 +16,13 @@ const client: NetworkControllerClient = {
Promise.resolve({ approvedCaipNetworkIds, supportsAllNetworks: false })
};
+const initialState = {
+ _client: client,
+ supportsAllNetworks: true,
+ isDefaultCaipNetwork: false,
+ smartAccountEnabledNetworks: []
+};
+
// -- Tests --------------------------------------------------------------------
describe('NetworkController', () => {
it('should throw if client not set', () => {
@@ -25,11 +32,7 @@ describe('NetworkController', () => {
it('should have valid default state', () => {
NetworkController.setClient(client);
- expect(NetworkController.state).toEqual({
- _client: NetworkController._getClient(),
- supportsAllNetworks: true,
- isDefaultCaipNetwork: false
- });
+ expect(NetworkController.state).toEqual(initialState);
});
it('should update state correctly on setRequestedCaipNetworks()', () => {
diff --git a/packages/core/src/controllers/AccountController.ts b/packages/core/src/controllers/AccountController.ts
index 344aafb87..808d38f41 100644
--- a/packages/core/src/controllers/AccountController.ts
+++ b/packages/core/src/controllers/AccountController.ts
@@ -3,7 +3,7 @@ import { subscribeKey as subKey } from 'valtio/utils';
import type { Balance } from '@reown/appkit-common-react-native';
import { CoreHelperUtil } from '../utils/CoreHelperUtil';
-import type { CaipAddress, ConnectedWalletInfo } from '../utils/TypeUtil';
+import type { AppKitFrameAccountType, CaipAddress, ConnectedWalletInfo } from '../utils/TypeUtil';
import { NetworkController } from './NetworkController';
import { BlockchainApiController } from './BlockchainApiController';
import { SnackController } from './SnackController';
@@ -20,6 +20,8 @@ export interface AccountControllerState {
profileImage?: string;
addressExplorerUrl?: string;
connectedWalletInfo?: ConnectedWalletInfo;
+ preferredAccountType?: AppKitFrameAccountType;
+ smartAccountDeployed?: boolean;
}
type StateKey = keyof AccountControllerState;
@@ -27,7 +29,9 @@ type StateKey = keyof AccountControllerState;
// -- State --------------------------------------------- //
const state = proxy({
isConnected: false,
- tokenBalance: []
+ tokenBalance: [],
+ smartAccountDeployed: false,
+ preferredAccountType: 'eoa'
});
// -- Controller ---------------------------------------- //
@@ -76,6 +80,14 @@ export const AccountController = {
state.addressExplorerUrl = explorerUrl;
},
+ setPreferredAccountType(accountType: AccountControllerState['preferredAccountType']) {
+ state.preferredAccountType = accountType;
+ },
+
+ setSmartAccountDeployed(smartAccountDeployed: AccountControllerState['smartAccountDeployed']) {
+ state.smartAccountDeployed = smartAccountDeployed;
+ },
+
async fetchTokenBalance() {
const chainId = NetworkController.state.caipNetwork?.id;
const address = AccountController.state.address;
@@ -110,5 +122,7 @@ export const AccountController = {
state.addressExplorerUrl = undefined;
state.tokenBalance = [];
state.connectedWalletInfo = undefined;
+ state.preferredAccountType = 'eoa';
+ state.smartAccountDeployed = false;
}
};
diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts
index a7b2d1b61..0e3057903 100644
--- a/packages/core/src/controllers/ConnectionController.ts
+++ b/packages/core/src/controllers/ConnectionController.ts
@@ -1,5 +1,6 @@
-import { subscribeKey as subKey } from 'valtio/utils';
import { proxy, ref } from 'valtio';
+import { subscribeKey as subKey } from 'valtio/utils';
+import type { SocialProvider } from '@reown/appkit-common-react-native';
import { CoreHelperUtil } from '../utils/CoreHelperUtil';
import { StorageUtil } from '../utils/StorageUtil';
import type {
@@ -10,7 +11,6 @@ import type {
} from '../utils/TypeUtil';
import { RouterController } from './RouterController';
import { ConnectorController } from './ConnectorController';
-import type { SocialProvider } from '@reown/appkit-common-react-native';
// -- Types --------------------------------------------- //
export interface ConnectExternalOptions {
@@ -86,15 +86,11 @@ export const ConnectionController = {
state.wcPromise = this._getClient().connectWalletConnect(uri => {
state.wcUri = uri;
state.wcPairingExpiry = CoreHelperUtil.getPairingExpiry();
- ConnectorController.setConnectedConnector('WALLET_CONNECT');
- StorageUtil.setConnectedConnector('WALLET_CONNECT');
}, walletUniversalLink);
},
async connectExternal(options: ConnectExternalOptions) {
await this._getClient().connectExternal?.(options);
- ConnectorController.setConnectedConnector(options.type);
- StorageUtil.setConnectedConnector(options.type);
},
async signMessage(message: string) {
@@ -179,13 +175,10 @@ export const ConnectionController = {
resetWcConnection() {
this.clearUri();
state.pressedWallet = undefined;
- state.connectedWalletImageUrl = undefined;
- state.connectedSocialProvider = undefined;
+ ConnectionController.setConnectedSocialProvider(undefined);
+ ConnectionController.setConnectedWalletImageUrl(undefined);
ConnectorController.setConnectedConnector(undefined);
StorageUtil.removeWalletConnectDeepLink();
- StorageUtil.removeConnectedWalletImageUrl();
- StorageUtil.removeConnectedConnector();
- StorageUtil.removeConnectedSocialProvider();
},
async disconnect() {
diff --git a/packages/core/src/controllers/ConnectorController.ts b/packages/core/src/controllers/ConnectorController.ts
index c634ae52e..a74a4c1c5 100644
--- a/packages/core/src/controllers/ConnectorController.ts
+++ b/packages/core/src/controllers/ConnectorController.ts
@@ -1,6 +1,7 @@
import { subscribeKey as subKey } from 'valtio/utils';
import { proxy, ref } from 'valtio';
import type { Connector, ConnectorType } from '../utils/TypeUtil';
+import { StorageUtil } from '../utils/StorageUtil';
// -- Types --------------------------------------------- //
export interface ConnectorControllerState {
@@ -40,8 +41,19 @@ export const ConnectorController = {
return state.connectors.find(c => c.type === 'AUTH');
},
- setConnectedConnector(connectorType: ConnectorControllerState['connectedConnector']) {
+ setConnectedConnector(
+ connectorType: ConnectorControllerState['connectedConnector'],
+ saveStorage = true
+ ) {
state.connectedConnector = connectorType;
+
+ if (saveStorage) {
+ if (connectorType) {
+ StorageUtil.setConnectedConnector(connectorType);
+ } else {
+ StorageUtil.removeConnectedConnector();
+ }
+ }
},
setAuthLoading(loading: ConnectorControllerState['authLoading']) {
diff --git a/packages/core/src/controllers/NetworkController.ts b/packages/core/src/controllers/NetworkController.ts
index 1468cba9f..b45c01088 100644
--- a/packages/core/src/controllers/NetworkController.ts
+++ b/packages/core/src/controllers/NetworkController.ts
@@ -1,6 +1,7 @@
import { proxy, ref } from 'valtio';
import type { CaipNetwork, CaipNetworkId } from '../utils/TypeUtil';
import { PublicStateController } from './PublicStateController';
+import { NetworkUtil } from '@reown/appkit-common-react-native';
// -- Types --------------------------------------------- //
export interface NetworkControllerClient {
@@ -18,12 +19,14 @@ export interface NetworkControllerState {
caipNetwork?: CaipNetwork;
requestedCaipNetworks?: CaipNetwork[];
approvedCaipNetworkIds?: CaipNetworkId[];
+ smartAccountEnabledNetworks: number[];
}
// -- State --------------------------------------------- //
const state = proxy({
supportsAllNetworks: true,
- isDefaultCaipNetwork: false
+ isDefaultCaipNetwork: false,
+ smartAccountEnabledNetworks: []
});
// -- Controller ---------------------------------------- //
@@ -57,6 +60,22 @@ export const NetworkController = {
state.requestedCaipNetworks = requestedNetworks;
},
+ setSmartAccountEnabledNetworks(
+ smartAccountEnabledNetworks: NetworkControllerState['smartAccountEnabledNetworks']
+ ) {
+ state.smartAccountEnabledNetworks = smartAccountEnabledNetworks;
+ },
+
+ checkIfSmartAccountEnabled() {
+ const networkId = NetworkUtil.caipNetworkIdToNumber(state.caipNetwork?.id);
+
+ if (!networkId) {
+ return false;
+ }
+
+ return Boolean(state.smartAccountEnabledNetworks?.includes(Number(networkId)));
+ },
+
async getApprovedCaipNetworksData() {
const data = await this._getClient().getApprovedCaipNetworksData();
state.supportsAllNetworks = data.supportsAllNetworks;
@@ -81,5 +100,6 @@ export const NetworkController = {
}
state.approvedCaipNetworkIds = undefined;
state.supportsAllNetworks = true;
+ state.smartAccountEnabledNetworks = [];
}
};
diff --git a/packages/core/src/controllers/OptionsController.ts b/packages/core/src/controllers/OptionsController.ts
index acbaba1c6..7140589ae 100644
--- a/packages/core/src/controllers/OptionsController.ts
+++ b/packages/core/src/controllers/OptionsController.ts
@@ -4,6 +4,7 @@ import type {
Features,
Metadata,
ProjectId,
+ SdkType,
SdkVersion,
Tokens
} from '../utils/TypeUtil';
@@ -23,7 +24,7 @@ export interface OptionsControllerState {
customWallets?: CustomWallet[];
tokens?: Tokens;
enableAnalytics?: boolean;
- sdkType: string;
+ sdkType: SdkType;
sdkVersion: SdkVersion;
metadata?: Metadata;
isSiweEnabled?: boolean;
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index 92fd80a73..a472288ed 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -35,6 +35,7 @@ export interface RouterControllerState {
| 'UpdateEmailSecondaryOtp'
| 'UpdateEmailWallet'
| 'UpgradeEmailWallet'
+ | 'UpgradeToSmartAccount'
| 'WalletCompatibleNetworks'
| 'WalletReceive'
| 'WalletSend'
diff --git a/packages/core/src/controllers/SendController.ts b/packages/core/src/controllers/SendController.ts
index ab97b33ab..3aa0141e1 100644
--- a/packages/core/src/controllers/SendController.ts
+++ b/packages/core/src/controllers/SendController.ts
@@ -97,7 +97,7 @@ export const SendController = {
type: 'track',
event: 'SEND_INITIATED',
properties: {
- isSmartAccount: false,
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount',
token: this.state.token.address,
amount: this.state.sendTokenAmount,
network: NetworkController.state.caipNetwork?.id || ''
@@ -120,7 +120,7 @@ export const SendController = {
type: 'track',
event: 'SEND_INITIATED',
properties: {
- isSmartAccount: false,
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount',
token: this.state.token?.symbol,
amount: this.state.sendTokenAmount,
network: NetworkController.state.caipNetwork?.id || ''
@@ -162,7 +162,7 @@ export const SendController = {
type: 'track',
event: 'SEND_SUCCESS',
properties: {
- isSmartAccount: false,
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount',
token: this.state.token?.symbol || '',
amount: params.sendTokenAmount,
network: NetworkController.state.caipNetwork?.id || ''
@@ -175,7 +175,7 @@ export const SendController = {
type: 'track',
event: 'SEND_ERROR',
properties: {
- isSmartAccount: false,
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount',
token: this.state.token?.symbol || '',
amount: params.sendTokenAmount,
network: NetworkController.state.caipNetwork?.id || ''
diff --git a/packages/core/src/controllers/TransactionsController.ts b/packages/core/src/controllers/TransactionsController.ts
index af350299f..333f1d5c9 100644
--- a/packages/core/src/controllers/TransactionsController.ts
+++ b/packages/core/src/controllers/TransactionsController.ts
@@ -5,6 +5,7 @@ import { EventsController } from './EventsController';
import { SnackController } from './SnackController';
import { NetworkController } from './NetworkController';
import { BlockchainApiController } from './BlockchainApiController';
+import { AccountController } from './AccountController';
// -- Types --------------------------------------------- //
type TransactionByMonthMap = Record;
@@ -74,7 +75,7 @@ export const TransactionsController = {
address: accountAddress,
projectId,
cursor: state.next,
- isSmartAccount: false
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
}
});
SnackController.showError('Failed to fetch transactions');
diff --git a/packages/core/src/utils/ConstantsUtil.ts b/packages/core/src/utils/ConstantsUtil.ts
index a4f7ea25f..8e537210f 100644
--- a/packages/core/src/utils/ConstantsUtil.ts
+++ b/packages/core/src/utils/ConstantsUtil.ts
@@ -3,7 +3,7 @@ import type { Features } from './TypeUtil';
const defaultFeatures: Features = {
email: true,
emailShowWallets: true,
- socials: ['x', 'discord', 'github', 'apple', 'facebook', 'farcaster']
+ socials: ['x', 'discord', 'apple', 'farcaster']
};
export const ConstantsUtil = {
diff --git a/packages/core/src/utils/StorageUtil.ts b/packages/core/src/utils/StorageUtil.ts
index 6bf3218d2..e340d58b6 100644
--- a/packages/core/src/utils/StorageUtil.ts
+++ b/packages/core/src/utils/StorageUtil.ts
@@ -92,7 +92,7 @@ export const StorageUtil = {
}
},
- async getConnectedConnector() {
+ async getConnectedConnector(): Promise {
try {
const connector = (await AsyncStorage.getItem(CONNECTED_CONNECTOR)) as ConnectorType;
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 03ddc6f84..6d7ce82a0 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -56,6 +56,8 @@ export type CaipNamespaces = Record<
}
>;
+export type SdkType = 'appkit';
+
export type SdkVersion =
| `react-native-wagmi-${string}`
| `react-native-ethers5-${string}`
@@ -375,18 +377,34 @@ export type Event =
| {
type: 'track';
event: 'CLICK_SIGN_SIWE_MESSAGE';
+ properties: {
+ network: string;
+ isSmartAccount: boolean;
+ };
}
| {
type: 'track';
event: 'CLICK_CANCEL_SIWE';
+ properties: {
+ network: string;
+ isSmartAccount: boolean;
+ };
}
| {
type: 'track';
event: 'SIWE_AUTH_SUCCESS';
+ properties: {
+ network: string;
+ isSmartAccount: boolean;
+ };
}
| {
type: 'track';
event: 'SIWE_AUTH_ERROR';
+ properties: {
+ network: string;
+ isSmartAccount: boolean;
+ };
}
| {
type: 'track';
@@ -473,6 +491,14 @@ export type Event =
properties: {
provider: SocialProvider;
};
+ }
+ | {
+ type: 'track';
+ event: 'SET_PREFERRED_ACCOUNT_TYPE';
+ properties: {
+ accountType: AppKitFrameAccountType;
+ network: string;
+ };
};
// -- Send Controller Types -------------------------------------
@@ -500,6 +526,9 @@ export interface WriteContractArgs {
* Matches type defined for packages/wallet/src/AppKitFrameProvider.ts
* It's duplicated in order to decouple scaffold from email package
*/
+
+export type AppKitFrameAccountType = 'eoa' | 'smartAccount';
+
export interface AppKitFrameProvider {
readonly id: string;
readonly name: string;
@@ -510,6 +539,7 @@ export interface AppKitFrameProvider {
getSecureSiteHeaders(): Record;
getEmail(): string | undefined;
getUsername(): string | undefined;
+ getLastUsedChainId(): Promise;
rejectRpcRequest(): void;
connectEmail(payload: { email: string }): Promise<{
action: 'VERIFY_DEVICE' | 'VERIFY_OTP';
@@ -519,19 +549,17 @@ export interface AppKitFrameProvider {
chainId: string | number;
email: string;
address: string;
- accounts?:
- | {
- type: 'eoa' | 'smartAccount';
- address: string;
- }[]
- | undefined;
- userName?: string | undefined;
+ accounts?: {
+ type: AppKitFrameAccountType;
+ address: string;
+ }[];
+ userName?: string;
}>;
getSocialRedirectUri(payload: { provider: SocialProvider }): Promise<{
uri: string;
}>;
connectOtp(payload: { otp: string }): Promise;
- connectFarcaster: () => Promise<{ username: string }>;
+ connectFarcaster: () => Promise<{ userName: string }>;
getFarcasterUri(): Promise<{ url: string }>;
isConnected(): Promise<{
isConnected: boolean;
@@ -553,18 +581,31 @@ export interface AppKitFrameProvider {
syncDappData(payload: {
projectId: string;
sdkVersion: SdkVersion;
+ sdkType: SdkType;
metadata?: Metadata;
}): Promise;
connect(payload?: { chainId: number | undefined }): Promise<{
chainId: number;
- email: string;
+ email?: string | null;
address: string;
+ smartAccountDeployed: boolean;
+ preferredAccountType: AppKitFrameAccountType;
}>;
switchNetwork(chainId: number): Promise<{
chainId: number;
}>;
+ setPreferredAccount(type: AppKitFrameAccountType): Promise<{
+ type: AppKitFrameAccountType;
+ address: string;
+ }>;
+ getSmartAccountEnabledNetworks(): Promise<{
+ smartAccountEnabledNetworks: number[];
+ }>;
disconnect(): Promise;
request(req: any): Promise;
AuthView: () => JSX.Element | null;
Webview: () => JSX.Element | null;
+ onSetPreferredAccount: (
+ callback: (values: { type: AppKitFrameAccountType; address: string }) => void
+ ) => void;
}
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 6f6659de9..3147c523c 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -24,7 +24,8 @@ import {
type SendTransactionArgs,
type Token,
AppKitScaffold,
- type WriteContractArgs
+ type WriteContractArgs,
+ type AppKitFrameAccountType
} from '@reown/appkit-scaffold-react-native';
import { erc20ABI, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import {
@@ -126,9 +127,9 @@ export class AppKit extends AppKitScaffold {
new Promise(async resolve => {
const walletChoice = await StorageUtil.getConnectedConnector();
const walletConnectType =
- PresetsUtil.ConnectorTypesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID];
+ PresetsUtil.ConnectorTypesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID]!;
- const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID];
+ const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID]!;
if (walletChoice?.includes(walletConnectType)) {
const provider = await this.getWalletConnectProvider();
const result = getWalletConnectCaipNetworks(provider);
@@ -399,8 +400,8 @@ export class AppKit extends AppKitScaffold {
this.createProvider();
- EthersStoreUtil.subscribeKey('address', () => {
- this.syncAccount();
+ EthersStoreUtil.subscribeKey('address', address => {
+ this.syncAccount({ address });
});
EthersStoreUtil.subscribeKey('chainId', () => {
@@ -681,12 +682,10 @@ export class AppKit extends AppKitScaffold {
}
}
- private async syncAccount() {
- const address = EthersStoreUtil.state.address;
+ private async syncAccount({ address }: { address?: Address }) {
const chainId = EthersStoreUtil.state.chainId;
const isConnected = EthersStoreUtil.state.isConnected;
- this.resetAccount();
if (isConnected && address && chainId) {
const caipAddress: CaipAddress = `${ConstantsUtil.EIP155}:${chainId}:${address}`;
@@ -701,6 +700,7 @@ export class AppKit extends AppKitScaffold {
]);
this.hasSyncedConnectedAccount = true;
} else if (!isConnected && this.hasSyncedConnectedAccount) {
+ this.resetAccount();
this.resetWcConnection();
this.resetNetwork();
}
@@ -874,6 +874,20 @@ export class AppKit extends AppKitScaffold {
}
}
+ private async handleAuthSetPreferredAccount(address: string, type: AppKitFrameAccountType) {
+ if (!address) {
+ return;
+ }
+
+ const chainId = this.getCaipNetwork()?.id;
+ const caipAddress: CaipAddress = `${ConstantsUtil.EIP155}:${chainId}:${address}`;
+ this.setCaipAddress(caipAddress);
+ this.setPreferredAccountType(type);
+
+ await this.syncAccount({ address: address as Address });
+ this.setLoading(false);
+ }
+
private syncConnectors(config: ProviderType) {
const _connectors: Connector[] = [];
const EXCLUDED_CONNECTORS = [ConstantsUtil.AUTH_CONNECTOR_ID];
@@ -939,5 +953,16 @@ export class AppKit extends AppKitScaffold {
if (isConnected) {
this.setAuthProvider();
}
+
+ this.addAuthListeners(this.authProvider);
+ }
+
+ private async addAuthListeners(authProvider: AppKitFrameProvider) {
+ authProvider.onSetPreferredAccount(async ({ address, type }) => {
+ if (address) {
+ await this.handleAuthSetPreferredAccount(address, type);
+ }
+ this.setLoading(false);
+ });
}
}
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index cb38f6a79..f700f5f8a 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -1,5 +1,6 @@
import { Contract, ethers, utils } from 'ethers';
import {
+ type AppKitFrameAccountType,
type CaipAddress,
type CaipNetwork,
type CaipNetworkId,
@@ -113,9 +114,9 @@ export class AppKit extends AppKitScaffold {
new Promise(async resolve => {
const walletChoice = await StorageUtil.getConnectedConnector();
const walletConnectType =
- PresetsUtil.ConnectorTypesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID];
+ PresetsUtil.ConnectorTypesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID]!;
- const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID];
+ const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID]!;
if (walletChoice?.includes(walletConnectType)) {
const provider = await this.getWalletConnectProvider();
const result = getWalletConnectCaipNetworks(provider);
@@ -381,8 +382,8 @@ export class AppKit extends AppKitScaffold {
this.createProvider();
- EthersStoreUtil.subscribeKey('address', () => {
- this.syncAccount();
+ EthersStoreUtil.subscribeKey('address', address => {
+ this.syncAccount({ address });
});
EthersStoreUtil.subscribeKey('chainId', () => {
@@ -661,12 +662,10 @@ export class AppKit extends AppKitScaffold {
}
}
- private async syncAccount() {
- const address = EthersStoreUtil.state.address;
+ private async syncAccount({ address }: { address?: Address }) {
const chainId = EthersStoreUtil.state.chainId;
const isConnected = EthersStoreUtil.state.isConnected;
- this.resetAccount();
if (isConnected && address && chainId) {
const caipAddress: CaipAddress = `${ConstantsUtil.EIP155}:${chainId}:${address}`;
@@ -681,6 +680,7 @@ export class AppKit extends AppKitScaffold {
]);
this.hasSyncedConnectedAccount = true;
} else if (!isConnected && this.hasSyncedConnectedAccount) {
+ this.resetAccount();
this.resetWcConnection();
this.resetNetwork();
}
@@ -853,6 +853,18 @@ export class AppKit extends AppKitScaffold {
}
}
+ private async handleAuthSetPreferredAccount(address: string, type: AppKitFrameAccountType) {
+ if (!address) {
+ return;
+ }
+ const chainId = this.getCaipNetwork()?.id;
+ const caipAddress: CaipAddress = `${ConstantsUtil.EIP155}:${chainId}:${address}`;
+ this.setCaipAddress(caipAddress);
+ this.setPreferredAccountType(type);
+ await this.syncAccount({ address: address as Address });
+ this.setLoading(false);
+ }
+
private syncConnectors(config: ProviderType) {
const _connectors: Connector[] = [];
const EXCLUDED_CONNECTORS = [ConstantsUtil.AUTH_CONNECTOR_ID];
@@ -918,5 +930,16 @@ export class AppKit extends AppKitScaffold {
if (isConnected) {
this.setAuthProvider();
}
+
+ this.addAuthListeners(this.authProvider);
+ }
+
+ private async addAuthListeners(authProvider: AppKitFrameProvider) {
+ authProvider.onSetPreferredAccount(async ({ address, type }) => {
+ if (address) {
+ await this.handleAuthSetPreferredAccount(address, type);
+ }
+ this.setLoading(false);
+ });
}
}
diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts
index 0878c85df..18b863c2c 100644
--- a/packages/scaffold/src/client.ts
+++ b/packages/scaffold/src/client.ts
@@ -228,6 +228,11 @@ export class AppKitScaffold {
BlockchainApiController.setClientId(clientId);
};
+ protected setPreferredAccountType: (typeof AccountController)['setPreferredAccountType'] =
+ preferredAccountType => {
+ AccountController.setPreferredAccountType(preferredAccountType);
+ };
+
// -- Private ------------------------------------------------------------------
private async initControllers(options: ScaffoldOptions) {
this.initAsyncValues(options);
@@ -311,7 +316,7 @@ export class AppKitScaffold {
private async initConnectedConnector() {
const connectedConnector = await StorageUtil.getConnectedConnector();
if (connectedConnector) {
- ConnectorController.setConnectedConnector(connectedConnector);
+ ConnectorController.setConnectedConnector(connectedConnector, false);
}
}
diff --git a/packages/scaffold/src/modal/w3m-modal/index.tsx b/packages/scaffold/src/modal/w3m-modal/index.tsx
index 13b93def5..eae3b380f 100644
--- a/packages/scaffold/src/modal/w3m-modal/index.tsx
+++ b/packages/scaffold/src/modal/w3m-modal/index.tsx
@@ -27,7 +27,7 @@ import styles from './styles';
export function AppKit() {
const { open, loading } = useSnapshot(ModalController.state);
- const { connectors } = useSnapshot(ConnectorController.state);
+ const { connectors, connectedConnector } = useSnapshot(ConnectorController.state);
const { caipAddress, isConnected } = useSnapshot(AccountController.state);
const { frameViewVisible, webviewVisible } = useSnapshot(WebviewController.state);
const { isSiweEnabled } = OptionsController.state;
@@ -38,6 +38,7 @@ export function AppKit() {
const authProvider = connectors.find(c => c.type === 'AUTH')?.provider as AppKitFrameProvider;
const AuthView = authProvider?.AuthView;
const SocialView = authProvider?.Webview;
+ const showAuth = !connectedConnector || connectedConnector === 'AUTH';
const onBackButtonPress = () => {
if (RouterController.state.history.length > 1) {
@@ -70,7 +71,7 @@ export function AppKit() {
const newAddress = CoreHelperUtil.getPlainAddress(address);
TransactionsController.resetTransactions();
- TransactionsController.fetchTransactions(newAddress);
+ TransactionsController.fetchTransactions(newAddress, true);
if (isSiweEnabled) {
const newNetworkId = CoreHelperUtil.getNetworkId(address);
@@ -136,8 +137,8 @@ export function AppKit() {
- {!!authProvider && AuthView && }
- {!!authProvider && SocialView && }
+ {!!showAuth && AuthView && }
+ {!!showAuth && SocialView && }
>
);
}
diff --git a/packages/scaffold/src/modal/w3m-router/index.tsx b/packages/scaffold/src/modal/w3m-router/index.tsx
index ff7f694e8..5cc2a4a4f 100644
--- a/packages/scaffold/src/modal/w3m-router/index.tsx
+++ b/packages/scaffold/src/modal/w3m-router/index.tsx
@@ -6,9 +6,12 @@ import { AccountDefaultView } from '../../views/w3m-account-default-view';
import { AccountView } from '../../views/w3m-account-view';
import { AllWalletsView } from '../../views/w3m-all-wallets-view';
import { ConnectView } from '../../views/w3m-connect-view';
+import { ConnectSocialsView } from '../../views/w3m-connect-socials-view';
import { ConnectingView } from '../../views/w3m-connecting-view';
import { ConnectingExternalView } from '../../views/w3m-connecting-external-view';
+import { ConnectingFarcasterView } from '../../views/w3m-connecting-farcaster-view';
import { ConnectingSocialView } from '../../views/w3m-connecting-social-view';
+import { CreateView } from '../../views/w3m-create-view';
import { ConnectingSiweView } from '@reown/appkit-siwe-react-native';
import { EmailVerifyOtpView } from '../../views/w3m-email-verify-otp-view';
import { EmailVerifyDeviceView } from '../../views/w3m-email-verify-device-view';
@@ -19,6 +22,7 @@ import { UpdateEmailWalletView } from '../../views/w3m-update-email-wallet-view'
import { UpdateEmailPrimaryOtpView } from '../../views/w3m-update-email-primary-otp-view';
import { UpdateEmailSecondaryOtpView } from '../../views/w3m-update-email-secondary-otp-view';
import { UpgradeEmailWalletView } from '../../views/w3m-upgrade-email-wallet-view';
+import { UpgradeToSmartAccountView } from '../../views/w3m-upgrade-to-smart-account-view';
import { TransactionsView } from '../../views/w3m-transactions-view';
import { WalletCompatibleNetworks } from '../../views/w3m-wallet-compatible-networks-view';
import { WalletReceiveView } from '../../views/w3m-wallet-receive-view';
@@ -29,9 +33,6 @@ import { WhatIsANetworkView } from '../../views/w3m-what-is-a-network-view';
import { WhatIsAWalletView } from '../../views/w3m-what-is-a-wallet-view';
import { UiUtil } from '../../utils/UiUtil';
-import { ConnectingFarcasterView } from '../../views/w3m-connecting-farcaster-view';
-import { ConnectSocialsView } from '../../views/w3m-connect-socials-view';
-import { CreateView } from '../../views/w3m-create-view';
export function AppKitRouter() {
const { view } = useSnapshot(RouterController.state);
@@ -84,6 +85,8 @@ export function AppKitRouter() {
return UpdateEmailWalletView;
case 'UpgradeEmailWallet':
return UpgradeEmailWalletView;
+ case 'UpgradeToSmartAccount':
+ return UpgradeToSmartAccountView;
case 'WalletCompatibleNetworks':
return WalletCompatibleNetworks;
case 'WalletReceive':
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index 6c5f2a89b..567b3acd9 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -43,7 +43,7 @@ export function AccountActivity({ style }: Props) {
address: AccountController.state.address,
projectId: OptionsController.state.projectId,
cursor: TransactionsController.state.next,
- isSmartAccount: false
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
}
});
};
diff --git a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
index bbc8b7972..a1627cb94 100644
--- a/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-tokens/index.tsx
@@ -1,5 +1,11 @@
import { useCallback, useState } from 'react';
-import { RefreshControl, ScrollView, type StyleProp, type ViewStyle } from 'react-native';
+import {
+ RefreshControl,
+ ScrollView,
+ StyleSheet,
+ type StyleProp,
+ type ViewStyle
+} from 'react-native';
import { useSnapshot } from 'valtio';
import {
AccountController,
@@ -7,7 +13,14 @@ import {
NetworkController,
RouterController
} from '@reown/appkit-core-react-native';
-import { FlexView, ListItem, Text, ListToken, useTheme } from '@reown/appkit-ui-react-native';
+import {
+ FlexView,
+ ListItem,
+ Text,
+ ListToken,
+ useTheme,
+ Spacing
+} from '@reown/appkit-ui-react-native';
interface Props {
style?: StyleProp;
@@ -32,7 +45,12 @@ export function AccountTokens({ style }: Props) {
if (!tokenBalance?.length) {
return (
-
+
Receive funds
@@ -72,3 +90,10 @@ export function AccountTokens({ style }: Props) {
);
}
+
+const styles = StyleSheet.create({
+ receiveButton: {
+ width: 'auto',
+ marginHorizontal: Spacing.s
+ }
+});
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index b9a35a3ad..b0a084d19 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -35,7 +35,7 @@ export function AccountWalletFeatures() {
type: 'track',
event: 'CLICK_TRANSACTIONS',
properties: {
- isSmartAccount: false
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
}
});
};
@@ -46,7 +46,7 @@ export function AccountWalletFeatures() {
event: 'OPEN_SEND',
properties: {
network: NetworkController.state.caipNetwork?.id || '',
- isSmartAccount: false
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
}
});
RouterController.push('WalletSend');
diff --git a/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx b/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
index f3ea27a44..bfb615385 100644
--- a/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
+++ b/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
@@ -56,18 +56,18 @@ export function AllWalletsList({ columns, itemWidth, onItemPress }: AllWalletsLi
);
};
- const walletTemplate = ({ item, index }: { item: WcWallet; index: number }) => {
+ const walletTemplate = ({ item }: { item: WcWallet; index: number }) => {
const isInstalled = ApiController.state.installed.find(wallet => wallet?.id === item?.id);
if (!item?.id) {
return (
-
+
);
}
return (
-
+
{
@@ -30,7 +32,7 @@ export function Header() {
Connect: 'Connect wallet',
ConnectSocials: 'All socials',
ConnectingExternal: connectorName ?? 'Connect wallet',
- ConnectingSiwe: 'Sign In',
+ ConnectingSiwe: undefined,
ConnectingFarcaster: socialName ?? 'Connecting Social',
ConnectingSocial: socialName ?? 'Connecting Social',
ConnectingWalletConnect: walletName ?? 'WalletConnect',
@@ -45,6 +47,7 @@ export function Header() {
UpdateEmailSecondaryOtp: 'Confirm new email',
UpdateEmailWallet: 'Edit email',
UpgradeEmailWallet: 'Upgrade wallet',
+ UpgradeToSmartAccount: undefined,
WalletCompatibleNetworks: 'Compatible networks',
WalletReceive: 'Receive',
WalletSend: 'Send',
@@ -58,10 +61,13 @@ export function Header() {
const header = headings(data, view);
const dynamicButtonTemplate = () => {
- const hideBackViews = ['ConnectingSiwe'];
- const showBack =
- RouterController.state.history.length > 1 &&
- !hideBackViews.includes(RouterController.state.view);
+ const noButtonViews = ['ConnectingSiwe'];
+
+ if (noButtonViews.includes(RouterController.state.view)) {
+ return ;
+ }
+
+ const showBack = RouterController.state.history.length > 1;
return showBack ? (
1;
+ const showSwitchAccountType = isAuth && NetworkController.checkIfSmartAccountEnabled();
const { padding } = useCustomDimensions();
async function onDisconnect() {
@@ -66,6 +75,29 @@ export function AccountDefaultView() {
}
}
+ const onSwitchAccountType = async () => {
+ try {
+ if (isAuth) {
+ ModalController.setLoading(true);
+ const accountType =
+ AccountController.state.preferredAccountType === 'eoa' ? 'smartAccount' : 'eoa';
+ const provider = ConnectorController.getAuthConnector()?.provider as AppKitFrameProvider;
+ await provider?.setPreferredAccount(accountType);
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SET_PREFERRED_ACCOUNT_TYPE',
+ properties: {
+ accountType,
+ network: NetworkController.state.caipNetwork?.id || ''
+ }
+ });
+ }
+ } catch (error) {
+ ModalController.setLoading(false);
+ SnackController.showError('Error switching account type');
+ }
+ };
+
const getUserEmail = () => {
const provider = ConnectorController.getAuthConnector()?.provider as AppKitFrameProvider;
if (!provider) return '';
@@ -215,6 +247,20 @@ export function AccountDefaultView() {
Activity
)}
+ {showSwitchAccountType && (
+
+ {`Switch to your ${
+ preferredAccountType === 'eoa' ? 'smart account' : 'EOA'
+ }`}
+
+ )}
{
if (OptionsController.isClipboardAvailable() && value) {
@@ -46,6 +51,10 @@ export function AccountView() {
RouterController.push('Networks');
};
+ const onActivatePress = () => {
+ RouterController.push('UpgradeToSmartAccount');
+ };
+
useEffect(() => {
AccountController.fetchTokenBalance();
SendController.resetSend();
@@ -72,6 +81,9 @@ export function AccountView() {
+ {showActivate && (
+
+ )}
();
+ const [url, setUrl] = useState();
const showCopy = OptionsController.isClipboardAvailable();
const socialProvider = data?.socialProvider;
const provider = authConnector?.provider as AppKitFrameProvider;
@@ -37,9 +37,9 @@ export function ConnectingFarcasterView() {
try {
if (!WebviewController.state.connecting && provider && socialProvider && authConnector) {
setError(false);
- const { url } = await provider.getFarcasterUri();
- setUrl(url);
- Linking.openURL(url);
+ const { url: farcasterUrl } = await provider.getFarcasterUri();
+ setUrl(farcasterUrl);
+ Linking.openURL(farcasterUrl);
await provider.connectFarcaster();
await ConnectionController.connectExternal(authConnector);
ConnectionController.setConnectedSocialProvider(socialProvider);
@@ -63,8 +63,8 @@ export function ConnectingFarcasterView() {
}, [provider, socialProvider, authConnector]);
const onCopyUrl = () => {
- if (_url) {
- OptionsController.copyToClipboard(_url);
+ if (url) {
+ OptionsController.copyToClipboard(url);
SnackController.showSuccess('Link copied');
}
};
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
index 50a8af39d..a644dd464 100644
--- a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
@@ -54,6 +54,7 @@ export function ConnectingSocialView() {
const parsedUrl = new URL(url);
await provider?.connectSocial(parsedUrl.search);
await ConnectionController.connectExternal(authConnector);
+ ConnectorController.setConnectedConnector('AUTH');
ConnectionController.setConnectedSocialProvider(socialProvider);
WebviewController.setConnecting(false);
diff --git a/packages/scaffold/src/views/w3m-connecting-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-view/index.tsx
index 7034ddd9f..82a501ce6 100644
--- a/packages/scaffold/src/views/w3m-connecting-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-view/index.tsx
@@ -11,7 +11,8 @@ import {
type Platform,
OptionsController,
ApiController,
- EventsController
+ EventsController,
+ ConnectorController
} from '@reown/appkit-core-react-native';
import { ConnectingQrCode } from '../../partials/w3m-connecting-qrcode';
@@ -48,6 +49,7 @@ export function ConnectingView() {
ConnectionController.setWcError(false);
ConnectionController.connectWalletConnect(routeData?.wallet?.link_mode ?? undefined);
await ConnectionController.state.wcPromise;
+ ConnectorController.setConnectedConnector('WALLET_CONNECT');
AccountController.setIsConnected(true);
if (OptionsController.state.isSiweEnabled) {
diff --git a/packages/scaffold/src/views/w3m-network-switch-view/index.tsx b/packages/scaffold/src/views/w3m-network-switch-view/index.tsx
index 52d653071..7c3739df9 100644
--- a/packages/scaffold/src/views/w3m-network-switch-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-network-switch-view/index.tsx
@@ -5,6 +5,7 @@ import {
ApiController,
AssetUtil,
ConnectionController,
+ ConnectorController,
EventsController,
NetworkController,
RouterController
@@ -23,6 +24,7 @@ export function NetworkSwitchView() {
const { data } = useSnapshot(RouterController.state);
const { recentWallets } = useSnapshot(ConnectionController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
+ const isAuthConnected = ConnectorController.state.connectedConnector === 'AUTH';
const [error, setError] = useState(false);
const [showRetry, setShowRetry] = useState(false);
const network = data?.network!;
@@ -90,6 +92,14 @@ export function NetworkSwitchView() {
);
}
+ if (isAuthConnected) {
+ return (
+
+ Switching to {network.name} network
+
+ );
+ }
+
return (
<>
{`Approve in ${walletName}`}
diff --git a/packages/scaffold/src/views/w3m-networks-view/index.tsx b/packages/scaffold/src/views/w3m-networks-view/index.tsx
index 774e8c8df..2803d2382 100644
--- a/packages/scaffold/src/views/w3m-networks-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-networks-view/index.tsx
@@ -16,7 +16,8 @@ import {
type CaipNetwork,
AccountController,
EventsController,
- RouterUtil
+ RouterUtil,
+ ConnectorController
} from '@reown/appkit-core-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
@@ -32,6 +33,7 @@ export function NetworksView() {
const itemGap = Math.abs(
Math.trunc((usableWidth - numColumns * CardSelectWidth) / numColumns) / 2
);
+ const isAuthConnected = ConnectorController.state.connectedConnector === 'AUTH';
const onHelpPress = () => {
RouterController.push('WhatIsANetwork');
@@ -55,7 +57,7 @@ export function NetworksView() {
const onNetworkPress = async (network: CaipNetwork) => {
if (AccountController.state.isConnected && caipNetwork?.id !== network.id) {
- if (approvedCaipNetworkIds?.includes(network.id)) {
+ if (approvedCaipNetworkIds?.includes(network.id) && !isAuthConnected) {
await NetworkController.switchActiveNetwork(network);
RouterUtil.navigateAfterNetworkSwitch(['ConnectingSiwe']);
@@ -66,7 +68,7 @@ export function NetworksView() {
network: network.id
}
});
- } else if (supportsAllNetworks) {
+ } else if (supportsAllNetworks || isAuthConnected) {
RouterController.push('SwitchNetwork', { network });
}
} else if (!AccountController.state.isConnected) {
diff --git a/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx b/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
index d3239180a..6b66cf5f2 100644
--- a/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-upgrade-email-wallet-view/index.tsx
@@ -18,7 +18,7 @@ export function UpgradeEmailWalletView() {
Follow the instructions on
{
+ try {
+ ModalController.setLoading(true);
+ const accountType =
+ AccountController.state.preferredAccountType === 'eoa' ? 'smartAccount' : 'eoa';
+ const provider = ConnectorController.getAuthConnector()?.provider as AppKitFrameProvider;
+ await provider?.setPreferredAccount(accountType);
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SET_PREFERRED_ACCOUNT_TYPE',
+ properties: {
+ accountType,
+ network: NetworkController.state.caipNetwork?.id || ''
+ }
+ });
+ } catch (error) {
+ ModalController.setLoading(false);
+ SnackController.showError('Error switching account type');
+ }
+ };
+
+ const onClose = () => {
+ ModalController.close();
+ ModalController.setLoading(false);
+ };
+
+ const onGoBack = () => {
+ RouterController.goBack();
+ ModalController.setLoading(false);
+ };
+
+ const onLearnMorePress = () => {
+ Linking.openURL('https://reown.com/faq');
+ };
+
+ useEffect(() => {
+ // Go back if the address has changed
+ if (address && initialAddress !== address) {
+ RouterController.goBack();
+ }
+ }, [initialAddress, address]);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ Discover Smart Accounts
+
+
+ Access advanced brand new features as username, improved security and a smoother user
+ experience!
+
+
+
+ Do it later
+
+
+ Continue
+
+
+
+ Learn more
+
+
+ >
+ );
+}
diff --git a/packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/styles.ts b/packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/styles.ts
new file mode 100644
index 000000000..f2d23ef07
--- /dev/null
+++ b/packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/styles.ts
@@ -0,0 +1,29 @@
+import { Spacing } from '@reown/appkit-ui-react-native';
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ container: {
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ title: {
+ marginTop: Spacing.xl,
+ marginVertical: Spacing.s
+ },
+ button: {
+ width: 110
+ },
+ cancelButton: {
+ marginRight: Spacing.m
+ },
+ middleIcon: {
+ marginHorizontal: Spacing.s
+ },
+ closeButton: {
+ alignSelf: 'flex-end',
+ right: Spacing.xl,
+ top: Spacing.l,
+ position: 'absolute',
+ zIndex: 2
+ }
+});
diff --git a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
index 0c03c449a..2e8c061b6 100644
--- a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
@@ -1,21 +1,33 @@
import { ScrollView } from 'react-native';
+import { useSnapshot } from 'valtio';
import { FlexView, Text, Banner, NetworkImage } from '@reown/appkit-ui-react-native';
-import { ApiController, AssetUtil, NetworkController } from '@reown/appkit-core-react-native';
+import {
+ AccountController,
+ ApiController,
+ AssetUtil,
+ NetworkController
+} from '@reown/appkit-core-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
export function WalletCompatibleNetworks() {
const { padding } = useCustomDimensions();
- const approvedNetworks = NetworkController.getApprovedCaipNetworks();
+ const { preferredAccountType } = useSnapshot(AccountController.state);
+ const { caipNetwork } = useSnapshot(NetworkController.state);
+ const isSmartAccount =
+ preferredAccountType === 'smartAccount' && NetworkController.checkIfSmartAccountEnabled();
+ const approvedNetworks = isSmartAccount
+ ? [caipNetwork]
+ : NetworkController.getApprovedCaipNetworks();
const imageHeaders = ApiController._getApiHeaders();
return (
- {approvedNetworks.map(network => (
+ {approvedNetworks.map((network, index) => (
- {network.name}
+ {network?.name ?? 'Unknown Network'}
))}
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
index c5cf27c9d..47b613d0b 100644
--- a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
@@ -21,7 +21,7 @@ import {
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
export function WalletReceiveView() {
- const { address, profileName } = useSnapshot(AccountController.state);
+ const { address, profileName, preferredAccountType } = useSnapshot(AccountController.state);
const { caipNetwork } = useSnapshot(NetworkController.state);
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
const { padding } = useCustomDimensions();
@@ -31,6 +31,8 @@ export function WalletReceiveView() {
.filter(network => network?.imageId)
?.slice(0, 5) || [];
const imagesArray = slicedNetworks.map(AssetUtil.getNetworkImage).filter(Boolean) as string[];
+ const isSmartAccount =
+ preferredAccountType === 'smartAccount' && NetworkController.checkIfSmartAccountEnabled();
const label = UiUtil.getTruncateString({
string: profileName ?? address ?? '',
@@ -69,7 +71,9 @@ export function WalletReceiveView() {
diff --git a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx
index b3c477003..ea085ecd2 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-preview-view/components/preview-send-pill.tsx
@@ -31,6 +31,6 @@ export function PreviewSendPill({ text, children }: PreviewSendPillProps) {
const styles = StyleSheet.create({
pill: {
borderRadius: BorderRadius.full,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
}
});
diff --git a/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
index 80175219d..5d7a1c295 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-select-token-view/index.tsx
@@ -12,6 +12,7 @@ import {
import type { Balance } from '@reown/appkit-common-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import { AccountPlaceholder } from '../../partials/w3m-account-placeholder';
import styles from './styles';
export function WalletSendSelectTokenView() {
@@ -54,18 +55,26 @@ export function WalletSendSelectTokenView() {
Your tokens
- {filteredTokens.map((token, index) => (
- onTokenPress(token)}
+ {filteredTokens.length ? (
+ filteredTokens.map((token, index) => (
+ onTokenPress(token)}
+ />
+ ))
+ ) : (
+
- ))}
+ )}
);
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
index 7fded2195..7e52d3f4f 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/styles.ts
@@ -10,12 +10,6 @@ export default StyleSheet.create({
tokenInput: {
marginBottom: Spacing.xs
},
- mockInput: {
- width: '100%',
- borderWidth: 1,
- height: 120,
- borderRadius: 20
- },
arrowIcon: {
position: 'absolute',
top: -30,
diff --git a/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx b/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx
index b7955c678..db9825873 100644
--- a/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx
+++ b/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx
@@ -1,10 +1,11 @@
import { useSnapshot } from 'valtio';
-import { Button, FlexView, Text } from '@reown/appkit-ui-react-native';
+import { Button, FlexView, IconLink, Text } from '@reown/appkit-ui-react-native';
import {
AccountController,
ConnectionController,
EventsController,
ModalController,
+ NetworkController,
OptionsController,
RouterController,
SnackController
@@ -26,14 +27,22 @@ export function ConnectingSiweView() {
setIsSigning(true);
EventsController.sendEvent({
event: 'CLICK_SIGN_SIWE_MESSAGE',
- type: 'track'
+ type: 'track',
+ properties: {
+ network: NetworkController.state.caipNetwork?.id || '',
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
+ }
});
try {
const session = await SIWEController.signIn();
EventsController.sendEvent({
event: 'SIWE_AUTH_SUCCESS',
- type: 'track'
+ type: 'track',
+ properties: {
+ network: NetworkController.state.caipNetwork?.id || '',
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
+ }
});
return session;
@@ -44,7 +53,11 @@ export function ConnectingSiweView() {
return EventsController.sendEvent({
event: 'SIWE_AUTH_ERROR',
- type: 'track'
+ type: 'track',
+ properties: {
+ network: NetworkController.state.caipNetwork?.id || '',
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
+ }
});
} finally {
setIsSigning(false);
@@ -63,12 +76,26 @@ export function ConnectingSiweView() {
}
EventsController.sendEvent({
event: 'CLICK_CANCEL_SIWE',
- type: 'track'
+ type: 'track',
+ properties: {
+ network: NetworkController.state.caipNetwork?.id || '',
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
+ }
});
};
return (
+
+
+ Sign in
+
{dappName} needs to connect to your wallet
diff --git a/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/styles.ts b/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/styles.ts
index 900ef0370..42d56456f 100644
--- a/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/styles.ts
+++ b/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/styles.ts
@@ -3,6 +3,7 @@ import { StyleSheet } from 'react-native';
export default StyleSheet.create({
logoContainer: {
+ marginTop: Spacing.xl,
marginBottom: Spacing.m
},
button: {
@@ -14,5 +15,12 @@ export default StyleSheet.create({
subtitle: {
marginHorizontal: '10%',
marginVertical: Spacing.l
+ },
+ closeButton: {
+ alignSelf: 'flex-end',
+ right: Spacing.xl,
+ top: Spacing.l,
+ position: 'absolute',
+ zIndex: 2
}
});
diff --git a/packages/ui/src/__tests__/wui-text.test.tsx b/packages/ui/src/__tests__/wui-text.test.tsx
index e39bae272..7475ecb83 100644
--- a/packages/ui/src/__tests__/wui-text.test.tsx
+++ b/packages/ui/src/__tests__/wui-text.test.tsx
@@ -1,6 +1,15 @@
import { render } from '@testing-library/react-native';
+import { configureInternal } from '@testing-library/react-native/build/config';
import { Text } from '../components/wui-text';
+configureInternal({
+ hostComponentNames: {
+ text: 'RCTText',
+ textInput: 'RCTTextInput',
+ switch: 'RCTSwitch'
+ }
+});
+
test('Text render', () => {
const label = 'Hello World';
const { getAllByText } = render({label});
diff --git a/packages/ui/src/assets/visual/Google.tsx b/packages/ui/src/assets/visual/Google.tsx
new file mode 100644
index 000000000..486a89013
--- /dev/null
+++ b/packages/ui/src/assets/visual/Google.tsx
@@ -0,0 +1,43 @@
+import Svg, { Path, Rect, type SvgProps } from 'react-native-svg';
+const GoogleSvg = (props: SvgProps) => (
+
+
+
+
+
+
+
+
+
+
+);
+
+export default GoogleSvg;
diff --git a/packages/ui/src/assets/visual/Lightbulb.tsx b/packages/ui/src/assets/visual/Lightbulb.tsx
new file mode 100644
index 000000000..545d436be
--- /dev/null
+++ b/packages/ui/src/assets/visual/Lightbulb.tsx
@@ -0,0 +1,54 @@
+import Svg, { ClipPath, Defs, G, Path, Rect, type SvgProps } from 'react-native-svg';
+const LightbulbSvg = (props: SvgProps) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+export default LightbulbSvg;
diff --git a/packages/ui/src/assets/visual/Pencil.tsx b/packages/ui/src/assets/visual/Pencil.tsx
new file mode 100644
index 000000000..08d189244
--- /dev/null
+++ b/packages/ui/src/assets/visual/Pencil.tsx
@@ -0,0 +1,80 @@
+import Svg, { ClipPath, Defs, G, Path, Rect, type SvgProps } from 'react-native-svg';
+
+const PencilSvg = (props: SvgProps) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+export default PencilSvg;
diff --git a/packages/ui/src/components/wui-card/styles.ts b/packages/ui/src/components/wui-card/styles.ts
index b7f5974f8..86e49e888 100644
--- a/packages/ui/src/components/wui-card/styles.ts
+++ b/packages/ui/src/components/wui-card/styles.ts
@@ -4,7 +4,7 @@ import { BorderRadius } from '../../utils/ThemeUtil';
export default StyleSheet.create({
container: {
borderRadius: BorderRadius.l,
- borderWidth: 1,
+ borderWidth: StyleSheet.hairlineWidth,
overflow: 'hidden'
}
});
diff --git a/packages/ui/src/components/wui-lean-text/index.tsx b/packages/ui/src/components/wui-lean-text/index.tsx
new file mode 100644
index 000000000..98fe33a25
--- /dev/null
+++ b/packages/ui/src/components/wui-lean-text/index.tsx
@@ -0,0 +1,10 @@
+import { type ComponentType, createElement, forwardRef } from 'react';
+import type { TextProps } from 'react-native';
+
+const LeanText = forwardRef((props, ref) => {
+ return createElement('RCTText', { ...props, ref });
+}) as ComponentType;
+
+LeanText.displayName = 'RCTText';
+
+export { LeanText };
diff --git a/packages/ui/src/components/wui-lean-view/index.tsx b/packages/ui/src/components/wui-lean-view/index.tsx
new file mode 100644
index 000000000..8bcda5fdb
--- /dev/null
+++ b/packages/ui/src/components/wui-lean-view/index.tsx
@@ -0,0 +1,10 @@
+import { type ComponentType, createElement, forwardRef } from 'react';
+import type { ViewProps } from 'react-native';
+
+const LeanView = forwardRef((props, ref) => {
+ return createElement('RCTView', { ...props, ref });
+}) as ComponentType;
+
+LeanView.displayName = 'RCTView';
+
+export { LeanView };
diff --git a/packages/ui/src/components/wui-text/index.tsx b/packages/ui/src/components/wui-text/index.tsx
index 41d32ef1c..a728a292f 100644
--- a/packages/ui/src/components/wui-text/index.tsx
+++ b/packages/ui/src/components/wui-text/index.tsx
@@ -1,5 +1,6 @@
-import { Text as NativeText, type TextProps as NativeProps } from 'react-native';
+import { type TextProps as NativeProps } from 'react-native';
import { useTheme } from '../../hooks/useTheme';
+import { LeanText } from '../wui-lean-text';
import type { ColorType, TextType } from '../../utils/TypesUtil';
import styles from './styles';
@@ -20,7 +21,7 @@ export function Text({
const Theme = useTheme();
return (
-
{children}
-
+
);
}
diff --git a/packages/ui/src/components/wui-visual/index.tsx b/packages/ui/src/components/wui-visual/index.tsx
index c6b849cb0..99830e391 100644
--- a/packages/ui/src/components/wui-visual/index.tsx
+++ b/packages/ui/src/components/wui-visual/index.tsx
@@ -14,6 +14,9 @@ import NounSvg from '../../assets/visual/Noun';
import ProfileSvg from '../../assets/visual/Profile';
import SystemSvg from '../../assets/visual/System';
import type { VisualType } from '../../utils/TypesUtil';
+import GoogleSvg from '../../assets/visual/Google';
+import LightbulbSvg from '../../assets/visual/Lightbulb';
+import PencilSvg from '../../assets/visual/Pencil';
const svgOptions: Record JSX.Element> = {
browser: BrowserSvg,
@@ -21,12 +24,15 @@ const svgOptions: Record JSX.Element> = {
defi: DefiSvg,
defiAlt: DefiAltSvg,
eth: EthSvg,
+ google: GoogleSvg,
layers: LayersSvg,
+ lightbulb: LightbulbSvg,
lock: LockSvg,
login: LoginSvg,
network: NetworkSvg,
nft: NftSvg,
noun: NounSvg,
+ pencil: PencilSvg,
profile: ProfileSvg,
system: SystemSvg
};
diff --git a/packages/ui/src/composites/wui-account-button/styles.ts b/packages/ui/src/composites/wui-account-button/styles.ts
index 1eda1c32b..2e1441204 100644
--- a/packages/ui/src/composites/wui-account-button/styles.ts
+++ b/packages/ui/src/composites/wui-account-button/styles.ts
@@ -6,7 +6,7 @@ export default StyleSheet.create({
flexDirection: 'row',
height: 40,
borderRadius: BorderRadius.full,
- borderWidth: 1,
+ borderWidth: StyleSheet.hairlineWidth,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: Spacing['3xs']
@@ -36,7 +36,7 @@ export default StyleSheet.create({
paddingLeft: Spacing['3xs'],
paddingRight: Spacing.xs,
borderRadius: BorderRadius.full,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
},
address: {
marginLeft: Spacing['3xs']
diff --git a/packages/ui/src/composites/wui-account-pill/index.tsx b/packages/ui/src/composites/wui-account-pill/index.tsx
index 9b7ebd886..3f3bfc163 100644
--- a/packages/ui/src/composites/wui-account-pill/index.tsx
+++ b/packages/ui/src/composites/wui-account-pill/index.tsx
@@ -66,7 +66,13 @@ export function AccountPill({
truncate: 'middle'
})}
-
+
);
}
diff --git a/packages/ui/src/composites/wui-account-pill/styles.ts b/packages/ui/src/composites/wui-account-pill/styles.ts
index 75d118b60..7be825c94 100644
--- a/packages/ui/src/composites/wui-account-pill/styles.ts
+++ b/packages/ui/src/composites/wui-account-pill/styles.ts
@@ -11,9 +11,12 @@ export default StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
borderRadius: BorderRadius.full,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
},
text: {
marginLeft: Spacing['2xs']
+ },
+ copyButton: {
+ marginHorizontal: Spacing['3xs']
}
});
diff --git a/packages/ui/src/composites/wui-button/styles.ts b/packages/ui/src/composites/wui-button/styles.ts
index 8da1107cf..b9330c059 100644
--- a/packages/ui/src/composites/wui-button/styles.ts
+++ b/packages/ui/src/composites/wui-button/styles.ts
@@ -62,7 +62,7 @@ export default StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
borderRadius: BorderRadius.xs,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
},
smButton: {
height: 32,
diff --git a/packages/ui/src/composites/wui-chip/styles.ts b/packages/ui/src/composites/wui-chip/styles.ts
index 1d7552b2e..ac3e04789 100644
--- a/packages/ui/src/composites/wui-chip/styles.ts
+++ b/packages/ui/src/composites/wui-chip/styles.ts
@@ -65,11 +65,11 @@ export default StyleSheet.create({
paddingHorizontal: Spacing.xs,
alignItems: 'center',
borderRadius: BorderRadius.s,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
},
image: {
borderRadius: BorderRadius.full,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
},
smImage: {
width: 16,
diff --git a/packages/ui/src/composites/wui-compatible-network/index.tsx b/packages/ui/src/composites/wui-compatible-network/index.tsx
index af94c9358..3e1420f9e 100644
--- a/packages/ui/src/composites/wui-compatible-network/index.tsx
+++ b/packages/ui/src/composites/wui-compatible-network/index.tsx
@@ -13,9 +13,6 @@ export interface CompatibleNetworkProps {
style?: StyleProp;
}
-const offset = [20, 15, 10, 5, 0];
-const zIndex = [5, 4, 3, 2, 1];
-
export function CompatibleNetwork({
text,
onPress,
@@ -44,7 +41,7 @@ export function CompatibleNetwork({
imageHeaders={imageHeaders}
borderColor={Theme['bg-200']}
borderWidth={2}
- style={{ left: offset[index], zIndex: zIndex[index] }}
+ style={[styles.item, { zIndex: networkImages.length - index }]}
/>
))}
@@ -60,5 +57,8 @@ const styles = StyleSheet.create({
flexDirection: 'row',
justifyContent: 'space-between',
paddingRight: 0
+ },
+ item: {
+ marginLeft: -5
}
});
diff --git a/packages/ui/src/composites/wui-connect-button/styles.ts b/packages/ui/src/composites/wui-connect-button/styles.ts
index 572cdbc20..8804ce23e 100644
--- a/packages/ui/src/composites/wui-connect-button/styles.ts
+++ b/packages/ui/src/composites/wui-connect-button/styles.ts
@@ -51,7 +51,7 @@ export default StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
borderRadius: BorderRadius.s,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
},
smButton: {
height: 32
diff --git a/packages/ui/src/composites/wui-input-text/styles.ts b/packages/ui/src/composites/wui-input-text/styles.ts
index 2cf4398e6..4b18dffa5 100644
--- a/packages/ui/src/composites/wui-input-text/styles.ts
+++ b/packages/ui/src/composites/wui-input-text/styles.ts
@@ -7,7 +7,7 @@ const baseStyle = {
borderRadius: BorderRadius.xxs,
alignItems: 'center',
paddingHorizontal: Spacing.xs,
- borderWidth: 1
+ borderWidth: StyleSheet.hairlineWidth
} as ViewStyle;
export const outerBorderRadius = {
diff --git a/packages/ui/src/composites/wui-list-wallet/index.tsx b/packages/ui/src/composites/wui-list-wallet/index.tsx
index 58b8a01b7..c8a28665d 100644
--- a/packages/ui/src/composites/wui-list-wallet/index.tsx
+++ b/packages/ui/src/composites/wui-list-wallet/index.tsx
@@ -1,4 +1,4 @@
-import { Animated, Pressable, View, type StyleProp, type ViewStyle } from 'react-native';
+import { Animated, Pressable, type StyleProp, type ViewStyle } from 'react-native';
import { Text } from '../../components/wui-text';
import useAnimatedValue from '../../hooks/useAnimatedValue';
import { useTheme } from '../../hooks/useTheme';
@@ -6,9 +6,10 @@ import type { IconType, TagType } from '../../utils/TypesUtil';
import { Tag } from '../wui-tag';
import { WalletImage } from '../wui-wallet-image';
import { Icon } from '../../components/wui-icon';
+import { LeanView } from '../../components/wui-lean-view';
+import { IconBox } from '../wui-icon-box';
import styles from './styles';
-import { IconBox } from '../wui-icon-box';
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
@@ -67,7 +68,7 @@ export function ListWallet({
function imageTemplate() {
return (
-
+
{templateInstalled()}
-
+
);
}
@@ -116,12 +117,12 @@ export function ListWallet({
onPressOut={setStartValue}
testID={testID}
>
-
+
{imageTemplate()}
{name}
-
+
{iconTemplate()}
);
diff --git a/packages/ui/src/composites/wui-network-button/styles.ts b/packages/ui/src/composites/wui-network-button/styles.ts
index 199f2d29b..f2166e82e 100644
--- a/packages/ui/src/composites/wui-network-button/styles.ts
+++ b/packages/ui/src/composites/wui-network-button/styles.ts
@@ -7,7 +7,7 @@ export default StyleSheet.create({
height: 40,
alignItems: 'center',
justifyContent: 'center',
- borderWidth: 1,
+ borderWidth: StyleSheet.hairlineWidth,
borderRadius: BorderRadius.full,
paddingHorizontal: Spacing['2xs']
},
diff --git a/packages/ui/src/composites/wui-otp/index.tsx b/packages/ui/src/composites/wui-otp/index.tsx
index 868101c5b..ebf83152c 100644
--- a/packages/ui/src/composites/wui-otp/index.tsx
+++ b/packages/ui/src/composites/wui-otp/index.tsx
@@ -3,8 +3,7 @@ import {
type NativeSyntheticEvent,
TextInput,
type TextInputKeyPressEventData,
- View,
- Platform
+ View
} from 'react-native';
import { InputNumeric, type InputNumericProps } from '../wui-input-numeric';
import styles from './styles';
@@ -90,7 +89,7 @@ export function Otp({ length, style, onChangeText, autoFocus }: OtpProps) {
inputRef={refArray[index]}
onChangeText={text => _onChangeText(text, index)}
onKeyPress={(e: any) => onKeyPress(e, index)}
- autoComplete={Platform.OS === 'android' ? 'sms-otp' : 'one-time-code'}
+ autoComplete="off"
/>
))}
diff --git a/packages/ui/src/composites/wui-promo/index.tsx b/packages/ui/src/composites/wui-promo/index.tsx
new file mode 100644
index 000000000..19a3597c9
--- /dev/null
+++ b/packages/ui/src/composites/wui-promo/index.tsx
@@ -0,0 +1,42 @@
+import { Pressable, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
+import { Icon } from '../../components/wui-icon';
+import { Text } from '../../components/wui-text';
+import { useTheme } from '../../hooks/useTheme';
+import { FlexView } from '../../layout/wui-flex';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
+
+export interface PromoProps {
+ text: string;
+ style?: StyleProp;
+ onPress?: () => void;
+}
+
+export function Promo({ text, style, onPress }: PromoProps) {
+ const Theme = useTheme();
+
+ return (
+
+
+
+ {text}
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ borderRadius: BorderRadius.full
+ },
+ icon: {
+ marginLeft: Spacing['2xs']
+ }
+});
diff --git a/packages/ui/src/composites/wui-snackbar/styles.ts b/packages/ui/src/composites/wui-snackbar/styles.ts
index 23c1b9bae..7c0ced601 100644
--- a/packages/ui/src/composites/wui-snackbar/styles.ts
+++ b/packages/ui/src/composites/wui-snackbar/styles.ts
@@ -7,7 +7,7 @@ export default StyleSheet.create({
flexDirection: 'row',
paddingHorizontal: 8,
borderRadius: BorderRadius.full,
- borderWidth: 1,
+ borderWidth: StyleSheet.hairlineWidth,
alignItems: 'center'
},
text: {
diff --git a/packages/ui/src/composites/wui-tabs/styles.ts b/packages/ui/src/composites/wui-tabs/styles.ts
index 6a81b4fb3..0fdd348e6 100644
--- a/packages/ui/src/composites/wui-tabs/styles.ts
+++ b/packages/ui/src/composites/wui-tabs/styles.ts
@@ -22,7 +22,7 @@ export default StyleSheet.create({
activeMark: {
position: 'absolute',
height: 28,
- borderWidth: 1,
+ borderWidth: StyleSheet.hairlineWidth,
borderRadius: BorderRadius['3xl'],
margin: Spacing['3xs']
}
diff --git a/packages/ui/src/composites/wui-wallet-image/styles.ts b/packages/ui/src/composites/wui-wallet-image/styles.ts
index 610fd4b63..1a0f1f5b3 100644
--- a/packages/ui/src/composites/wui-wallet-image/styles.ts
+++ b/packages/ui/src/composites/wui-wallet-image/styles.ts
@@ -32,7 +32,7 @@ export default StyleSheet.create({
borderRadius: BorderRadius.m
},
border: {
- borderWidth: 1,
+ borderWidth: StyleSheet.hairlineWidth,
position: 'absolute'
}
});
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 317211753..ddea358d4 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -49,6 +49,7 @@ export { LogoSelect, type LogoSelectProps } from './composites/wui-logo-select';
export { NetworkButton, type NetworkButtonProps } from './composites/wui-network-button';
export { NetworkImage, type NetworkImageProps } from './composites/wui-network-image';
export { Otp, type OtpProps } from './composites/wui-otp';
+export { Promo, type PromoProps } from './composites/wui-promo';
export { QrCode, type QrCodeProps } from './composites/wui-qr-code';
export { SearchBar, type SearchBarProps } from './composites/wui-search-bar';
export { Snackbar, type SnackbarProps } from './composites/wui-snackbar';
diff --git a/packages/ui/src/layout/wui-flex/index.tsx b/packages/ui/src/layout/wui-flex/index.tsx
index fdee104bf..c810bd6e1 100644
--- a/packages/ui/src/layout/wui-flex/index.tsx
+++ b/packages/ui/src/layout/wui-flex/index.tsx
@@ -1,4 +1,4 @@
-import { View, type StyleProp, type ViewStyle } from 'react-native';
+import { type StyleProp, type ViewStyle } from 'react-native';
import type {
FlexAlignType,
@@ -9,8 +9,8 @@ import type {
FlexWrapType,
SpacingType
} from '../../utils/TypesUtil';
-
import { UiUtil } from '../../utils/UiUtil';
+import { LeanView } from '../../components/wui-lean-view';
export interface FlexViewProps {
children?: React.ReactNode;
@@ -45,5 +45,5 @@ export function FlexView(props: FlexViewProps) {
marginLeft: props.margin && UiUtil.getSpacingStyles(props.margin, 3)
};
- return {props.children};
+ return {props.children};
}
diff --git a/packages/ui/src/layout/wui-separator/index.tsx b/packages/ui/src/layout/wui-separator/index.tsx
index 701d00316..3dd59ff8b 100644
--- a/packages/ui/src/layout/wui-separator/index.tsx
+++ b/packages/ui/src/layout/wui-separator/index.tsx
@@ -1,5 +1,6 @@
-import { View, type StyleProp, type ViewStyle } from 'react-native';
+import { type StyleProp, type ViewStyle } from 'react-native';
import { Text } from '../../components/wui-text';
+import { LeanView } from '../../components/wui-lean-view';
import { FlexView } from '../../layout/wui-flex';
import { useTheme } from '../../hooks/useTheme';
import styles from './styles';
@@ -13,18 +14,20 @@ export function Separator({ text, style }: SeparatorProps) {
const Theme = useTheme();
if (!text) {
- return ;
+ return (
+
+ );
}
return (
-
{text}
-
diff --git a/packages/ui/src/utils/TypesUtil.ts b/packages/ui/src/utils/TypesUtil.ts
index d1e264cab..a6f323441 100644
--- a/packages/ui/src/utils/TypesUtil.ts
+++ b/packages/ui/src/utils/TypesUtil.ts
@@ -96,6 +96,15 @@ export type ColorType =
| 'fg-250'
| 'fg-275'
| 'fg-300'
+ | 'bg-100'
+ | 'bg-125'
+ | 'bg-150'
+ | 'bg-175'
+ | 'bg-200'
+ | 'bg-225'
+ | 'bg-250'
+ | 'bg-275'
+ | 'bg-300'
| 'accent-glass-020'
| 'accent-glass-015'
| 'accent-glass-010'
@@ -186,12 +195,15 @@ export type VisualType =
| 'defi'
| 'defiAlt'
| 'eth'
+ | 'google'
| 'layers'
+ | 'lightbulb'
| 'lock'
| 'login'
| 'network'
| 'nft'
| 'noun'
+ | 'pencil'
| 'profile'
| 'system';
diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts
index 0f45eb838..a44975182 100644
--- a/packages/wagmi/src/client.ts
+++ b/packages/wagmi/src/client.ts
@@ -2,7 +2,9 @@ import { formatUnits, type Hex, parseUnits } from 'viem';
import {
type GetAccountReturnType,
type GetEnsAddressReturnType,
+ type Connector as WagmiConnector,
connect,
+ reconnect,
disconnect,
signMessage,
getAccount,
@@ -33,7 +35,8 @@ import {
type SendTransactionArgs,
type Token,
AppKitScaffold,
- type WriteContractArgs
+ type WriteContractArgs,
+ type AppKitFrameProvider
} from '@reown/appkit-scaffold-react-native';
import {
ConstantsUtil,
@@ -101,9 +104,9 @@ export class AppKit extends AppKitScaffold {
async getApprovedCaipNetworksData() {
const walletChoice = await StorageUtil.getConnectedConnector();
const walletConnectType =
- PresetsUtil.ConnectorTypesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID];
+ PresetsUtil.ConnectorTypesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID]!;
- const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID];
+ const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID]!;
if (walletChoice?.includes(walletConnectType)) {
const connector = wagmiConfig.connectors.find(
@@ -340,7 +343,6 @@ export class AppKit extends AppKitScaffold {
this.syncRequestedNetworks([...wagmiConfig.chains]);
this.syncConnectors([...wagmiConfig.connectors]);
- this.listenAuthConnector([...wagmiConfig.connectors]);
watchConnectors(wagmiConfig, {
onChange: connectors => this.syncConnectors([...connectors])
@@ -400,7 +402,6 @@ export class AppKit extends AppKitScaffold {
GetAccountReturnType,
'address' | 'isConnected' | 'chainId' | 'connector' | 'isConnecting' | 'isReconnecting'
>) {
- this.resetAccount();
this.syncNetwork(address, chainId, isConnected);
this.setLoading(!!connector && (isConnecting || isReconnecting));
@@ -416,6 +417,7 @@ export class AppKit extends AppKitScaffold {
]);
this.hasSyncedConnectedAccount = true;
} else if (!isConnected && this.hasSyncedConnectedAccount) {
+ this.resetAccount();
this.resetWcConnection();
this.resetNetwork();
}
@@ -554,15 +556,21 @@ export class AppKit extends AppKitScaffold {
name: 'Auth',
provider
});
+ this.addAuthListeners(authConnector);
}
}
- private async listenAuthConnector(connectors: AppKitClientOptions['wagmiConfig']['connectors']) {
- const connector = connectors.find(c => c.id === ConstantsUtil.AUTH_CONNECTOR_ID);
-
+ private async addAuthListeners(connector: WagmiConnector) {
const connectedConnector = await StorageUtil.getItem('@w3m/connected_connector');
if (connector && connectedConnector === 'AUTH') {
super.setLoading(true);
+
+ const provider = (await connector.getProvider()) as AppKitFrameProvider;
+
+ provider.onSetPreferredAccount(async () => {
+ await reconnect(this.wagmiConfig, { connectors: [connector] });
+ this.setLoading(false);
+ });
}
}
}
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index cadd052e8..c77d79d1c 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { useEffect, useRef, useState } from 'react';
+import { memo, useEffect, useRef, useState } from 'react';
import { Animated, Appearance, Linking, Platform, SafeAreaView, StyleSheet } from 'react-native';
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
@@ -8,9 +8,11 @@ import {
OptionsController,
ModalController,
type OptionsControllerState,
- StorageUtil,
RouterController,
- WebviewController
+ WebviewController,
+ AccountController,
+ NetworkController,
+ ConnectionController
} from '@reown/appkit-core-react-native';
import { useTheme, BorderRadius } from '@reown/appkit-ui-react-native';
import type { AppKitFrameProvider } from './AppKitFrameProvider';
@@ -20,11 +22,13 @@ import type { AppKitFrameTypes } from './AppKitFrameTypes';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
-export function AuthWebview() {
+function _AuthWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
const authConnector = ConnectorController.getAuthConnector();
- const { projectId, sdkVersion } = useSnapshot(OptionsController.state) as OptionsControllerState;
+ const { projectId, sdkVersion, sdkType } = useSnapshot(
+ OptionsController.state
+ ) as OptionsControllerState;
const { frameViewVisible } = useSnapshot(WebviewController.state);
const [isBackdropVisible, setIsBackdropVisible] = useState(false);
const animatedHeight = useRef(new Animated.Value(0));
@@ -48,53 +52,11 @@ export function AuthWebview() {
};
const handleMessage = (e: WebViewMessageEvent) => {
- let event = parseMessage(e);
+ try {
+ let event = parseMessage(e);
- provider.onMessage(event);
-
- provider.onRpcRequest((request: AppKitFrameTypes.RPCRequest) => {
- if (AppKitFrameHelpers.checkIfRequestExists(request)) {
- if (!AppKitFrameHelpers.checkIfRequestIsAllowed(request)) {
- WebviewController.setFrameViewVisible(true);
- }
- }
- });
-
- provider.onRpcSuccess((_, request) => {
- const isSafeRequest = AppKitFrameHelpers.checkIfRequestIsSafe(request);
- if (isSafeRequest) {
- return;
- }
-
- if (RouterController.state.transactionStack.length === 0) {
- ModalController.close();
- } else {
- RouterController?.popTransactionStack();
- }
- WebviewController.setFrameViewVisible(false);
- });
-
- provider.onRpcError(() => {
- if (ModalController.state.open) {
- if (RouterController.state.transactionStack.length === 0) {
- ModalController.close();
- } else {
- RouterController?.popTransactionStack(true);
- }
- }
- WebviewController.setFrameViewVisible(false);
- });
-
- provider.onIsConnected(event, () => {
- ConnectorController.setAuthLoading(false);
- ModalController.setLoading(false);
- });
-
- provider.onNotConnected(event, () => {
- ConnectorController.setAuthLoading(false);
- ModalController.setLoading(false);
- StorageUtil.removeConnectedConnector();
- });
+ provider.onMessage(event);
+ } catch (error) {}
};
const show = animatedHeight.current.interpolate({
@@ -102,6 +64,8 @@ export function AuthWebview() {
outputRange: ['0%', '80%']
});
+ useEffect(() => {}, [provider]);
+
useEffect(() => {
Animated.timing(animatedHeight.current, {
toValue: frameViewVisible ? 1 : 0,
@@ -127,7 +91,61 @@ export function AuthWebview() {
}, [animatedHeight, backdropOpacity, frameViewVisible, setIsBackdropVisible]);
useEffect(() => {
- provider?.setWebviewRef(webviewRef);
+ if (provider) {
+ provider.setWebviewRef(webviewRef);
+ provider.onRpcRequest((request: AppKitFrameTypes.RPCRequest) => {
+ if (AppKitFrameHelpers.checkIfRequestExists(request)) {
+ if (!AppKitFrameHelpers.checkIfRequestIsAllowed(request)) {
+ WebviewController.setFrameViewVisible(true);
+ }
+ }
+ });
+
+ provider.onRpcSuccess((_, request) => {
+ const isSafeRequest = AppKitFrameHelpers.checkIfRequestIsSafe(request);
+ if (isSafeRequest) {
+ return;
+ }
+
+ if (RouterController.state.transactionStack.length === 0) {
+ ModalController.close();
+ } else {
+ RouterController?.popTransactionStack();
+ }
+ WebviewController.setFrameViewVisible(false);
+ });
+
+ provider.onRpcError(() => {
+ if (ModalController.state.open) {
+ if (RouterController.state.transactionStack.length === 0) {
+ ModalController.close();
+ } else {
+ RouterController?.popTransactionStack(true);
+ }
+ }
+ WebviewController.setFrameViewVisible(false);
+ });
+
+ provider.onIsConnected(({ smartAccountDeployed, preferredAccountType }) => {
+ provider.getSmartAccountEnabledNetworks();
+ AccountController.setPreferredAccountType(preferredAccountType);
+ AccountController.setSmartAccountDeployed(smartAccountDeployed);
+ ConnectorController.setAuthLoading(false);
+ ModalController.setLoading(false);
+ });
+
+ provider.onNotConnected(() => {
+ ConnectorController.setAuthLoading(false);
+ ModalController.setLoading(false);
+ if (ConnectorController.state.connectedConnector === 'AUTH') {
+ ConnectionController.disconnect();
+ }
+ });
+
+ provider.onGetSmartAccountEnabledNetworks(({ smartAccountEnabledNetworks }) => {
+ return NetworkController.setSmartAccountEnabledNetworks(smartAccountEnabledNetworks);
+ });
+ }
}, [provider, webviewRef]);
return provider ? (
@@ -179,8 +197,9 @@ export function AuthWebview() {
'--w3m-background': Theme['bg-100']
}
});
- provider?.syncDappData?.({ projectId, sdkVersion });
+ provider?.syncDappData?.({ projectId, sdkVersion, sdkType });
provider?.onWebviewLoaded();
+ provider?.isConnected();
}, 1500);
}
}}
@@ -193,6 +212,8 @@ export function AuthWebview() {
) : null;
}
+export const AuthWebview = memo(_AuthWebview);
+
const styles = StyleSheet.create({
backdrop: {
position: 'absolute',
diff --git a/packages/wallet/src/AppKitFrameConstants.ts b/packages/wallet/src/AppKitFrameConstants.ts
index ddf30ed71..ac1e4844a 100644
--- a/packages/wallet/src/AppKitFrameConstants.ts
+++ b/packages/wallet/src/AppKitFrameConstants.ts
@@ -1,8 +1,8 @@
export const AppKitFrameConstants = {
SECURE_SITE_SDK: 'https://secure-mobile.walletconnect.com/mobile-sdk',
SECURE_SITE_ORIGIN: 'https://secure.walletconnect.com',
- SECURE_SITE_DASHBOARD: `https://secure.walletconnect.com/dashboard`,
- SECURE_SITE_ICON: `https://secure.walletconnect.com/images/favicon.png`,
+ SECURE_SITE_DASHBOARD: `https://secure.reown.com/dashboard`,
+ SECURE_SITE_ICON: `https://secure.reown.com/images/favicon.png`,
APP_EVENT_KEY: '@w3m-app/',
FRAME_EVENT_KEY: '@w3m-frame/',
RPC_METHOD_KEY: 'RPC_',
@@ -14,6 +14,7 @@ export const AppKitFrameConstants = {
LAST_EMAIL_LOGIN_TIME: 'LAST_EMAIL_LOGIN_TIME', // Also present in core/src/utils/StorageUtil.ts
EMAIL: 'EMAIL',
SOCIAL_USERNAME: 'SOCIAL_USERNAME',
+ SMART_ACCOUNT_ENABLED_NETWORKS: 'SMART_ACCOUNT_ENABLED_NETWORKS',
FRAME_MESSAGES_HANDLER: `
window.addEventListener('message', ({ data, origin }) => {
@@ -40,6 +41,8 @@ export const AppKitFrameConstants = {
APP_SYNC_DAPP_DATA: '@w3m-app/SYNC_DAPP_DATA',
APP_CONNECT_FARCASTER: '@w3m-app/CONNECT_FARCASTER',
APP_GET_FARCASTER_URI: '@w3m-app/GET_FARCASTER_URI',
+ APP_GET_SMART_ACCOUNT_ENABLED_NETWORKS: '@w3m-app/GET_SMART_ACCOUNT_ENABLED_NETWORKS',
+ APP_SET_PREFERRED_ACCOUNT: '@w3m-app/SET_PREFERRED_ACCOUNT',
FRAME_SWITCH_NETWORK_ERROR: '@w3m-frame/SWITCH_NETWORK_ERROR',
FRAME_SWITCH_NETWORK_SUCCESS: '@w3m-frame/SWITCH_NETWORK_SUCCESS',
@@ -77,7 +80,13 @@ export const AppKitFrameConstants = {
FRAME_SYNC_THEME_SUCCESS: '@w3m-frame/SYNC_THEME_SUCCESS',
FRAME_SYNC_THEME_ERROR: '@w3m-frame/SYNC_THEME_ERROR',
FRAME_SYNC_DAPP_DATA_SUCCESS: '@w3m-frame/SYNC_DAPP_DATA_SUCCESS',
- FRAME_SYNC_DAPP_DATA_ERROR: '@w3m-frame/SYNC_DAPP_DATA_ERROR'
+ FRAME_SYNC_DAPP_DATA_ERROR: '@w3m-frame/SYNC_DAPP_DATA_ERROR',
+ FRAME_GET_SMART_ACCOUNT_ENABLED_NETWORKS_SUCCESS:
+ '@w3m-frame/GET_SMART_ACCOUNT_ENABLED_NETWORKS_SUCCESS',
+ FRAME_GET_SMART_ACCOUNT_ENABLED_NETWORKS_ERROR:
+ '@w3m-frame/GET_SMART_ACCOUNT_ENABLED_NETWORKS_ERROR',
+ FRAME_SET_PREFERRED_ACCOUNT_SUCCESS: '@w3m-frame/SET_PREFERRED_ACCOUNT_SUCCESS',
+ FRAME_SET_PREFERRED_ACCOUNT_ERROR: '@w3m-frame/SET_PREFERRED_ACCOUNT_ERROR'
} as const;
export const AppKitFrameRpcConstants = {
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index bb8096ac1..9ae9fb2a8 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -55,13 +55,9 @@ export class AppKitFrameProvider {
this.metadata = metadata;
this.projectId = projectId;
- this.getAsyncEmail().then(email => {
- this.email = email;
- });
+ this.loadAsyncValues();
- this.getAsyncUsername().then(username => {
- this.username = username;
- });
+ this.events.setMaxListeners(Number.POSITIVE_INFINITY);
}
public setWebviewRef(webviewRef: RefObject) {
@@ -69,7 +65,6 @@ export class AppKitFrameProvider {
}
public onMessage(event: AppKitFrameTypes.FrameEvent) {
- // console.log('💻 received', event); // eslint-disable-line no-console
this.events.emit('message', event);
}
@@ -146,48 +141,36 @@ export class AppKitFrameProvider {
}
public async connectSocial(uri: string) {
- try {
- const response = await this.appEvent<'ConnectSocial'>({
- type: AppKitFrameConstants.APP_CONNECT_SOCIAL,
- payload: { uri }
- } as AppKitFrameTypes.AppEvent);
-
- if (response.userName) {
- this.setSocialLoginSuccess(response.userName);
- }
+ const response = await this.appEvent<'ConnectSocial'>({
+ type: AppKitFrameConstants.APP_CONNECT_SOCIAL,
+ payload: { uri }
+ } as AppKitFrameTypes.AppEvent);
- return response;
- } catch (error) {
- throw error;
+ if (response.userName) {
+ this.setSocialLoginSuccess(response.userName);
}
+
+ return response;
}
public async getFarcasterUri() {
- try {
- const response = await this.appEvent<'GetFarcasterUri'>({
- type: AppKitFrameConstants.APP_GET_FARCASTER_URI
- } as AppKitFrameTypes.AppEvent);
+ const response = await this.appEvent<'GetFarcasterUri'>({
+ type: AppKitFrameConstants.APP_GET_FARCASTER_URI
+ } as AppKitFrameTypes.AppEvent);
- return response;
- } catch (error) {
- throw error;
- }
+ return response;
}
public async connectFarcaster() {
- try {
- const response = await this.appEvent<'ConnectFarcaster'>({
- type: AppKitFrameConstants.APP_CONNECT_FARCASTER
- } as AppKitFrameTypes.AppEvent);
-
- if (response.userName) {
- this.setSocialLoginSuccess(response.userName);
- }
+ const response = await this.appEvent<'ConnectFarcaster'>({
+ type: AppKitFrameConstants.APP_CONNECT_FARCASTER
+ } as AppKitFrameTypes.AppEvent);
- return response;
- } catch (error) {
- throw error;
+ if (response.userName) {
+ this.setSocialLoginSuccess(response.userName);
}
+
+ return response;
}
public async connectOtp(payload: AppKitFrameTypes.Requests['AppConnectOtpRequest']) {
@@ -231,14 +214,10 @@ export class AppKitFrameProvider {
public async getSocialRedirectUri(
payload: AppKitFrameTypes.Requests['AppGetSocialRedirectUriRequest']
) {
- try {
- return this.appEvent<'GetSocialRedirectUri'>({
- type: AppKitFrameConstants.APP_GET_SOCIAL_REDIRECT_URI,
- payload
- } as AppKitFrameTypes.AppEvent);
- } catch (error) {
- throw error;
- }
+ return this.appEvent<'GetSocialRedirectUri'>({
+ type: AppKitFrameConstants.APP_GET_SOCIAL_REDIRECT_URI,
+ payload
+ } as AppKitFrameTypes.AppEvent);
}
public async updateEmail(payload: AppKitFrameTypes.Requests['AppUpdateEmailRequest']) {
@@ -306,6 +285,29 @@ export class AppKitFrameProvider {
return response;
}
+ public async getSmartAccountEnabledNetworks() {
+ try {
+ const response = await this.appEvent<'GetSmartAccountEnabledNetworks'>({
+ type: AppKitFrameConstants.APP_GET_SMART_ACCOUNT_ENABLED_NETWORKS
+ } as AppKitFrameTypes.AppEvent);
+ this.persistSmartAccountEnabledNetworks(response.smartAccountEnabledNetworks);
+
+ return response;
+ } catch (error) {
+ this.persistSmartAccountEnabledNetworks([]);
+ throw error;
+ }
+ }
+
+ public async setPreferredAccount(type: AppKitFrameTypes.AccountType) {
+ const response = await this.appEvent<'SetPreferredAccount'>({
+ type: AppKitFrameConstants.APP_SET_PREFERRED_ACCOUNT,
+ payload: { type }
+ } as AppKitFrameTypes.AppEvent);
+
+ return response;
+ }
+
// -- Provider Methods ------------------------------------------------
public async connect(payload?: AppKitFrameTypes.Requests['AppGetUserRequest']) {
const lastUsedChain = await this.getLastUsedChainId();
@@ -385,24 +387,18 @@ export class AppKitFrameProvider {
this.rpcErrorHandler = callback;
}
- public onRpcResponse(event: AppKitFrameTypes.FrameEvent, callback: (request: unknown) => void) {
- this.onFrameEvent(event, frameEvent => {
- if (frameEvent.type.includes(AppKitFrameConstants.RPC_METHOD_KEY)) {
- callback(frameEvent);
- }
- });
- }
-
- public onIsConnected(event: AppKitFrameTypes.FrameEvent, callback: () => void) {
- this.onFrameEvent(event, frameEvent => {
+ public onIsConnected(
+ callback: (response: AppKitFrameTypes.Responses['FrameGetUserResponse']) => void
+ ) {
+ this.onFrameEvent(frameEvent => {
if (frameEvent.type === AppKitFrameConstants.FRAME_GET_USER_SUCCESS) {
- callback();
+ callback(frameEvent.payload);
}
});
}
- public onNotConnected(event: AppKitFrameTypes.FrameEvent, callback: () => void) {
- this.onFrameEvent(event, frameEvent => {
+ public onNotConnected(callback: () => void) {
+ this.onFrameEvent(frameEvent => {
if (frameEvent.type === AppKitFrameConstants.FRAME_IS_CONNECTED_ERROR) {
callback();
}
@@ -415,6 +411,39 @@ export class AppKitFrameProvider {
});
}
+ public onGetSmartAccountEnabledNetworks(
+ callback: (
+ response: AppKitFrameTypes.Responses['FrameGetSmartAccountEnabledNetworksResponse']
+ ) => void
+ ) {
+ this.onFrameEvent(frameEvent => {
+ if (
+ frameEvent.type === AppKitFrameConstants.FRAME_GET_SMART_ACCOUNT_ENABLED_NETWORKS_SUCCESS
+ ) {
+ callback(frameEvent.payload);
+ }
+ });
+ }
+
+ public onSetPreferredAccount(
+ callback: (response: AppKitFrameTypes.Responses['FrameSetPreferredAccountResponse']) => void
+ ) {
+ this.onFrameEvent(frameEvent => {
+ if (frameEvent.type === AppKitFrameConstants.FRAME_SET_PREFERRED_ACCOUNT_SUCCESS) {
+ callback(frameEvent.payload);
+ }
+ });
+ }
+
+ public async getLastUsedChainId() {
+ const chainId = await AppKitFrameStorage.get(AppKitFrameConstants.LAST_USED_CHAIN_KEY);
+ if (chainId) {
+ return Number(chainId);
+ }
+
+ return undefined;
+ }
+
// -- Private Methods -------------------------------------------------
private setNewLastEmailLoginTime() {
AppKitFrameStorage.set(AppKitFrameConstants.LAST_EMAIL_LOGIN_TIME, Date.now().toString());
@@ -445,13 +474,8 @@ export class AppKitFrameProvider {
AppKitFrameStorage.set(AppKitFrameConstants.LAST_USED_CHAIN_KEY, String(chainId));
}
- private async getLastUsedChainId() {
- const chainId = await AppKitFrameStorage.get(AppKitFrameConstants.LAST_USED_CHAIN_KEY);
- if (chainId) {
- return Number(chainId);
- }
-
- return undefined;
+ private persistSmartAccountEnabledNetworks(networks: number[]) {
+ AppKitFrameStorage.set(AppKitFrameConstants.SMART_ACCOUNT_ENABLED_NETWORKS, networks.join(','));
}
private async registerFrameEventHandler(
@@ -518,18 +542,19 @@ export class AppKitFrameProvider {
});
}
- private onFrameEvent(
- event: AppKitFrameTypes.FrameEvent,
- callback: (event: AppKitFrameTypes.FrameEvent) => void
- ) {
- if (
- !event.type?.includes(AppKitFrameConstants.FRAME_EVENT_KEY) ||
- event.origin !== AppKitFrameConstants.SECURE_SITE_ORIGIN
- ) {
- return;
- }
- const frameEvent = AppKitFrameSchema.frameEvent.parse(event);
- callback(frameEvent);
+ private onFrameEvent(callback: (event: AppKitFrameTypes.FrameEvent) => void) {
+ const eventHandler = (event: AppKitFrameTypes.FrameEvent) => {
+ if (
+ !event.type?.includes(AppKitFrameConstants.FRAME_EVENT_KEY) ||
+ event.origin !== AppKitFrameConstants.SECURE_SITE_ORIGIN
+ ) {
+ return;
+ }
+ // console.log('💻 received', event); // eslint-disable-line no-console
+ callback(event);
+ };
+
+ this.events.addListener('message', eventHandler);
}
private postAppEvent(event: AppKitFrameTypes.AppEvent) {
@@ -554,15 +579,10 @@ export class AppKitFrameProvider {
);
}
- private async getAsyncEmail() {
+ private async loadAsyncValues() {
const email = await AppKitFrameStorage.get(AppKitFrameConstants.EMAIL);
-
- return email;
- }
-
- private async getAsyncUsername() {
+ this.email = email;
const username = await AppKitFrameStorage.get(AppKitFrameConstants.SOCIAL_USERNAME);
-
- return username;
+ this.username = username;
}
}
diff --git a/packages/wallet/src/AppKitFrameSchema.ts b/packages/wallet/src/AppKitFrameSchema.ts
index 329a26c75..3d7ffe04e 100644
--- a/packages/wallet/src/AppKitFrameSchema.ts
+++ b/packages/wallet/src/AppKitFrameSchema.ts
@@ -29,14 +29,14 @@ export const GetTransactionByHashResponse = z.object({
v: z.string(),
value: z.string()
});
-export const AppSwitchNetworkRequest = z.object({ chainId: z.string().or(z.number()) });
+export const AppSwitchNetworkRequest = z.object({ chainId: z.number() });
export const AppConnectEmailRequest = z.object({ email: z.string().email() });
export const AppConnectOtpRequest = z.object({ otp: z.string() });
export const AppConnectSocialRequest = z.object({ uri: z.string() });
export const AppGetSocialRedirectUriRequest = z.object({
provider: z.enum(['google', 'github', 'apple', 'facebook', 'x', 'discord', 'farcaster'])
});
-export const AppGetUserRequest = z.object({ chainId: z.optional(z.string().or(z.number())) });
+export const AppGetUserRequest = z.object({ chainId: z.optional(z.number()) });
export const AppUpdateEmailRequest = z.object({ email: z.string().email() });
export const AppUpdateEmailPrimaryOtpRequest = z.object({ otp: z.string() });
export const AppUpdateEmailSecondaryOtpRequest = z.object({ otp: z.string() });
@@ -59,10 +59,16 @@ export const AppSyncDappDataRequest = z.object({
| `react-native-ethers5-${string}`
| `react-native-ethers-${string}`
>,
+ sdkType: z.enum(['appkit']),
projectId: z.string()
});
export const AppSetPreferredAccountRequest = z.object({ type: z.string() });
+const AccountTypeEnum = z.enum([
+ AppKitFrameRpcConstants.ACCOUNT_TYPES.EOA,
+ AppKitFrameRpcConstants.ACCOUNT_TYPES.SMART_ACCOUNT
+]);
+
export const FrameConnectEmailResponse = z.object({
action: z.enum(['VERIFY_DEVICE', 'VERIFY_OTP'])
});
@@ -72,7 +78,9 @@ export const FrameUpdateEmailResponse = z.object({
export const FrameGetUserResponse = z.object({
email: z.string().email().optional().nullable(),
address: z.string(),
- chainId: z.string().or(z.number())
+ chainId: z.number(),
+ smartAccountDeployed: z.boolean(),
+ preferredAccountType: AccountTypeEnum
});
export const FrameIsConnectedResponse = z.object({ isConnected: z.boolean() });
export const FrameGetChainIdResponse = z.object({ chainId: z.number() });
@@ -88,10 +96,7 @@ export const FrameConnectSocialResponse = z.object({
.array(
z.object({
address: z.string(),
- type: z.enum([
- AppKitFrameRpcConstants.ACCOUNT_TYPES.EOA,
- AppKitFrameRpcConstants.ACCOUNT_TYPES.SMART_ACCOUNT
- ])
+ type: AccountTypeEnum
})
)
.optional(),
@@ -106,6 +111,15 @@ export const FrameConnectFarcasterResponse = z.object({
userName: z.string()
});
+export const FrameSetPreferredAccountResponse = z.object({
+ type: AccountTypeEnum,
+ address: z.string()
+});
+
+export const FrameGetSmartAccountEnabledNetworksResponse = z.object({
+ smartAccountEnabledNetworks: z.array(z.number())
+});
+
export const RpcResponse = z.any();
export const RpcEthAccountsRequest = z.object({
@@ -334,6 +348,15 @@ export const AppKitFrameSchema = {
.or(EventSchema.extend({ type: zType('APP_GET_CHAIN_ID') }))
+ .or(EventSchema.extend({ type: zType('APP_GET_SMART_ACCOUNT_ENABLED_NETWORKS') }))
+
+ .or(
+ EventSchema.extend({
+ type: zType('APP_SET_PREFERRED_ACCOUNT'),
+ payload: AppSetPreferredAccountRequest
+ })
+ )
+
.or(
EventSchema.extend({
type: zType('APP_RPC_REQUEST'),
@@ -660,4 +683,35 @@ export const AppKitFrameSchema = {
)
.or(EventSchema.extend({ type: zType('FRAME_SYNC_DAPP_DATA_SUCCESS'), origin: z.string() }))
+
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_SMART_ACCOUNT_ENABLED_NETWORKS_SUCCESS'),
+ payload: FrameGetSmartAccountEnabledNetworksResponse,
+ origin: z.string()
+ })
+ )
+
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_GET_SMART_ACCOUNT_ENABLED_NETWORKS_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
+
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_SET_PREFERRED_ACCOUNT_SUCCESS'),
+ payload: FrameSetPreferredAccountResponse,
+ origin: z.string()
+ })
+ )
+ .or(
+ EventSchema.extend({
+ type: zType('FRAME_SET_PREFERRED_ACCOUNT_ERROR'),
+ payload: zError,
+ origin: z.string()
+ })
+ )
};
diff --git a/packages/wallet/src/AppKitFrameTypes.ts b/packages/wallet/src/AppKitFrameTypes.ts
index c4e4104e3..40b712b34 100644
--- a/packages/wallet/src/AppKitFrameTypes.ts
+++ b/packages/wallet/src/AppKitFrameTypes.ts
@@ -61,8 +61,12 @@ import {
AppGetSocialRedirectUriRequest,
AppConnectSocialRequest,
FrameGetFarcasterUriResponse,
- FrameConnectFarcasterResponse
+ FrameConnectFarcasterResponse,
+ AppSetPreferredAccountRequest,
+ FrameSetPreferredAccountResponse,
+ FrameGetSmartAccountEnabledNetworksResponse
} from './AppKitFrameSchema';
+import type { AppKitFrameRpcConstants } from './AppKitFrameConstants';
export namespace AppKitFrameTypes {
export type AppEvent = z.infer;
@@ -81,6 +85,8 @@ export namespace AppKitFrameTypes {
AppUpdateEmailSecondaryOtpRequest: z.infer;
AppGetSocialRedirectUriRequest: z.infer;
AppConnectSocialRequest: z.infer;
+ AppSetPreferredAccountRequest: z.infer;
+ AppGetSmartAccountEnabledNetworksRequest: undefined;
}
export interface Responses {
@@ -101,6 +107,10 @@ export namespace AppKitFrameTypes {
FrameUpdateEmailSecondaryOtpResponse: z.infer;
FrameConnectDeviceResponse: undefined;
FrameSignOutResponse: undefined;
+ FrameGetSmartAccountEnabledNetworksResponse: z.infer<
+ typeof FrameGetSmartAccountEnabledNetworksResponse
+ >;
+ FrameSetPreferredAccountResponse: z.infer;
FrameRpcResponse: RPCResponse;
}
@@ -159,6 +169,9 @@ export namespace AppKitFrameTypes {
export type FrameSessionType = z.infer;
+ export type AccountType =
+ (typeof AppKitFrameRpcConstants.ACCOUNT_TYPES)[keyof typeof AppKitFrameRpcConstants.ACCOUNT_TYPES];
+
export type ProviderRequestType =
| 'GetUser'
| 'ConnectDevice'
@@ -175,6 +188,8 @@ export namespace AppKitFrameTypes {
| 'UpdateEmailPrimaryOtp'
| 'UpdateEmailSecondaryOtp'
| 'GetChainId'
+ | 'GetSmartAccountEnabledNetworks'
+ | 'SetPreferredAccount'
| 'IsConnected'
| 'SignOut'
| 'Rpc';
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index 536ad48cc..d4c98dea5 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { useEffect, useRef, useState } from 'react';
+import { memo, useEffect, useRef, useState } from 'react';
import { Animated, SafeAreaView, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
@@ -13,7 +13,7 @@ import type { AppKitFrameProvider } from './AppKitFrameProvider';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
-export function AppKitWebview() {
+function _AppKitWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
const authConnector = ConnectorController.getAuthConnector();
@@ -110,6 +110,8 @@ export function AppKitWebview() {
) : null;
}
+export const AppKitWebview = memo(_AppKitWebview);
+
const styles = StyleSheet.create({
backdrop: {
position: 'absolute',
diff --git a/yarn.lock b/yarn.lock
index 49c489586..4f8e5d222 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -38,6 +38,13 @@ __metadata:
languageName: node
linkType: hard
+"@adraffy/ens-normalize@npm:1.11.0":
+ version: 1.11.0
+ resolution: "@adraffy/ens-normalize@npm:1.11.0"
+ checksum: 5111d0f1a273468cb5661ed3cf46ee58de8f32f84e2ebc2365652e66c1ead82649df94c736804e2b9cfa831d30ef24e1cc3575d970dbda583416d3a98d8870a6
+ languageName: node
+ linkType: hard
+
"@ampproject/remapping@npm:^2.2.0":
version: 2.2.1
resolution: "@ampproject/remapping@npm:2.2.1"
@@ -97,7 +104,7 @@ __metadata:
"@tanstack/react-query-persist-client": "npm:5.56.2"
"@types/react": "npm:~18.2.79"
"@types/react-native": "npm:0.72.2"
- "@walletconnect/react-native-compat": "npm:2.16.1"
+ "@walletconnect/react-native-compat": "npm:2.17.1"
babel-plugin-module-resolver: "npm:^5.0.0"
expo: "npm:~51.0.24"
expo-application: "npm:~5.9.1"
@@ -114,8 +121,8 @@ __metadata:
react-native-webview: "npm:13.8.6"
typescript: "npm:~5.3.3"
uuid: "npm:3.4.0"
- viem: "npm:2.21.6"
- wagmi: "npm:2.12.11"
+ viem: "npm:2.21.37"
+ wagmi: "npm:2.12.25"
languageName: unknown
linkType: soft
@@ -3613,17 +3620,15 @@ __metadata:
languageName: node
linkType: hard
-"@coinbase/wallet-sdk@npm:4.0.4":
- version: 4.0.4
- resolution: "@coinbase/wallet-sdk@npm:4.0.4"
+"@coinbase/wallet-sdk@npm:4.1.0":
+ version: 4.1.0
+ resolution: "@coinbase/wallet-sdk@npm:4.1.0"
dependencies:
- buffer: "npm:^6.0.3"
+ "@noble/hashes": "npm:^1.4.0"
clsx: "npm:^1.2.1"
eventemitter3: "npm:^5.0.1"
- keccak: "npm:^3.0.3"
preact: "npm:^10.16.0"
- sha.js: "npm:^2.4.11"
- checksum: 7c8c39688c144b5305ac59d847023f7dce9ccffdd8ed6fdcc690c03980ce7cf8f88caff4e0cf0a1f081bcfd61ebe6a590970771505f86700f9b798a0e8e2dc88
+ checksum: 9ccd8171e8874a357f246fc3b8b9641cb015f12e0c8912c15b77c55cdca58c00ba59c68afdc3162d26421fedcaf8164a95ee39abce96e4dcde5b391e0920ca65
languageName: node
linkType: hard
@@ -3636,6 +3641,15 @@ __metadata:
languageName: node
linkType: hard
+"@ecies/ciphers@npm:^0.2.0":
+ version: 0.2.1
+ resolution: "@ecies/ciphers@npm:0.2.1"
+ peerDependencies:
+ "@noble/ciphers": ^1.0.0
+ checksum: 0ce13f5f8216047afde68afe549021c65145af2d2f08da032552487f170c47fd480c11fa358b5cdcc29e70928e5d81e037b6a5963a20ba74d3c242881ba5bb50
+ languageName: node
+ linkType: hard
+
"@esbuild/aix-ppc64@npm:0.23.1":
version: 0.23.1
resolution: "@esbuild/aix-ppc64@npm:0.23.1"
@@ -5375,9 +5389,9 @@ __metadata:
languageName: node
linkType: hard
-"@metamask/sdk-communication-layer@npm:0.28.2":
- version: 0.28.2
- resolution: "@metamask/sdk-communication-layer@npm:0.28.2"
+"@metamask/sdk-communication-layer@npm:0.30.0":
+ version: 0.30.0
+ resolution: "@metamask/sdk-communication-layer@npm:0.30.0"
dependencies:
bufferutil: "npm:^4.0.8"
date-fns: "npm:^2.29.3"
@@ -5390,13 +5404,13 @@ __metadata:
eventemitter2: ^6.4.7
readable-stream: ^3.6.2
socket.io-client: ^4.5.1
- checksum: 7d51316eb313bd4464e8e5d787c4d88228e40673414883a693f5772908cb5c17903db0d3101bc04ee9db218728525a0ad3a8545c6e7d933b48f3ae6ce8a474bc
+ checksum: e3f2b1a05e474142c1c92c89b4347cbefe4503143cd9e27ff961a341afe2bc2d593b111db5a9425231ff1661a9219449fb50c47c3f4ccc39c81c97e925aac477
languageName: node
linkType: hard
-"@metamask/sdk-install-modal-web@npm:0.28.1":
- version: 0.28.1
- resolution: "@metamask/sdk-install-modal-web@npm:0.28.1"
+"@metamask/sdk-install-modal-web@npm:0.30.0":
+ version: 0.30.0
+ resolution: "@metamask/sdk-install-modal-web@npm:0.30.0"
dependencies:
qr-code-styling: "npm:^1.6.0-rc.1"
peerDependencies:
@@ -5411,24 +5425,22 @@ __metadata:
optional: true
react-native:
optional: true
- checksum: e7bc9789d6499ff1f2ec2587b0604c4df445bc35e0914165289348fe9325ccff60ef094b5ebe39310af9c68ee8d6d71ed0a6a217e2d3947a2aa92a4c7063e4a1
+ checksum: b515a356148179e74c80562d6127c59a21d25bce0a83bef3b190d02785d231936cc394fb87f6141a673ba0d8ba3f443f0572540aa6883b74ea17b9f6e771dc00
languageName: node
linkType: hard
-"@metamask/sdk@npm:0.28.2":
- version: 0.28.2
- resolution: "@metamask/sdk@npm:0.28.2"
+"@metamask/sdk@npm:0.30.1":
+ version: 0.30.1
+ resolution: "@metamask/sdk@npm:0.30.1"
dependencies:
"@metamask/onboarding": "npm:^1.0.1"
"@metamask/providers": "npm:16.1.0"
- "@metamask/sdk-communication-layer": "npm:0.28.2"
- "@metamask/sdk-install-modal-web": "npm:0.28.1"
- "@types/dom-screen-wake-lock": "npm:^1.0.0"
- "@types/uuid": "npm:^10.0.0"
+ "@metamask/sdk-communication-layer": "npm:0.30.0"
+ "@metamask/sdk-install-modal-web": "npm:0.30.0"
bowser: "npm:^2.9.0"
cross-fetch: "npm:^4.0.0"
debug: "npm:^4.3.4"
- eciesjs: "npm:^0.3.15"
+ eciesjs: "npm:^0.4.8"
eth-rpc-errors: "npm:^4.0.3"
eventemitter2: "npm:^6.4.7"
i18next: "npm:23.11.5"
@@ -5438,7 +5450,6 @@ __metadata:
qrcode-terminal-nooctal: "npm:^0.12.1"
react-native-webview: "npm:^11.26.0"
readable-stream: "npm:^3.6.2"
- rollup-plugin-visualizer: "npm:^5.9.2"
socket.io-client: "npm:^4.5.1"
util: "npm:^0.12.4"
uuid: "npm:^8.3.2"
@@ -5450,7 +5461,7 @@ __metadata:
optional: true
react-dom:
optional: true
- checksum: 519240bd0729e9fbee6000d794c7071d4739917c40b3f4529f6315690b76221595110e4ede6ade10b595da8de4a152ac8a8571f6600ab16b132de61548536b37
+ checksum: e42a98471adecc6c291e322ec6772fa8f8d9ae9949887e59c77f7d916ff44f5e69fc57b74449b2e04603e8ecb550e782815a6dc8f81f8afc291fc61d06fe6722
languageName: node
linkType: hard
@@ -5594,6 +5605,13 @@ __metadata:
languageName: node
linkType: hard
+"@noble/ciphers@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "@noble/ciphers@npm:1.0.0"
+ checksum: 6c04d6e9d10a922fff170efc44622c95a25fb817f4b593e0f150dd27599576f3fe3c5b61eb02054b22d1507e3839879ddd5acb2d2acf8efbea4efab99bbcd333
+ languageName: node
+ linkType: hard
+
"@noble/curves@npm:1.1.0, @noble/curves@npm:~1.1.0":
version: 1.1.0
resolution: "@noble/curves@npm:1.1.0"
@@ -5621,6 +5639,15 @@ __metadata:
languageName: node
linkType: hard
+"@noble/curves@npm:1.6.0, @noble/curves@npm:^1.6.0, @noble/curves@npm:~1.6.0":
+ version: 1.6.0
+ resolution: "@noble/curves@npm:1.6.0"
+ dependencies:
+ "@noble/hashes": "npm:1.5.0"
+ checksum: f3262aa4d39148e627cd82b5ac1c93f88c5bb46dd2566b5e8e52ffac3a0fc381ad30c2111656fd2bd3b0d37d43d540543e0d93a5ff96a6cb184bc3bfe10d1cd9
+ languageName: node
+ linkType: hard
+
"@noble/curves@npm:^1.4.0, @noble/curves@npm:~1.4.0":
version: 1.4.2
resolution: "@noble/curves@npm:1.4.2"
@@ -5651,6 +5678,13 @@ __metadata:
languageName: node
linkType: hard
+"@noble/hashes@npm:1.5.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:~1.5.0":
+ version: 1.5.0
+ resolution: "@noble/hashes@npm:1.5.0"
+ checksum: 1b46539695fbfe4477c0822d90c881a04d4fa2921c08c552375b444a48cac9930cb1ee68de0a3c7859e676554d0f3771999716606dc4d8f826e414c11692cdd9
+ languageName: node
+ linkType: hard
+
"@noble/hashes@npm:~1.3.1":
version: 1.3.3
resolution: "@noble/hashes@npm:1.3.3"
@@ -5658,13 +5692,6 @@ __metadata:
languageName: node
linkType: hard
-"@noble/hashes@npm:~1.5.0":
- version: 1.5.0
- resolution: "@noble/hashes@npm:1.5.0"
- checksum: 1b46539695fbfe4477c0822d90c881a04d4fa2921c08c552375b444a48cac9930cb1ee68de0a3c7859e676554d0f3771999716606dc4d8f826e414c11692cdd9
- languageName: node
- linkType: hard
-
"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
@@ -6731,6 +6758,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@reown/appkit-auth-wagmi-react-native@workspace:packages/auth-wagmi"
dependencies:
+ "@reown/appkit-core-react-native": "npm:1.0.2"
"@reown/appkit-wallet-react-native": "npm:1.0.2"
peerDependencies:
wagmi: ">=2"
@@ -6963,6 +6991,13 @@ __metadata:
languageName: node
linkType: hard
+"@scure/base@npm:~1.1.7":
+ version: 1.1.9
+ resolution: "@scure/base@npm:1.1.9"
+ checksum: 77a06b9a2db8144d22d9bf198338893d77367c51b58c72b99df990c0a11f7cadd066d4102abb15e3ca6798d1529e3765f55c4355742465e49aed7a0c01fe76e8
+ languageName: node
+ linkType: hard
+
"@scure/base@npm:~1.1.8":
version: 1.1.8
resolution: "@scure/base@npm:1.1.8"
@@ -6992,6 +7027,17 @@ __metadata:
languageName: node
linkType: hard
+"@scure/bip32@npm:1.5.0":
+ version: 1.5.0
+ resolution: "@scure/bip32@npm:1.5.0"
+ dependencies:
+ "@noble/curves": "npm:~1.6.0"
+ "@noble/hashes": "npm:~1.5.0"
+ "@scure/base": "npm:~1.1.7"
+ checksum: 3319beda59e7f129d770cbe49709a2d1742f2deb6989b12e37aa1a47cd128a8c943bdd9286c6a5513ef4539307c4bca8f89f9aa91f294cac4598cbf95fa0c01d
+ languageName: node
+ linkType: hard
+
"@scure/bip39@npm:1.2.1":
version: 1.2.1
resolution: "@scure/bip39@npm:1.2.1"
@@ -8066,13 +8112,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/dom-screen-wake-lock@npm:^1.0.0":
- version: 1.0.3
- resolution: "@types/dom-screen-wake-lock@npm:1.0.3"
- checksum: bab45f6a797de562f1bd3c095c49b7c0464ad05e571f38d00adaa35da2b02109bfe587206cc55f420377634cf0f7b07caa5acb3257e49dfd2d94dab74c617bf1
- languageName: node
- linkType: hard
-
"@types/escodegen@npm:^0.0.6":
version: 0.0.6
resolution: "@types/escodegen@npm:0.0.6"
@@ -8384,15 +8423,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/secp256k1@npm:^4.0.4":
- version: 4.0.6
- resolution: "@types/secp256k1@npm:4.0.6"
- dependencies:
- "@types/node": "npm:*"
- checksum: 0e391316ae30c218779583b626382a56546ddbefb65f1ff9cf5e078af8a7118f67f3e66e30914399cc6f8710c424d0d8c3f34262ffb1f429c6ad911fd0d0bc26
- languageName: node
- linkType: hard
-
"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4":
version: 7.5.0
resolution: "@types/semver@npm:7.5.0"
@@ -8463,13 +8493,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/uuid@npm:^10.0.0":
- version: 10.0.0
- resolution: "@types/uuid@npm:10.0.0"
- checksum: 9a1404bf287164481cb9b97f6bb638f78f955be57c40c6513b7655160beb29df6f84c915aaf4089a1559c216557dc4d2f79b48d978742d3ae10b937420ddac60
- languageName: node
- linkType: hard
-
"@types/uuid@npm:^9.0.1":
version: 9.0.8
resolution: "@types/uuid@npm:9.0.8"
@@ -8786,35 +8809,34 @@ __metadata:
languageName: node
linkType: hard
-"@wagmi/connectors@npm:5.1.10":
- version: 5.1.10
- resolution: "@wagmi/connectors@npm:5.1.10"
+"@wagmi/connectors@npm:5.3.3":
+ version: 5.3.3
+ resolution: "@wagmi/connectors@npm:5.3.3"
dependencies:
- "@coinbase/wallet-sdk": "npm:4.0.4"
- "@metamask/sdk": "npm:0.28.2"
+ "@coinbase/wallet-sdk": "npm:4.1.0"
+ "@metamask/sdk": "npm:0.30.1"
"@safe-global/safe-apps-provider": "npm:0.18.3"
"@safe-global/safe-apps-sdk": "npm:9.1.0"
- "@walletconnect/ethereum-provider": "npm:2.16.1"
- "@walletconnect/modal": "npm:2.6.2"
+ "@walletconnect/ethereum-provider": "npm:2.17.0"
cbw-sdk: "npm:@coinbase/wallet-sdk@3.9.3"
peerDependencies:
- "@wagmi/core": 2.13.5
+ "@wagmi/core": 2.14.1
typescript: ">=5.0.4"
viem: 2.x
peerDependenciesMeta:
typescript:
optional: true
- checksum: 9af1a06bd239f7c710ebc05a507f65d20a1860b8e05d4bf10b85cef94d8d9ae77cc7a4dbc402b9237fde0701071f46fa8e7a384fcb7873ea03493b11a6125d22
+ checksum: 78789ed27fca0bc1d54a3a8282584ddcbdcee26f2d95b27d7dd9663a7cd02e2728e0bcdd0ce0aaae8983dfac3ad966c03243dd08ce11b80d908c314f0d139cb7
languageName: node
linkType: hard
-"@wagmi/core@npm:2.13.5":
- version: 2.13.5
- resolution: "@wagmi/core@npm:2.13.5"
+"@wagmi/core@npm:2.14.1":
+ version: 2.14.1
+ resolution: "@wagmi/core@npm:2.14.1"
dependencies:
eventemitter3: "npm:5.0.1"
mipd: "npm:0.0.7"
- zustand: "npm:4.4.1"
+ zustand: "npm:5.0.0"
peerDependencies:
"@tanstack/query-core": ">=5.0.0"
typescript: ">=5.0.4"
@@ -8824,7 +8846,7 @@ __metadata:
optional: true
typescript:
optional: true
- checksum: e386de867acf92e6a29a6e22e2d612719a1c60cb126473d6675b8b02af2f92c13c9202b89287540872eeace15213fe309411466d5d93fe5308da3a68550aca9f
+ checksum: 4cde494a8fcf218e79eb4e650fd598fbb273fcaa3cab52aa0a3b41a2a104de2bac602ed19d2d2c6b130f881300770d809b5e1bfd81a8375269bed7d4e9606fb0
languageName: node
linkType: hard
@@ -8852,6 +8874,30 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/core@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/core@npm:2.17.0"
+ dependencies:
+ "@walletconnect/heartbeat": "npm:1.2.2"
+ "@walletconnect/jsonrpc-provider": "npm:1.0.14"
+ "@walletconnect/jsonrpc-types": "npm:1.0.4"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/jsonrpc-ws-connection": "npm:1.0.14"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
+ "@walletconnect/logger": "npm:2.1.2"
+ "@walletconnect/relay-api": "npm:1.0.11"
+ "@walletconnect/relay-auth": "npm:1.0.4"
+ "@walletconnect/safe-json": "npm:1.0.2"
+ "@walletconnect/time": "npm:1.0.2"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
+ events: "npm:3.3.0"
+ lodash.isequal: "npm:4.5.0"
+ uint8arrays: "npm:3.1.0"
+ checksum: 34ae5b9b68c08c1dd3ebb2a6ebff8697307e76fbfe4d6b51d5d090da5cd1613e1c66fa5ac3a87c914333458d7b5bf075bb664292f6b2c7d438c72f706d87416d
+ languageName: node
+ linkType: hard
+
"@walletconnect/environment@npm:^1.0.1":
version: 1.0.1
resolution: "@walletconnect/environment@npm:1.0.1"
@@ -8879,6 +8925,24 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/ethereum-provider@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/ethereum-provider@npm:2.17.0"
+ dependencies:
+ "@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
+ "@walletconnect/jsonrpc-provider": "npm:1.0.14"
+ "@walletconnect/jsonrpc-types": "npm:1.0.4"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/modal": "npm:2.7.0"
+ "@walletconnect/sign-client": "npm:2.17.0"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/universal-provider": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
+ events: "npm:3.3.0"
+ checksum: b046a9c296e95b22841f0b2efd28a4ce1a38529a9ba412d3c8ffc482879d79c3d2a24b8c0ec712baecf781938b4321ab5c1ecad5573d078add7c47b0cfd08a25
+ languageName: node
+ linkType: hard
+
"@walletconnect/events@npm:1.0.1, @walletconnect/events@npm:^1.0.1":
version: 1.0.1
resolution: "@walletconnect/events@npm:1.0.1"
@@ -9001,6 +9065,15 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/modal-core@npm:2.7.0":
+ version: 2.7.0
+ resolution: "@walletconnect/modal-core@npm:2.7.0"
+ dependencies:
+ valtio: "npm:1.11.2"
+ checksum: 84b11735c005e37e661aa0f08b2e8c8098db3b2cacd957c4a73f4d3de11b2d5e04dd97ab970f8d22fc3e8269fea3297b9487e177343bbab8dd69b3b917fb7f60
+ languageName: node
+ linkType: hard
+
"@walletconnect/modal-ui@npm:2.6.2":
version: 2.6.2
resolution: "@walletconnect/modal-ui@npm:2.6.2"
@@ -9013,6 +9086,18 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/modal-ui@npm:2.7.0":
+ version: 2.7.0
+ resolution: "@walletconnect/modal-ui@npm:2.7.0"
+ dependencies:
+ "@walletconnect/modal-core": "npm:2.7.0"
+ lit: "npm:2.8.0"
+ motion: "npm:10.16.2"
+ qrcode: "npm:1.5.3"
+ checksum: b717f1fc9854b7d14a4364720fce2d44167f547533340704644ed2fdf9d861b3798ffd19a3b51062a366a8bc39f84b9a8bb3dd04e9e33da742192359be00b051
+ languageName: node
+ linkType: hard
+
"@walletconnect/modal@npm:2.6.2":
version: 2.6.2
resolution: "@walletconnect/modal@npm:2.6.2"
@@ -9023,6 +9108,16 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/modal@npm:2.7.0":
+ version: 2.7.0
+ resolution: "@walletconnect/modal@npm:2.7.0"
+ dependencies:
+ "@walletconnect/modal-core": "npm:2.7.0"
+ "@walletconnect/modal-ui": "npm:2.7.0"
+ checksum: 2f3074eebbca41a46e29680dc2565bc762133508774f05db0075a82b0b66ecc8defca40a94ad63669676090a7e3ef671804592b10e91636ab1cdeac014a1eb11
+ languageName: node
+ linkType: hard
+
"@walletconnect/react-native-compat@npm:2.16.1":
version: 2.16.1
resolution: "@walletconnect/react-native-compat@npm:2.16.1"
@@ -9042,6 +9137,26 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/react-native-compat@npm:2.17.1":
+ version: 2.17.1
+ resolution: "@walletconnect/react-native-compat@npm:2.17.1"
+ dependencies:
+ events: "npm:3.3.0"
+ fast-text-encoding: "npm:1.0.6"
+ react-native-url-polyfill: "npm:2.0.0"
+ peerDependencies:
+ "@react-native-async-storage/async-storage": "*"
+ "@react-native-community/netinfo": "*"
+ expo-application: "*"
+ react-native: "*"
+ react-native-get-random-values: "*"
+ peerDependenciesMeta:
+ expo-application:
+ optional: true
+ checksum: 55afa3b7de9cf71f208a10d30ac70bbef67d32013807ebfc2f99ab61cc7e27a51def1e4e795e88e9164452c0ab1d219820cf5b8e0e5e4c316a7501a508476bba
+ languageName: node
+ linkType: hard
+
"@walletconnect/relay-api@npm:1.0.11":
version: 1.0.11
resolution: "@walletconnect/relay-api@npm:1.0.11"
@@ -9091,6 +9206,23 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/sign-client@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/sign-client@npm:2.17.0"
+ dependencies:
+ "@walletconnect/core": "npm:2.17.0"
+ "@walletconnect/events": "npm:1.0.1"
+ "@walletconnect/heartbeat": "npm:1.2.2"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/logger": "npm:2.1.2"
+ "@walletconnect/time": "npm:1.0.2"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
+ events: "npm:3.3.0"
+ checksum: 48f7d13b3db49584a40dc2653f49fabadd100a324e2213476b8d9e4d6fe0808a08ae14103d2e5b609abff3115197003d8570d606275dbd0f6774d0d49da10c61
+ languageName: node
+ linkType: hard
+
"@walletconnect/time@npm:1.0.2, @walletconnect/time@npm:^1.0.2":
version: 1.0.2
resolution: "@walletconnect/time@npm:1.0.2"
@@ -9114,6 +9246,20 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/types@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/types@npm:2.17.0"
+ dependencies:
+ "@walletconnect/events": "npm:1.0.1"
+ "@walletconnect/heartbeat": "npm:1.2.2"
+ "@walletconnect/jsonrpc-types": "npm:1.0.4"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
+ "@walletconnect/logger": "npm:2.1.2"
+ events: "npm:3.3.0"
+ checksum: bdc0c062da1edb4410882d9cfca1bb30eb0afd7caea90d5e7a66eaf15e28380e9ef97635cd5e5a017947f4c814c1f780622b4d8946b11a335d415ae066ec7ade
+ languageName: node
+ linkType: hard
+
"@walletconnect/universal-provider@npm:2.16.1":
version: 2.16.1
resolution: "@walletconnect/universal-provider@npm:2.16.1"
@@ -9131,6 +9277,23 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/universal-provider@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/universal-provider@npm:2.17.0"
+ dependencies:
+ "@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
+ "@walletconnect/jsonrpc-provider": "npm:1.0.14"
+ "@walletconnect/jsonrpc-types": "npm:1.0.4"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/logger": "npm:2.1.2"
+ "@walletconnect/sign-client": "npm:2.17.0"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
+ events: "npm:3.3.0"
+ checksum: 7c1afc79054db5add4e937d7adaadb4fc26aecffb5d749d388418fa5d4eb153807ab4de301b642cd80669b4e5c6bcae917f18cf5ce8696d87da8b3705b60d1ec
+ languageName: node
+ linkType: hard
+
"@walletconnect/utils@npm:2.16.1":
version: 2.16.1
resolution: "@walletconnect/utils@npm:2.16.1"
@@ -9155,6 +9318,30 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/utils@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/utils@npm:2.17.0"
+ dependencies:
+ "@stablelib/chacha20poly1305": "npm:1.0.1"
+ "@stablelib/hkdf": "npm:1.0.1"
+ "@stablelib/random": "npm:1.0.2"
+ "@stablelib/sha256": "npm:1.0.1"
+ "@stablelib/x25519": "npm:1.0.3"
+ "@walletconnect/relay-api": "npm:1.0.11"
+ "@walletconnect/relay-auth": "npm:1.0.4"
+ "@walletconnect/safe-json": "npm:1.0.2"
+ "@walletconnect/time": "npm:1.0.2"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/window-getters": "npm:1.0.1"
+ "@walletconnect/window-metadata": "npm:1.0.1"
+ detect-browser: "npm:5.3.0"
+ elliptic: "npm:^6.5.7"
+ query-string: "npm:7.1.3"
+ uint8arrays: "npm:3.1.0"
+ checksum: d1da74b2cd7af35f16d735fe408cfc820c611b2709bd00899e4e91b0b0a6dcd8f344f97df34d0ef8cabc121619a40b62118ffa2aa233ddba9863d1ba23480a0c
+ languageName: node
+ linkType: hard
+
"@walletconnect/window-getters@npm:1.0.1, @walletconnect/window-getters@npm:^1.0.1":
version: 1.0.1
resolution: "@walletconnect/window-getters@npm:1.0.1"
@@ -9375,6 +9562,21 @@ __metadata:
languageName: node
linkType: hard
+"abitype@npm:1.0.6":
+ version: 1.0.6
+ resolution: "abitype@npm:1.0.6"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ zod: ^3 >=3.22.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ zod:
+ optional: true
+ checksum: 30ca97010bbf34b9aaed401858eeb6bc30419f7ff11eb34adcb243522dd56c9d8a9d3d406aa5d4f60a7c263902f5136043005698e3f073ea882a4922d43a2929
+ languageName: node
+ linkType: hard
+
"abort-controller@npm:^3.0.0":
version: 3.0.0
resolution: "abort-controller@npm:3.0.0"
@@ -9710,8 +9912,8 @@ __metadata:
tsconfig: "npm:*"
turbo: "npm:2.1.1"
typescript: "npm:5.2.2"
- viem: "npm:2.21.6"
- wagmi: "npm:2.12.11"
+ viem: "npm:2.21.37"
+ wagmi: "npm:2.12.25"
languageName: unknown
linkType: soft
@@ -12085,14 +12287,15 @@ __metadata:
languageName: node
linkType: hard
-"eciesjs@npm:^0.3.15":
- version: 0.3.18
- resolution: "eciesjs@npm:0.3.18"
+"eciesjs@npm:^0.4.8":
+ version: 0.4.10
+ resolution: "eciesjs@npm:0.4.10"
dependencies:
- "@types/secp256k1": "npm:^4.0.4"
- futoin-hkdf: "npm:^1.5.3"
- secp256k1: "npm:^5.0.0"
- checksum: 88e334b1fb8ae685eadf8023bc4a5c5247c1f7e6b873b8ba8ec84a3e7890352160ca7fcc1b78f75e67e04f2142310e89788a013fbb4f272f2130e76ada5050bc
+ "@ecies/ciphers": "npm:^0.2.0"
+ "@noble/ciphers": "npm:^1.0.0"
+ "@noble/curves": "npm:^1.6.0"
+ "@noble/hashes": "npm:^1.5.0"
+ checksum: f9e0603a839b763c1bb0a00a64686d553f2d8c10efcfab57461d9e052ebacc80dca0e28cbad8548015a99bee90c60cb085486be4c44261283535873d97aba59e
languageName: node
linkType: hard
@@ -12153,21 +12356,6 @@ __metadata:
languageName: node
linkType: hard
-"elliptic@npm:^6.5.4":
- version: 6.5.5
- resolution: "elliptic@npm:6.5.5"
- dependencies:
- bn.js: "npm:^4.11.9"
- brorand: "npm:^1.1.0"
- hash.js: "npm:^1.0.0"
- hmac-drbg: "npm:^1.0.1"
- inherits: "npm:^2.0.4"
- minimalistic-assert: "npm:^1.0.1"
- minimalistic-crypto-utils: "npm:^1.0.1"
- checksum: 3e591e93783a1b66f234ebf5bd3a8a9a8e063a75073a35a671e03e3b25253b6e33ac121f7efe9b8808890fffb17b40596cc19d01e6e8d1fa13b9a56ff65597c8
- languageName: node
- linkType: hard
-
"elliptic@npm:^6.5.7":
version: 6.5.7
resolution: "elliptic@npm:6.5.7"
@@ -14076,13 +14264,6 @@ __metadata:
languageName: node
linkType: hard
-"futoin-hkdf@npm:^1.5.3":
- version: 1.5.3
- resolution: "futoin-hkdf@npm:1.5.3"
- checksum: fe87b50d2ac125ca2074e92588ca1df5016e9657267363cb77d8287080639dc31f90e7740f4737aa054c3e687b2ab3456f9b5c55950b94cd2c2010bc441aa5ae
- languageName: node
- linkType: hard
-
"gensync@npm:^1.0.0-beta.2":
version: 1.0.0-beta.2
resolution: "gensync@npm:1.0.0-beta.2"
@@ -15542,6 +15723,15 @@ __metadata:
languageName: node
linkType: hard
+"isows@npm:1.0.6":
+ version: 1.0.6
+ resolution: "isows@npm:1.0.6"
+ peerDependencies:
+ ws: "*"
+ checksum: f89338f63ce2f497d6cd0f86e42c634209328ebb43b3bdfdc85d8f1589ee75f02b7e6d9e1ba274101d0f6f513b1b8cbe6985e6542b4aaa1f0c5fd50d9c1be95c
+ languageName: node
+ linkType: hard
+
"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0":
version: 3.2.0
resolution: "istanbul-lib-coverage@npm:3.2.0"
@@ -18006,15 +18196,6 @@ __metadata:
languageName: node
linkType: hard
-"node-addon-api@npm:^5.0.0":
- version: 5.1.0
- resolution: "node-addon-api@npm:5.1.0"
- dependencies:
- node-gyp: "npm:latest"
- checksum: 0eb269786124ba6fad9df8007a149e03c199b3e5a3038125dfb3e747c2d5113d406a4e33f4de1ea600aa2339be1f137d55eba1a73ee34e5fff06c52a5c296d1d
- languageName: node
- linkType: hard
-
"node-addon-api@npm:^7.0.0":
version: 7.0.0
resolution: "node-addon-api@npm:7.0.0"
@@ -18427,7 +18608,7 @@ __metadata:
languageName: node
linkType: hard
-"open@npm:^8.0.4, open@npm:^8.3.0, open@npm:^8.4.0":
+"open@npm:^8.0.4, open@npm:^8.3.0":
version: 8.4.2
resolution: "open@npm:8.4.2"
dependencies:
@@ -20493,25 +20674,6 @@ __metadata:
languageName: node
linkType: hard
-"rollup-plugin-visualizer@npm:^5.9.2":
- version: 5.12.0
- resolution: "rollup-plugin-visualizer@npm:5.12.0"
- dependencies:
- open: "npm:^8.4.0"
- picomatch: "npm:^2.3.1"
- source-map: "npm:^0.7.4"
- yargs: "npm:^17.5.1"
- peerDependencies:
- rollup: 2.x || 3.x || 4.x
- peerDependenciesMeta:
- rollup:
- optional: true
- bin:
- rollup-plugin-visualizer: dist/bin/cli.js
- checksum: 0e44a641223377ebb472bb10f2b22efa773b5f6fbe8d54f197f07c68d7a432cbf00abad79a0aa1570f70c673c792f24700d926d663ed9a4d0ad8406ae5a0f4e4
- languageName: node
- linkType: hard
-
"run-applescript@npm:^5.0.0":
version: 5.0.0
resolution: "run-applescript@npm:5.0.0"
@@ -20652,18 +20814,6 @@ __metadata:
languageName: node
linkType: hard
-"secp256k1@npm:^5.0.0":
- version: 5.0.0
- resolution: "secp256k1@npm:5.0.0"
- dependencies:
- elliptic: "npm:^6.5.4"
- node-addon-api: "npm:^5.0.0"
- node-gyp: "npm:latest"
- node-gyp-build: "npm:^4.2.0"
- checksum: b9ab4c952babfe6103978b2f656265041ebe09b8a91b26a796cbcbe04d2252e28e12ec50d5ed3006bf2ca5feef6edcbd71c7c85122615f5ffbcd1acdd564f77f
- languageName: node
- linkType: hard
-
"selfsigned@npm:^2.4.1":
version: 2.4.1
resolution: "selfsigned@npm:2.4.1"
@@ -21064,7 +21214,7 @@ __metadata:
languageName: node
linkType: hard
-"source-map@npm:^0.7.3, source-map@npm:^0.7.4":
+"source-map@npm:^0.7.3":
version: 0.7.4
resolution: "source-map@npm:0.7.4"
checksum: dc0cf3768fe23c345ea8760487f8c97ef6fca8a73c83cd7c9bf2fde8bc2c34adb9c0824d6feb14bc4f9e37fb522e18af621543f1289038a66ac7586da29aa7dc
@@ -22794,25 +22944,25 @@ __metadata:
languageName: node
linkType: hard
-"viem@npm:2.21.6":
- version: 2.21.6
- resolution: "viem@npm:2.21.6"
+"viem@npm:2.21.37":
+ version: 2.21.37
+ resolution: "viem@npm:2.21.37"
dependencies:
- "@adraffy/ens-normalize": "npm:1.10.0"
- "@noble/curves": "npm:1.4.0"
- "@noble/hashes": "npm:1.4.0"
- "@scure/bip32": "npm:1.4.0"
+ "@adraffy/ens-normalize": "npm:1.11.0"
+ "@noble/curves": "npm:1.6.0"
+ "@noble/hashes": "npm:1.5.0"
+ "@scure/bip32": "npm:1.5.0"
"@scure/bip39": "npm:1.4.0"
- abitype: "npm:1.0.5"
- isows: "npm:1.0.4"
- webauthn-p256: "npm:0.0.5"
- ws: "npm:8.17.1"
+ abitype: "npm:1.0.6"
+ isows: "npm:1.0.6"
+ webauthn-p256: "npm:0.0.10"
+ ws: "npm:8.18.0"
peerDependencies:
typescript: ">=5.0.4"
peerDependenciesMeta:
typescript:
optional: true
- checksum: 6d039e0855567fb3793aee929ecb527e04ee000504aa73967bf4bd51d90c4a2dbc88f826790a06af7011432fde97ae7a22f9e24459dde462dc0d38c5157d2dc2
+ checksum: 573bacabc42f9e6b7050ce7fe62c2a41fe878bb9659888904d9f1acbc91a051fa4a4528eafd5c04242ddba99919cd2f5fab8987f299aa2936145254fb5caa951
languageName: node
linkType: hard
@@ -22845,12 +22995,12 @@ __metadata:
languageName: node
linkType: hard
-"wagmi@npm:2.12.11":
- version: 2.12.11
- resolution: "wagmi@npm:2.12.11"
+"wagmi@npm:2.12.25":
+ version: 2.12.25
+ resolution: "wagmi@npm:2.12.25"
dependencies:
- "@wagmi/connectors": "npm:5.1.10"
- "@wagmi/core": "npm:2.13.5"
+ "@wagmi/connectors": "npm:5.3.3"
+ "@wagmi/core": "npm:2.14.1"
use-sync-external-store: "npm:1.2.0"
peerDependencies:
"@tanstack/react-query": ">=5.0.0"
@@ -22860,7 +23010,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: bdf424fc1521b41bc19c933d1221133f377ed2f853d85d1da33d43cd737180bf3734ba8482ea475055a480d7a4fc32626ec29097aad07249b114662827c64ca8
+ checksum: 18510c1a7528c28b013130ec84fefc5792ee3d4105d60b0b598075b5b6620d51ad0e890e936c6e549e44de4eb6a36e975d14745551dcff3d1d8a963e4d29b8df
languageName: node
linkType: hard
@@ -22899,6 +23049,16 @@ __metadata:
languageName: node
linkType: hard
+"webauthn-p256@npm:0.0.10":
+ version: 0.0.10
+ resolution: "webauthn-p256@npm:0.0.10"
+ dependencies:
+ "@noble/curves": "npm:^1.4.0"
+ "@noble/hashes": "npm:^1.4.0"
+ checksum: 27d836d81a1fec24a31d2d9b652f8ff6876b51940d1003bbd14dc5cfa57c58d84223b5a4eece229516522fd997bc0bc7be618ac42b129fb5fa42fa530060b16d
+ languageName: node
+ linkType: hard
+
"webauthn-p256@npm:0.0.5":
version: 0.0.5
resolution: "webauthn-p256@npm:0.0.5"
@@ -23232,6 +23392,21 @@ __metadata:
languageName: node
linkType: hard
+"ws@npm:8.18.0":
+ version: 8.18.0
+ resolution: "ws@npm:8.18.0"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ">=5.0.2"
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 25eb33aff17edcb90721ed6b0eb250976328533ad3cd1a28a274bd263682e7296a6591ff1436d6cbc50fa67463158b062f9d1122013b361cec99a05f84680e06
+ languageName: node
+ linkType: hard
+
"ws@npm:8.5.0":
version: 8.5.0
resolution: "ws@npm:8.5.0"
@@ -23484,15 +23659,14 @@ __metadata:
languageName: node
linkType: hard
-"zustand@npm:4.4.1":
- version: 4.4.1
- resolution: "zustand@npm:4.4.1"
- dependencies:
- use-sync-external-store: "npm:1.2.0"
+"zustand@npm:5.0.0":
+ version: 5.0.0
+ resolution: "zustand@npm:5.0.0"
peerDependencies:
- "@types/react": ">=16.8"
- immer: ">=9.0"
- react: ">=16.8"
+ "@types/react": ">=18.0.0"
+ immer: ">=9.0.6"
+ react: ">=18.0.0"
+ use-sync-external-store: ">=1.2.0"
peerDependenciesMeta:
"@types/react":
optional: true
@@ -23500,6 +23674,8 @@ __metadata:
optional: true
react:
optional: true
- checksum: c119273886e5cdbd7a9f80c9e0fee8a2c736bb6428e283b25c6dfd428789a95e10b6ed6b18553c955ce0d5dd62e2f4a84af3e2a41f31fdb34fd25462d2b19a8c
+ use-sync-external-store:
+ optional: true
+ checksum: 7546df78aa512f1d2271e238c44699c0ac4bc57f12ae46fcfe8ba1e8a97686fc690596e654101acfabcd706099aa5d3519fc3f22d32b3082baa60699bb333e9a
languageName: node
linkType: hard
From 37983e71f78f85bcbd6b3c1708ddb359b920319b Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 5 Nov 2024 14:56:00 -0300
Subject: [PATCH 093/114] chore: bump walletconnect deps to 2.17.2 in ethers
packages (#267)
* chore: bump walletconnect deps to 2.17.2 in ethers packages
* chore: added changeset file
---
.changeset/red-ladybugs-matter.md | 18 +++
package.json | 2 +-
packages/ethers/package.json | 2 +-
packages/ethers5/package.json | 2 +-
yarn.lock | 232 +++++++++++++++---------------
5 files changed, 134 insertions(+), 122 deletions(-)
create mode 100644 .changeset/red-ladybugs-matter.md
diff --git a/.changeset/red-ladybugs-matter.md b/.changeset/red-ladybugs-matter.md
new file mode 100644
index 000000000..7c994a734
--- /dev/null
+++ b/.changeset/red-ladybugs-matter.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+chore: bump walletconnect deps to 2.17.2 in ethers packages
diff --git a/package.json b/package.json
index a837e27cc..57bc2f9c4 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
"@types/jest": "29.5.7",
"@types/qrcode": "1.5.5",
"@types/react": "^18.2.6",
- "@walletconnect/react-native-compat": "2.16.1",
+ "@walletconnect/react-native-compat": "2.17.2",
"babel-jest": "^29.7.0",
"eslint": "^8.46.0",
"eslint-plugin-ft-flow": "2.0.3",
diff --git a/packages/ethers/package.json b/packages/ethers/package.json
index af6fdbddf..9047e6046 100644
--- a/packages/ethers/package.json
+++ b/packages/ethers/package.json
@@ -42,7 +42,7 @@
"@reown/appkit-scaffold-react-native": "1.0.2",
"@reown/appkit-scaffold-utils-react-native": "1.0.2",
"@reown/appkit-siwe-react-native": "1.0.2",
- "@walletconnect/ethereum-provider": "2.16.1"
+ "@walletconnect/ethereum-provider": "2.17.2"
},
"peerDependencies": {
"@react-native-async-storage/async-storage": ">=1.17.0",
diff --git a/packages/ethers5/package.json b/packages/ethers5/package.json
index aeec760fc..790554726 100644
--- a/packages/ethers5/package.json
+++ b/packages/ethers5/package.json
@@ -42,7 +42,7 @@
"@reown/appkit-scaffold-react-native": "1.0.2",
"@reown/appkit-scaffold-utils-react-native": "1.0.2",
"@reown/appkit-siwe-react-native": "1.0.2",
- "@walletconnect/ethereum-provider": "2.16.1"
+ "@walletconnect/ethereum-provider": "2.17.2"
},
"peerDependencies": {
"@react-native-async-storage/async-storage": ">=1.17.0",
diff --git a/yarn.lock b/yarn.lock
index 4f8e5d222..b395190d6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6814,7 +6814,7 @@ __metadata:
"@reown/appkit-scaffold-react-native": "npm:1.0.2"
"@reown/appkit-scaffold-utils-react-native": "npm:1.0.2"
"@reown/appkit-siwe-react-native": "npm:1.0.2"
- "@walletconnect/ethereum-provider": "npm:2.16.1"
+ "@walletconnect/ethereum-provider": "npm:2.17.2"
ethers: "npm:6.10.0"
peerDependencies:
"@react-native-async-storage/async-storage": ">=1.17.0"
@@ -6835,7 +6835,7 @@ __metadata:
"@reown/appkit-scaffold-react-native": "npm:1.0.2"
"@reown/appkit-scaffold-utils-react-native": "npm:1.0.2"
"@reown/appkit-siwe-react-native": "npm:1.0.2"
- "@walletconnect/ethereum-provider": "npm:2.16.1"
+ "@walletconnect/ethereum-provider": "npm:2.17.2"
ethers: "npm:5.7.2"
peerDependencies:
"@react-native-async-storage/async-storage": ">=1.17.0"
@@ -8850,9 +8850,9 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/core@npm:2.16.1":
- version: 2.16.1
- resolution: "@walletconnect/core@npm:2.16.1"
+"@walletconnect/core@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/core@npm:2.17.0"
dependencies:
"@walletconnect/heartbeat": "npm:1.2.2"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
@@ -8865,18 +8865,18 @@ __metadata:
"@walletconnect/relay-auth": "npm:1.0.4"
"@walletconnect/safe-json": "npm:1.0.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.16.1"
- "@walletconnect/utils": "npm:2.16.1"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
events: "npm:3.3.0"
lodash.isequal: "npm:4.5.0"
uint8arrays: "npm:3.1.0"
- checksum: fadb2db6afe8b3da79b3c84be4e885227efdb38ec5857c66211e5a4ca2cf7b7a0204a3e336b51586bc0ebc816a03da4b4f135269877dcd1119c36385776c1db4
+ checksum: 34ae5b9b68c08c1dd3ebb2a6ebff8697307e76fbfe4d6b51d5d090da5cd1613e1c66fa5ac3a87c914333458d7b5bf075bb664292f6b2c7d438c72f706d87416d
languageName: node
linkType: hard
-"@walletconnect/core@npm:2.17.0":
- version: 2.17.0
- resolution: "@walletconnect/core@npm:2.17.0"
+"@walletconnect/core@npm:2.17.2":
+ version: 2.17.2
+ resolution: "@walletconnect/core@npm:2.17.2"
dependencies:
"@walletconnect/heartbeat": "npm:1.2.2"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
@@ -8889,12 +8889,13 @@ __metadata:
"@walletconnect/relay-auth": "npm:1.0.4"
"@walletconnect/safe-json": "npm:1.0.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.17.0"
- "@walletconnect/utils": "npm:2.17.0"
+ "@walletconnect/types": "npm:2.17.2"
+ "@walletconnect/utils": "npm:2.17.2"
+ "@walletconnect/window-getters": "npm:1.0.1"
events: "npm:3.3.0"
lodash.isequal: "npm:4.5.0"
uint8arrays: "npm:3.1.0"
- checksum: 34ae5b9b68c08c1dd3ebb2a6ebff8697307e76fbfe4d6b51d5d090da5cd1613e1c66fa5ac3a87c914333458d7b5bf075bb664292f6b2c7d438c72f706d87416d
+ checksum: 6124b81892a4e5e9350cfff22a7ce3a23a66c9589221411bd8bfd411fc392b6b343fae1634b32000d4275ba11b1a0f732cf6b7ba5da35b388854c7e7b4f2764d
languageName: node
linkType: hard
@@ -8907,39 +8908,40 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/ethereum-provider@npm:2.16.1":
- version: 2.16.1
- resolution: "@walletconnect/ethereum-provider@npm:2.16.1"
+"@walletconnect/ethereum-provider@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/ethereum-provider@npm:2.17.0"
dependencies:
"@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
"@walletconnect/jsonrpc-types": "npm:1.0.4"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
- "@walletconnect/modal": "npm:2.6.2"
- "@walletconnect/sign-client": "npm:2.16.1"
- "@walletconnect/types": "npm:2.16.1"
- "@walletconnect/universal-provider": "npm:2.16.1"
- "@walletconnect/utils": "npm:2.16.1"
+ "@walletconnect/modal": "npm:2.7.0"
+ "@walletconnect/sign-client": "npm:2.17.0"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/universal-provider": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
events: "npm:3.3.0"
- checksum: 985432b2f5c3da7648640e498d92ae2da05f0a18d43055d7a930c71185d9865fc38bd0a6c4fcb6e06007a8e61084f4e682f9054abee495713e7fe425cf02463e
+ checksum: b046a9c296e95b22841f0b2efd28a4ce1a38529a9ba412d3c8ffc482879d79c3d2a24b8c0ec712baecf781938b4321ab5c1ecad5573d078add7c47b0cfd08a25
languageName: node
linkType: hard
-"@walletconnect/ethereum-provider@npm:2.17.0":
- version: 2.17.0
- resolution: "@walletconnect/ethereum-provider@npm:2.17.0"
+"@walletconnect/ethereum-provider@npm:2.17.2":
+ version: 2.17.2
+ resolution: "@walletconnect/ethereum-provider@npm:2.17.2"
dependencies:
"@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
"@walletconnect/jsonrpc-types": "npm:1.0.4"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/modal": "npm:2.7.0"
- "@walletconnect/sign-client": "npm:2.17.0"
- "@walletconnect/types": "npm:2.17.0"
- "@walletconnect/universal-provider": "npm:2.17.0"
- "@walletconnect/utils": "npm:2.17.0"
+ "@walletconnect/sign-client": "npm:2.17.2"
+ "@walletconnect/types": "npm:2.17.2"
+ "@walletconnect/universal-provider": "npm:2.17.2"
+ "@walletconnect/utils": "npm:2.17.2"
events: "npm:3.3.0"
- checksum: b046a9c296e95b22841f0b2efd28a4ce1a38529a9ba412d3c8ffc482879d79c3d2a24b8c0ec712baecf781938b4321ab5c1ecad5573d078add7c47b0cfd08a25
+ checksum: 191eb6106119a57c1e4c82212cf6650f9e9e32b26a39c5aba0745125067e9153f30ddc43254bafd95ed5f1debd5a5d08094dd5a037ff4a61e645c652ae3d022c
languageName: node
linkType: hard
@@ -9056,15 +9058,6 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/modal-core@npm:2.6.2":
- version: 2.6.2
- resolution: "@walletconnect/modal-core@npm:2.6.2"
- dependencies:
- valtio: "npm:1.11.2"
- checksum: 5e3fb21a1fc923ec0d2a3e33cc360e3d56278a211609d5fd4cc4d6e3b4f1acb40b9783fcc771b259b78c7e731af3862def096aa1da2e210e7859729808304c94
- languageName: node
- linkType: hard
-
"@walletconnect/modal-core@npm:2.7.0":
version: 2.7.0
resolution: "@walletconnect/modal-core@npm:2.7.0"
@@ -9074,18 +9067,6 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/modal-ui@npm:2.6.2":
- version: 2.6.2
- resolution: "@walletconnect/modal-ui@npm:2.6.2"
- dependencies:
- "@walletconnect/modal-core": "npm:2.6.2"
- lit: "npm:2.8.0"
- motion: "npm:10.16.2"
- qrcode: "npm:1.5.3"
- checksum: 5d8f0a2703b9757dfa48ad3e48a40e64608f6a28db31ec93a2f10e942dcc5ee986c03ffdab94018e905836d339131fc928bc14614a94943011868cdddc36a32a
- languageName: node
- linkType: hard
-
"@walletconnect/modal-ui@npm:2.7.0":
version: 2.7.0
resolution: "@walletconnect/modal-ui@npm:2.7.0"
@@ -9098,16 +9079,6 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/modal@npm:2.6.2":
- version: 2.6.2
- resolution: "@walletconnect/modal@npm:2.6.2"
- dependencies:
- "@walletconnect/modal-core": "npm:2.6.2"
- "@walletconnect/modal-ui": "npm:2.6.2"
- checksum: 1cc309f63d061e49fdf7b10d28093d7ef1a47f4624f717f8fd3bf6097ac3b00cea4acc45c50e8bd386d4bcfdf10f4dcba960f7129c557b9dc42ef7d05b970807
- languageName: node
- linkType: hard
-
"@walletconnect/modal@npm:2.7.0":
version: 2.7.0
resolution: "@walletconnect/modal@npm:2.7.0"
@@ -9118,9 +9089,9 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/react-native-compat@npm:2.16.1":
- version: 2.16.1
- resolution: "@walletconnect/react-native-compat@npm:2.16.1"
+"@walletconnect/react-native-compat@npm:2.17.1":
+ version: 2.17.1
+ resolution: "@walletconnect/react-native-compat@npm:2.17.1"
dependencies:
events: "npm:3.3.0"
fast-text-encoding: "npm:1.0.6"
@@ -9129,17 +9100,18 @@ __metadata:
"@react-native-async-storage/async-storage": "*"
"@react-native-community/netinfo": "*"
expo-application: "*"
+ react-native: "*"
react-native-get-random-values: "*"
peerDependenciesMeta:
expo-application:
optional: true
- checksum: d73dd15cb83b35ac46420b184906c0ae42216fe69b8b90d631bdc8479952703dabee7f498cbf089ad23826b3f93370b8ebbc6c7c911cdcba7cf80f41f8614370
+ checksum: 55afa3b7de9cf71f208a10d30ac70bbef67d32013807ebfc2f99ab61cc7e27a51def1e4e795e88e9164452c0ab1d219820cf5b8e0e5e4c316a7501a508476bba
languageName: node
linkType: hard
-"@walletconnect/react-native-compat@npm:2.17.1":
- version: 2.17.1
- resolution: "@walletconnect/react-native-compat@npm:2.17.1"
+"@walletconnect/react-native-compat@npm:2.17.2":
+ version: 2.17.2
+ resolution: "@walletconnect/react-native-compat@npm:2.17.2"
dependencies:
events: "npm:3.3.0"
fast-text-encoding: "npm:1.0.6"
@@ -9153,7 +9125,7 @@ __metadata:
peerDependenciesMeta:
expo-application:
optional: true
- checksum: 55afa3b7de9cf71f208a10d30ac70bbef67d32013807ebfc2f99ab61cc7e27a51def1e4e795e88e9164452c0ab1d219820cf5b8e0e5e4c316a7501a508476bba
+ checksum: ec6e15d6966f22268a8c8f94e19d1259dfed25097632d5ff1cf8134aaf0f87c0f6a8528b3b2d39754c7d6d9d5d402ece91a7e63c8c5302be29fbf724f0cd4b25
languageName: node
linkType: hard
@@ -9189,37 +9161,37 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/sign-client@npm:2.16.1":
- version: 2.16.1
- resolution: "@walletconnect/sign-client@npm:2.16.1"
+"@walletconnect/sign-client@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/sign-client@npm:2.17.0"
dependencies:
- "@walletconnect/core": "npm:2.16.1"
+ "@walletconnect/core": "npm:2.17.0"
"@walletconnect/events": "npm:1.0.1"
"@walletconnect/heartbeat": "npm:1.2.2"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
"@walletconnect/logger": "npm:2.1.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.16.1"
- "@walletconnect/utils": "npm:2.16.1"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
events: "npm:3.3.0"
- checksum: 88727aca13a4e4b5420bde6cb15567a5d07587e8f814025e8c11f69edf941112acf78b21487a8a1380afb42351f8057cb2fc9e92c625f5adee3d085d3efeb072
+ checksum: 48f7d13b3db49584a40dc2653f49fabadd100a324e2213476b8d9e4d6fe0808a08ae14103d2e5b609abff3115197003d8570d606275dbd0f6774d0d49da10c61
languageName: node
linkType: hard
-"@walletconnect/sign-client@npm:2.17.0":
- version: 2.17.0
- resolution: "@walletconnect/sign-client@npm:2.17.0"
+"@walletconnect/sign-client@npm:2.17.2":
+ version: 2.17.2
+ resolution: "@walletconnect/sign-client@npm:2.17.2"
dependencies:
- "@walletconnect/core": "npm:2.17.0"
+ "@walletconnect/core": "npm:2.17.2"
"@walletconnect/events": "npm:1.0.1"
"@walletconnect/heartbeat": "npm:1.2.2"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
"@walletconnect/logger": "npm:2.1.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.17.0"
- "@walletconnect/utils": "npm:2.17.0"
+ "@walletconnect/types": "npm:2.17.2"
+ "@walletconnect/utils": "npm:2.17.2"
events: "npm:3.3.0"
- checksum: 48f7d13b3db49584a40dc2653f49fabadd100a324e2213476b8d9e4d6fe0808a08ae14103d2e5b609abff3115197003d8570d606275dbd0f6774d0d49da10c61
+ checksum: 0acbda4ea34be209b1436134804e72641ca377e2bb6823b7d94177b30e50b8e6de28dfdad6ff64dac61a1305e7b6f281df2357488382c88e440a79b817d377a8
languageName: node
linkType: hard
@@ -9232,9 +9204,9 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/types@npm:2.16.1":
- version: 2.16.1
- resolution: "@walletconnect/types@npm:2.16.1"
+"@walletconnect/types@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/types@npm:2.17.0"
dependencies:
"@walletconnect/events": "npm:1.0.1"
"@walletconnect/heartbeat": "npm:1.2.2"
@@ -9242,13 +9214,13 @@ __metadata:
"@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/logger": "npm:2.1.2"
events: "npm:3.3.0"
- checksum: d796b934fe30771a281dd716c4a0a36992a96b201cebd1012ad2278f7aff224503af6bb18e39461498927d47368c0b7a8d0457bbb42b4fe9712f3307b5c131f7
+ checksum: bdc0c062da1edb4410882d9cfca1bb30eb0afd7caea90d5e7a66eaf15e28380e9ef97635cd5e5a017947f4c814c1f780622b4d8946b11a335d415ae066ec7ade
languageName: node
linkType: hard
-"@walletconnect/types@npm:2.17.0":
- version: 2.17.0
- resolution: "@walletconnect/types@npm:2.17.0"
+"@walletconnect/types@npm:2.17.2":
+ version: 2.17.2
+ resolution: "@walletconnect/types@npm:2.17.2"
dependencies:
"@walletconnect/events": "npm:1.0.1"
"@walletconnect/heartbeat": "npm:1.2.2"
@@ -9256,47 +9228,50 @@ __metadata:
"@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/logger": "npm:2.1.2"
events: "npm:3.3.0"
- checksum: bdc0c062da1edb4410882d9cfca1bb30eb0afd7caea90d5e7a66eaf15e28380e9ef97635cd5e5a017947f4c814c1f780622b4d8946b11a335d415ae066ec7ade
+ checksum: 95bd3e4f4f2ef181ea69691800a0a06be2c4fa900ae972539851c5817a0f01b4ba9f381161d044df4db004f431bc416548ec6eca0ac523fc1fb06014386accac
languageName: node
linkType: hard
-"@walletconnect/universal-provider@npm:2.16.1":
- version: 2.16.1
- resolution: "@walletconnect/universal-provider@npm:2.16.1"
+"@walletconnect/universal-provider@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/universal-provider@npm:2.17.0"
dependencies:
"@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
"@walletconnect/jsonrpc-types": "npm:1.0.4"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
"@walletconnect/logger": "npm:2.1.2"
- "@walletconnect/sign-client": "npm:2.16.1"
- "@walletconnect/types": "npm:2.16.1"
- "@walletconnect/utils": "npm:2.16.1"
+ "@walletconnect/sign-client": "npm:2.17.0"
+ "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/utils": "npm:2.17.0"
events: "npm:3.3.0"
- checksum: cc128497dbf8555f65d383bd1c1962ee4d84a8bdb21680820766a96157799cf498d56836fb620d5c02f9ad7691c21d6173603795df5f7e2a558be47fab4133c1
+ checksum: 7c1afc79054db5add4e937d7adaadb4fc26aecffb5d749d388418fa5d4eb153807ab4de301b642cd80669b4e5c6bcae917f18cf5ce8696d87da8b3705b60d1ec
languageName: node
linkType: hard
-"@walletconnect/universal-provider@npm:2.17.0":
- version: 2.17.0
- resolution: "@walletconnect/universal-provider@npm:2.17.0"
+"@walletconnect/universal-provider@npm:2.17.2":
+ version: 2.17.2
+ resolution: "@walletconnect/universal-provider@npm:2.17.2"
dependencies:
+ "@walletconnect/events": "npm:1.0.1"
"@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
"@walletconnect/jsonrpc-types": "npm:1.0.4"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/logger": "npm:2.1.2"
- "@walletconnect/sign-client": "npm:2.17.0"
- "@walletconnect/types": "npm:2.17.0"
- "@walletconnect/utils": "npm:2.17.0"
+ "@walletconnect/sign-client": "npm:2.17.2"
+ "@walletconnect/types": "npm:2.17.2"
+ "@walletconnect/utils": "npm:2.17.2"
events: "npm:3.3.0"
- checksum: 7c1afc79054db5add4e937d7adaadb4fc26aecffb5d749d388418fa5d4eb153807ab4de301b642cd80669b4e5c6bcae917f18cf5ce8696d87da8b3705b60d1ec
+ lodash: "npm:4.17.21"
+ checksum: afc617916ce2a8e8b669f2d5813795fe0d2cc4400dc0b3275e0b814e5c960b6bc2a1de27fa22021a5fc124aa58ec5ec6a02403fd49ddc4945e1ea941fba3c4da
languageName: node
linkType: hard
-"@walletconnect/utils@npm:2.16.1":
- version: 2.16.1
- resolution: "@walletconnect/utils@npm:2.16.1"
+"@walletconnect/utils@npm:2.17.0":
+ version: 2.17.0
+ resolution: "@walletconnect/utils@npm:2.17.0"
dependencies:
"@stablelib/chacha20poly1305": "npm:1.0.1"
"@stablelib/hkdf": "npm:1.0.1"
@@ -9307,38 +9282,42 @@ __metadata:
"@walletconnect/relay-auth": "npm:1.0.4"
"@walletconnect/safe-json": "npm:1.0.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.16.1"
+ "@walletconnect/types": "npm:2.17.0"
"@walletconnect/window-getters": "npm:1.0.1"
"@walletconnect/window-metadata": "npm:1.0.1"
detect-browser: "npm:5.3.0"
elliptic: "npm:^6.5.7"
query-string: "npm:7.1.3"
uint8arrays: "npm:3.1.0"
- checksum: 0bfbc9d5f8be999f4c3d315a5d64c59ad6fcaaa14898bcdfea3bae4cf7a79da40f26cba27ea25fea6320b608064ee42059d10ac70c87086be876f08d7ad73205
+ checksum: d1da74b2cd7af35f16d735fe408cfc820c611b2709bd00899e4e91b0b0a6dcd8f344f97df34d0ef8cabc121619a40b62118ffa2aa233ddba9863d1ba23480a0c
languageName: node
linkType: hard
-"@walletconnect/utils@npm:2.17.0":
- version: 2.17.0
- resolution: "@walletconnect/utils@npm:2.17.0"
+"@walletconnect/utils@npm:2.17.2":
+ version: 2.17.2
+ resolution: "@walletconnect/utils@npm:2.17.2"
dependencies:
+ "@ethersproject/hash": "npm:5.7.0"
+ "@ethersproject/transactions": "npm:5.7.0"
"@stablelib/chacha20poly1305": "npm:1.0.1"
"@stablelib/hkdf": "npm:1.0.1"
"@stablelib/random": "npm:1.0.2"
"@stablelib/sha256": "npm:1.0.1"
"@stablelib/x25519": "npm:1.0.3"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/relay-api": "npm:1.0.11"
"@walletconnect/relay-auth": "npm:1.0.4"
"@walletconnect/safe-json": "npm:1.0.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.17.0"
+ "@walletconnect/types": "npm:2.17.2"
"@walletconnect/window-getters": "npm:1.0.1"
"@walletconnect/window-metadata": "npm:1.0.1"
detect-browser: "npm:5.3.0"
- elliptic: "npm:^6.5.7"
+ elliptic: "npm:6.6.0"
query-string: "npm:7.1.3"
uint8arrays: "npm:3.1.0"
- checksum: d1da74b2cd7af35f16d735fe408cfc820c611b2709bd00899e4e91b0b0a6dcd8f344f97df34d0ef8cabc121619a40b62118ffa2aa233ddba9863d1ba23480a0c
+ checksum: b44c0025be12301a28715a204c037328eae4fa432f0ee1730da08b3b6583e07aeaf59efd9dcc52209f6a61b50b31c84e555028b97067dfdf9f5efe1211378fc8
languageName: node
linkType: hard
@@ -9892,7 +9871,7 @@ __metadata:
"@types/jest": "npm:29.5.7"
"@types/qrcode": "npm:1.5.5"
"@types/react": "npm:^18.2.6"
- "@walletconnect/react-native-compat": "npm:2.16.1"
+ "@walletconnect/react-native-compat": "npm:2.17.2"
babel-jest: "npm:^29.7.0"
eslint: "npm:^8.46.0"
eslint-plugin-ft-flow: "npm:2.0.3"
@@ -12356,6 +12335,21 @@ __metadata:
languageName: node
linkType: hard
+"elliptic@npm:6.6.0":
+ version: 6.6.0
+ resolution: "elliptic@npm:6.6.0"
+ dependencies:
+ bn.js: "npm:^4.11.9"
+ brorand: "npm:^1.1.0"
+ hash.js: "npm:^1.0.0"
+ hmac-drbg: "npm:^1.0.1"
+ inherits: "npm:^2.0.4"
+ minimalistic-assert: "npm:^1.0.1"
+ minimalistic-crypto-utils: "npm:^1.0.1"
+ checksum: 42eb3492e218017bf8923a5d14a86f414952f2f771361805b3ae9f380923b5da53e203d0d92be95cb0a248858a78db7db5934a346e268abb757e6fe561d401c9
+ languageName: node
+ linkType: hard
+
"elliptic@npm:^6.5.7":
version: 6.5.7
resolution: "elliptic@npm:6.5.7"
@@ -16914,7 +16908,7 @@ __metadata:
languageName: node
linkType: hard
-"lodash@npm:^4.17.13, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4":
+"lodash@npm:4.17.21, lodash@npm:^4.17.13, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c
From f7bad91e91ff90025f8cb3ec3675294e7af44221 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 5 Nov 2024 14:56:19 -0300
Subject: [PATCH 094/114] chore(deps): bump @babel/traverse from 7.22.10 to
7.25.6 (#249)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.10 to 7.25.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.6/packages/babel-traverse)
---
updated-dependencies:
- dependency-name: "@babel/traverse"
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
yarn.lock | 95 ++-----------------------------------------------------
1 file changed, 2 insertions(+), 93 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index b395190d6..e223f6c01 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -387,7 +387,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/generator@npm:^7.24.8, @babel/generator@npm:^7.24.9":
+"@babel/generator@npm:^7.24.9":
version: 7.24.10
resolution: "@babel/generator@npm:7.24.10"
dependencies:
@@ -636,16 +636,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-function-name@npm:^7.23.0":
- version: 7.23.0
- resolution: "@babel/helper-function-name@npm:7.23.0"
- dependencies:
- "@babel/template": "npm:^7.22.15"
- "@babel/types": "npm:^7.23.0"
- checksum: d771dd1f3222b120518176733c52b7cadac1c256ff49b1889dbbe5e3fed81db855b8cc4e40d949c9d3eae0e795e8229c1c8c24c0e83f27cfa6ee3766696c6428
- languageName: node
- linkType: hard
-
"@babel/helper-function-name@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-function-name@npm:7.24.7"
@@ -665,15 +655,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-hoist-variables@npm:^7.24.7":
- version: 7.24.7
- resolution: "@babel/helper-hoist-variables@npm:7.24.7"
- dependencies:
- "@babel/types": "npm:^7.24.7"
- checksum: 19ee37563bbd1219f9d98991ad0e9abef77803ee5945fd85aa7aa62a67c69efca9a801696a1b58dda27f211e878b3327789e6fd2a6f6c725ccefe36774b5ce95
- languageName: node
- linkType: hard
-
"@babel/helper-member-expression-to-functions@npm:^7.22.15":
version: 7.23.0
resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0"
@@ -3153,7 +3134,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.25.2":
+"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.20.0, @babel/traverse@npm:^7.22.10, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.6, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.7.4":
version: 7.25.6
resolution: "@babel/traverse@npm:7.25.6"
dependencies:
@@ -3168,78 +3149,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/traverse@npm:^7.20.0, @babel/traverse@npm:^7.22.10, @babel/traverse@npm:^7.7.4":
- version: 7.22.10
- resolution: "@babel/traverse@npm:7.22.10"
- dependencies:
- "@babel/code-frame": "npm:^7.22.10"
- "@babel/generator": "npm:^7.22.10"
- "@babel/helper-environment-visitor": "npm:^7.22.5"
- "@babel/helper-function-name": "npm:^7.22.5"
- "@babel/helper-hoist-variables": "npm:^7.22.5"
- "@babel/helper-split-export-declaration": "npm:^7.22.6"
- "@babel/parser": "npm:^7.22.10"
- "@babel/types": "npm:^7.22.10"
- debug: "npm:^4.1.0"
- globals: "npm:^11.1.0"
- checksum: 8e8b63b053962908408ed9d954810e93f241122222db115327ed5876d020f420fc115ef2d79623c2a4928447ddc002ec220be2a152b241d19de2480c88e10cfb
- languageName: node
- linkType: hard
-
-"@babel/traverse@npm:^7.23.2":
- version: 7.23.2
- resolution: "@babel/traverse@npm:7.23.2"
- dependencies:
- "@babel/code-frame": "npm:^7.22.13"
- "@babel/generator": "npm:^7.23.0"
- "@babel/helper-environment-visitor": "npm:^7.22.20"
- "@babel/helper-function-name": "npm:^7.23.0"
- "@babel/helper-hoist-variables": "npm:^7.22.5"
- "@babel/helper-split-export-declaration": "npm:^7.22.6"
- "@babel/parser": "npm:^7.23.0"
- "@babel/types": "npm:^7.23.0"
- debug: "npm:^4.1.0"
- globals: "npm:^11.1.0"
- checksum: d096c7c4bab9262a2f658298a3c630ae4a15a10755bb257ae91d5ab3e3b2877438934859c8d34018b7727379fe6b26c4fa2efc81cf4c462a7fe00caf79fa02ff
- languageName: node
- linkType: hard
-
-"@babel/traverse@npm:^7.23.6":
- version: 7.23.6
- resolution: "@babel/traverse@npm:7.23.6"
- dependencies:
- "@babel/code-frame": "npm:^7.23.5"
- "@babel/generator": "npm:^7.23.6"
- "@babel/helper-environment-visitor": "npm:^7.22.20"
- "@babel/helper-function-name": "npm:^7.23.0"
- "@babel/helper-hoist-variables": "npm:^7.22.5"
- "@babel/helper-split-export-declaration": "npm:^7.22.6"
- "@babel/parser": "npm:^7.23.6"
- "@babel/types": "npm:^7.23.6"
- debug: "npm:^4.3.1"
- globals: "npm:^11.1.0"
- checksum: 5b4ebb94a00a7e1daf111e4b0b45a7998d5b7598637a14e75e855e88cc1b702789e09a958726b5d599a003be1e9032dbdfde4b88ea6061332228738950d5582d
- languageName: node
- linkType: hard
-
-"@babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8":
- version: 7.24.8
- resolution: "@babel/traverse@npm:7.24.8"
- dependencies:
- "@babel/code-frame": "npm:^7.24.7"
- "@babel/generator": "npm:^7.24.8"
- "@babel/helper-environment-visitor": "npm:^7.24.7"
- "@babel/helper-function-name": "npm:^7.24.7"
- "@babel/helper-hoist-variables": "npm:^7.24.7"
- "@babel/helper-split-export-declaration": "npm:^7.24.7"
- "@babel/parser": "npm:^7.24.8"
- "@babel/types": "npm:^7.24.8"
- debug: "npm:^4.3.1"
- globals: "npm:^11.1.0"
- checksum: 67a5cc35824455cdb54fb9e196a44b3186283e29018a9c2331f51763921e18e891b3c60c283615a27540ec8eb4c8b89f41c237b91f732a7aa518b2eb7a0d434d
- languageName: node
- linkType: hard
-
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4":
version: 7.22.10
resolution: "@babel/types@npm:7.22.10"
From 0d2bae4a91063fc9fc6feb10e9fe780924cb670f Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 6 Nov 2024 11:21:52 -0300
Subject: [PATCH 095/114] chore: remove nft tab (#268)
---
.changeset/grumpy-poems-tease.md | 18 ++++++++++++++++++
.../src/partials/w3m-account-nfts/index.tsx | 11 -----------
.../w3m-account-wallet-features/index.tsx | 6 ++----
3 files changed, 20 insertions(+), 15 deletions(-)
create mode 100644 .changeset/grumpy-poems-tease.md
delete mode 100644 packages/scaffold/src/partials/w3m-account-nfts/index.tsx
diff --git a/.changeset/grumpy-poems-tease.md b/.changeset/grumpy-poems-tease.md
new file mode 100644
index 000000000..0ce6e3641
--- /dev/null
+++ b/.changeset/grumpy-poems-tease.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+chore: removed nft tab
diff --git a/packages/scaffold/src/partials/w3m-account-nfts/index.tsx b/packages/scaffold/src/partials/w3m-account-nfts/index.tsx
deleted file mode 100644
index 59643cabc..000000000
--- a/packages/scaffold/src/partials/w3m-account-nfts/index.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { AccountPlaceholder } from '../w3m-account-placeholder';
-
-export function AccountNfts() {
- return (
-
- );
-}
diff --git a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
index b0a084d19..462058ae7 100644
--- a/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-wallet-features/index.tsx
@@ -9,7 +9,6 @@ import {
RouterController
} from '@reown/appkit-core-react-native';
import type { Balance as BalanceType } from '@reown/appkit-common-react-native';
-import { AccountNfts } from '../w3m-account-nfts';
import { AccountActivity } from '../w3m-account-activity';
import { AccountTokens } from '../w3m-account-tokens';
import styles from './styles';
@@ -87,12 +86,11 @@ export function AccountWalletFeatures() {
/>
-
+
{activeTab === 0 && }
- {activeTab === 1 && }
- {activeTab === 2 && }
+ {activeTab === 1 && }
);
From f5ca7548115d25e121931961295d822ecd13833c Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 6 Nov 2024 14:57:11 -0300
Subject: [PATCH 096/114] fix: show wallet view for email wallets (#269)
---
.changeset/witty-taxis-smell.md | 18 ++++++++++++++++++
.../src/controllers/ConnectionController.ts | 1 +
.../w3m-connecting-external-view/index.tsx | 4 +---
.../views/w3m-connecting-social-view/index.tsx | 1 -
4 files changed, 20 insertions(+), 4 deletions(-)
create mode 100644 .changeset/witty-taxis-smell.md
diff --git a/.changeset/witty-taxis-smell.md b/.changeset/witty-taxis-smell.md
new file mode 100644
index 000000000..d825b7102
--- /dev/null
+++ b/.changeset/witty-taxis-smell.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: show wallet view for email wallets
diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts
index 0e3057903..4e0087901 100644
--- a/packages/core/src/controllers/ConnectionController.ts
+++ b/packages/core/src/controllers/ConnectionController.ts
@@ -91,6 +91,7 @@ export const ConnectionController = {
async connectExternal(options: ConnectExternalOptions) {
await this._getClient().connectExternal?.(options);
+ ConnectorController.setConnectedConnector(options.type);
},
async signMessage(message: string) {
diff --git a/packages/scaffold/src/views/w3m-connecting-external-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-external-view/index.tsx
index 8d6f8678b..e5df102ea 100644
--- a/packages/scaffold/src/views/w3m-connecting-external-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-external-view/index.tsx
@@ -8,8 +8,7 @@ import {
ModalController,
EventsController,
StorageUtil,
- type WcWallet,
- ConnectorController
+ type WcWallet
} from '@reown/appkit-core-react-native';
import {
Button,
@@ -55,7 +54,6 @@ export function ConnectingExternalView() {
try {
if (connector) {
await ConnectionController.connectExternal(connector);
- ConnectorController.setConnectedConnector(connector.type);
storeConnectedWallet(data?.wallet);
ModalController.close();
EventsController.sendEvent({
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
index a644dd464..50a8af39d 100644
--- a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
@@ -54,7 +54,6 @@ export function ConnectingSocialView() {
const parsedUrl = new URL(url);
await provider?.connectSocial(parsedUrl.search);
await ConnectionController.connectExternal(authConnector);
- ConnectorController.setConnectedConnector('AUTH');
ConnectionController.setConnectedSocialProvider(socialProvider);
WebviewController.setConnecting(false);
From f2a139a264b2604c3cb91c73d044d695dfec5392 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 12 Nov 2024 11:54:22 -0300
Subject: [PATCH 097/114] fix/smart accounts (#270)
---
.../core/src/controllers/NetworkController.ts | 7 ++++++
.../core/src/controllers/WebviewController.ts | 17 +++++++++++++-
packages/ethers/src/client.ts | 1 +
packages/ethers5/src/client.ts | 1 +
.../src/partials/w3m-input-address/index.tsx | 1 -
.../src/views/w3m-account-view/index.tsx | 20 ++++++----------
.../w3m-connecting-social-view/index.tsx | 23 +++++++++++++------
.../index.tsx | 3 +--
.../views/w3m-wallet-receive-view/index.tsx | 18 ++++++++-------
.../src/views/w3m-wallet-send-view/index.tsx | 5 ++--
packages/ui/src/components/wui-card/index.tsx | 2 +-
.../src/composites/wui-account-pill/index.tsx | 18 ++-------------
.../src/composites/wui-account-pill/styles.ts | 3 ++-
packages/wagmi/src/client.ts | 16 +++++++------
packages/wallet/src/AppKitFrameConstants.ts | 8 +++++--
packages/wallet/src/AppKitWebview.tsx | 6 ++++-
16 files changed, 87 insertions(+), 62 deletions(-)
diff --git a/packages/core/src/controllers/NetworkController.ts b/packages/core/src/controllers/NetworkController.ts
index b45c01088..8d62235f3 100644
--- a/packages/core/src/controllers/NetworkController.ts
+++ b/packages/core/src/controllers/NetworkController.ts
@@ -88,6 +88,13 @@ export const NetworkController = {
.filter(Boolean) as CaipNetwork[];
},
+ getSmartAccountEnabledNetworks() {
+ return this.getApprovedCaipNetworks().filter(
+ network =>
+ state.smartAccountEnabledNetworks?.find(networkId => network.id === `eip155:${networkId}`)
+ );
+ },
+
async switchActiveNetwork(network: NetworkControllerState['caipNetwork']) {
await this._getClient().switchCaipNetwork(network);
state.caipNetwork = network;
diff --git a/packages/core/src/controllers/WebviewController.ts b/packages/core/src/controllers/WebviewController.ts
index f11cf7f66..3cec52ba7 100644
--- a/packages/core/src/controllers/WebviewController.ts
+++ b/packages/core/src/controllers/WebviewController.ts
@@ -8,6 +8,7 @@ export interface WebviewControllerState {
webviewUrl?: string;
connecting?: boolean;
connectingProvider?: SocialProvider;
+ processingAuth?: boolean;
}
// -- State --------------------------------------------- //
@@ -15,7 +16,8 @@ const state = proxy({
frameViewVisible: false,
webviewVisible: false,
connecting: false,
- connectingProvider: undefined
+ connectingProvider: undefined,
+ processingAuth: false
});
// -- Controller ---------------------------------------- //
@@ -44,5 +46,18 @@ export const WebviewController = {
setConnectingProvider(provider: WebviewControllerState['connectingProvider']) {
state.connectingProvider = provider;
+ },
+
+ setProcessingAuth(processingAuth: WebviewControllerState['processingAuth']) {
+ state.processingAuth = processingAuth;
+ },
+
+ reset() {
+ state.frameViewVisible = false;
+ state.webviewVisible = false;
+ state.connecting = false;
+ state.connectingProvider = undefined;
+ state.processingAuth = false;
+ state.webviewUrl = undefined;
}
};
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 3147c523c..499cfc2aa 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -946,6 +946,7 @@ export class AppKit extends AppKitScaffold {
const connectedConnector = await StorageUtil.getItem('@w3m/connected_connector');
if (connectedConnector === 'AUTH') {
+ // Set loader until it reconnects
this.setLoading(true);
}
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index f700f5f8a..56b233e77 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -923,6 +923,7 @@ export class AppKit extends AppKitScaffold {
const connectedConnector = await StorageUtil.getItem('@w3m/connected_connector');
if (connectedConnector === 'AUTH') {
+ // Set loader until it reconnects
this.setLoading(true);
}
diff --git a/packages/scaffold/src/partials/w3m-input-address/index.tsx b/packages/scaffold/src/partials/w3m-input-address/index.tsx
index 40e67a8a2..a7b01ab1b 100644
--- a/packages/scaffold/src/partials/w3m-input-address/index.tsx
+++ b/packages/scaffold/src/partials/w3m-input-address/index.tsx
@@ -64,7 +64,6 @@ export function InputAddress({ value }: InputAddressProps) {
selectionColor={Theme['accent-100']}
underlineColorAndroid="transparent"
selectTextOnFocus={false}
- multiline
returnKeyLabel="Done"
/>
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index 1ccc45444..661e0f5d2 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -16,15 +16,13 @@ import {
AssetUtil,
ModalController,
NetworkController,
- OptionsController,
RouterController,
- SendController,
- SnackController
+ SendController
} from '@reown/appkit-core-react-native';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
-import styles from './styles';
import { AccountWalletFeatures } from '../../partials/w3m-account-wallet-features';
+import styles from './styles';
export function AccountView() {
const Theme = useTheme();
@@ -36,13 +34,6 @@ export function AccountView() {
const showActivate =
preferredAccountType === 'eoa' && NetworkController.checkIfSmartAccountEnabled();
- const onCopyAddress = (value: string) => {
- if (OptionsController.isClipboardAvailable() && value) {
- OptionsController.copyToClipboard(value);
- SnackController.showSuccess('Address copied');
- }
- };
-
const onProfilePress = () => {
RouterController.push('AccountDefault');
};
@@ -82,13 +73,16 @@ export function AccountView() {
{showActivate && (
-
+
)}
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
index 50a8af39d..d5eb617df 100644
--- a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
@@ -1,5 +1,6 @@
import { useSnapshot } from 'valtio';
import { useCallback, useEffect, useState } from 'react';
+import { Platform } from 'react-native';
import {
ConnectionController,
ConnectorController,
@@ -19,7 +20,7 @@ import styles from './styles';
export function ConnectingSocialView() {
const { data } = RouterController.state;
const { maxWidth: width } = useCustomDimensions();
- const { connecting } = useSnapshot(WebviewController.state);
+ const { processingAuth } = useSnapshot(WebviewController.state);
const authConnector = ConnectorController.getAuthConnector();
const [error, setError] = useState(false);
const socialProvider = data?.socialProvider;
@@ -32,7 +33,10 @@ export function ConnectingSocialView() {
provider: socialProvider
});
WebviewController.setWebviewUrl(uri);
- WebviewController.setWebviewVisible(true);
+
+ const isNativeApple = socialProvider === 'apple' && Platform.OS === 'ios';
+
+ WebviewController.setWebviewVisible(!isNativeApple);
WebviewController.setConnecting(true);
WebviewController.setConnectingProvider(socialProvider);
}
@@ -49,7 +53,13 @@ export function ConnectingSocialView() {
const socialMessageHandler = useCallback(
async (url: string) => {
try {
- if (url.includes('/sdk/oauth') && socialProvider && authConnector) {
+ if (
+ url.includes('/sdk/oauth') &&
+ socialProvider &&
+ authConnector &&
+ !WebviewController.state.processingAuth
+ ) {
+ WebviewController.setProcessingAuth(true);
WebviewController.setWebviewVisible(false);
const parsedUrl = new URL(url);
await provider?.connectSocial(parsedUrl.search);
@@ -64,6 +74,7 @@ export function ConnectingSocialView() {
});
ModalController.close();
+ WebviewController.reset();
}
} catch (e) {
EventsController.sendEvent({
@@ -71,9 +82,7 @@ export function ConnectingSocialView() {
event: 'SOCIAL_LOGIN_ERROR',
properties: { provider: socialProvider! }
});
- WebviewController.setWebviewVisible(false);
- WebviewController.setConnecting(false);
- WebviewController.setConnectingProvider(undefined);
+ WebviewController.reset();
RouterController.goBack();
SnackController.showError('Something went wrong');
}
@@ -120,7 +129,7 @@ export function ConnectingSocialView() {
{`Continue with ${StringUtil.capitalize(socialProvider)}`}
- {connecting ? 'Retrieving user data' : 'Connect in the provider window'}
+ {processingAuth ? 'Retrieving user data' : 'Connect in the provider window'}
);
diff --git a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
index 2e8c061b6..3695bc470 100644
--- a/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-compatible-networks-view/index.tsx
@@ -13,11 +13,10 @@ import styles from './styles';
export function WalletCompatibleNetworks() {
const { padding } = useCustomDimensions();
const { preferredAccountType } = useSnapshot(AccountController.state);
- const { caipNetwork } = useSnapshot(NetworkController.state);
const isSmartAccount =
preferredAccountType === 'smartAccount' && NetworkController.checkIfSmartAccountEnabled();
const approvedNetworks = isSmartAccount
- ? [caipNetwork]
+ ? NetworkController.getSmartAccountEnabledNetworks()
: NetworkController.getApprovedCaipNetworks();
const imageHeaders = ApiController._getApiHeaders();
diff --git a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
index 47b613d0b..ae41a5175 100644
--- a/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-receive-view/index.tsx
@@ -26,13 +26,17 @@ export function WalletReceiveView() {
const networkImage = AssetUtil.getNetworkImage(caipNetwork);
const { padding } = useCustomDimensions();
const canCopy = OptionsController.isClipboardAvailable();
- const slicedNetworks =
- NetworkController.getApprovedCaipNetworks()
- .filter(network => network?.imageId)
- ?.slice(0, 5) || [];
- const imagesArray = slicedNetworks.map(AssetUtil.getNetworkImage).filter(Boolean) as string[];
const isSmartAccount =
preferredAccountType === 'smartAccount' && NetworkController.checkIfSmartAccountEnabled();
+ const networks = isSmartAccount
+ ? NetworkController.getSmartAccountEnabledNetworks()
+ : NetworkController.getApprovedCaipNetworks();
+
+ const imagesArray = networks
+ .filter(network => network?.imageId)
+ .slice(0, 5)
+ .map(AssetUtil.getNetworkImage)
+ .filter(Boolean) as string[];
const label = UiUtil.getTruncateString({
string: profileName ?? address ?? '',
@@ -71,9 +75,7 @@ export function WalletReceiveView() {
diff --git a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
index 8be4dd217..31d3f8509 100644
--- a/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-wallet-send-view/index.tsx
@@ -93,6 +93,7 @@ export function WalletSendView() {
}, [token, tokenBalance, fetchNetworkPrice]);
const actionText = getActionText();
+ const disabled = actionText !== 'Preview send';
return (
{loading ? (
-
+
) : (
-
+
{getActionText()}
)}
diff --git a/packages/ui/src/components/wui-card/index.tsx b/packages/ui/src/components/wui-card/index.tsx
index a354f5dbd..0d0eefb39 100644
--- a/packages/ui/src/components/wui-card/index.tsx
+++ b/packages/ui/src/components/wui-card/index.tsx
@@ -18,7 +18,7 @@ export function Card({ children, style }: CardProps) {
enabled={Platform.OS === 'ios'}
style={[
styles.container,
- { backgroundColor: Theme['bg-100'], borderColor: Theme['gray-glass-005'] },
+ { backgroundColor: Theme['bg-100'], borderColor: Theme['gray-glass-015'] },
style
]}
>
diff --git a/packages/ui/src/composites/wui-account-pill/index.tsx b/packages/ui/src/composites/wui-account-pill/index.tsx
index 3f3bfc163..208b80cc8 100644
--- a/packages/ui/src/composites/wui-account-pill/index.tsx
+++ b/packages/ui/src/composites/wui-account-pill/index.tsx
@@ -1,15 +1,14 @@
import { Animated, Pressable, type StyleProp, type ViewStyle } from 'react-native';
import { Avatar } from '../wui-avatar';
import { UiUtil } from '../../utils/UiUtil';
-import { IconLink } from '../wui-icon-link';
import { Text } from '../../components/wui-text';
import useAnimatedValue from '../../hooks/useAnimatedValue';
import { useTheme } from '../../hooks/useTheme';
import styles from './styles';
+import { Icon } from '../../components/wui-icon';
export interface AccountPillProps {
onPress: () => void;
- onCopy: (address: string) => void;
address?: string;
profileName?: string;
profileImage?: string;
@@ -20,7 +19,6 @@ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
export function AccountPill({
onPress,
- onCopy,
address,
profileName,
profileImage,
@@ -36,12 +34,6 @@ export function AccountPill({
const backgroundColor = animatedValue;
const borderColor = Theme['gray-glass-005'];
- const handleCopyAddress = () => {
- if (address) {
- onCopy(address);
- }
- };
-
return (
-
+
);
}
diff --git a/packages/ui/src/composites/wui-account-pill/styles.ts b/packages/ui/src/composites/wui-account-pill/styles.ts
index 7be825c94..4bb2e5f1d 100644
--- a/packages/ui/src/composites/wui-account-pill/styles.ts
+++ b/packages/ui/src/composites/wui-account-pill/styles.ts
@@ -17,6 +17,7 @@ export default StyleSheet.create({
marginLeft: Spacing['2xs']
},
copyButton: {
- marginHorizontal: Spacing['3xs']
+ marginLeft: Spacing.xs,
+ marginRight: Spacing.s
}
});
diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts
index a44975182..f5cea75d3 100644
--- a/packages/wagmi/src/client.ts
+++ b/packages/wagmi/src/client.ts
@@ -562,15 +562,17 @@ export class AppKit extends AppKitScaffold {
private async addAuthListeners(connector: WagmiConnector) {
const connectedConnector = await StorageUtil.getItem('@w3m/connected_connector');
- if (connector && connectedConnector === 'AUTH') {
+
+ if (connectedConnector === 'AUTH') {
+ // Set loader until it reconnects
super.setLoading(true);
+ }
- const provider = (await connector.getProvider()) as AppKitFrameProvider;
+ const provider = (await connector.getProvider()) as AppKitFrameProvider;
- provider.onSetPreferredAccount(async () => {
- await reconnect(this.wagmiConfig, { connectors: [connector] });
- this.setLoading(false);
- });
- }
+ provider.onSetPreferredAccount(async () => {
+ await reconnect(this.wagmiConfig, { connectors: [connector] });
+ this.setLoading(false);
+ });
}
}
diff --git a/packages/wallet/src/AppKitFrameConstants.ts b/packages/wallet/src/AppKitFrameConstants.ts
index ac1e4844a..98bd1afed 100644
--- a/packages/wallet/src/AppKitFrameConstants.ts
+++ b/packages/wallet/src/AppKitFrameConstants.ts
@@ -18,8 +18,12 @@ export const AppKitFrameConstants = {
FRAME_MESSAGES_HANDLER: `
window.addEventListener('message', ({ data, origin }) => {
- window.ReactNativeWebView.postMessage(JSON.stringify({ ...data, origin }))
- })
+ window.ReactNativeWebView.postMessage(
+ JSON.stringify({ ...data, origin }, (key, value) =>
+ typeof value === 'bigint' ? value.toString() : value
+ )
+ );
+ });
`,
APP_SWITCH_NETWORK: '@w3m-app/SWITCH_NETWORK',
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index d4c98dea5..19b58e885 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -10,6 +10,7 @@ import {
} from '@reown/appkit-core-react-native';
import { useTheme, BorderRadius, IconLink, Spacing } from '@reown/appkit-ui-react-native';
import type { AppKitFrameProvider } from './AppKitFrameProvider';
+import { AppKitFrameConstants } from './AppKitFrameConstants';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
@@ -100,7 +101,10 @@ function _AppKitWebview() {
containerStyle={styles.webview}
ref={webviewRef}
onNavigationStateChange={async navState => {
- if (webviewVisible) {
+ if (
+ !navState.loading &&
+ navState.url.includes(`${AppKitFrameConstants.SECURE_SITE_ORIGIN}/sdk/oauth`)
+ ) {
provider.events.emit('social', navState.url);
}
}}
From 636285bb261815b6766b78728219c7820532e150 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 19 Nov 2024 15:21:14 -0300
Subject: [PATCH 098/114] fix: error handling improvements (#271)
---
.changeset/warm-camels-cheat.md | 18 +++
.changeset/young-ducks-approve.md | 18 +++
apps/native/App.tsx | 3 +-
apps/native/package.json | 4 +-
package.json | 4 +-
packages/common/src/index.ts | 1 +
packages/common/src/utils/ErrorUtil.ts | 35 ++++++
.../controllers/OptionsController.test.ts | 3 +-
.../controllers/SnackController.test.ts | 29 ++++-
.../core/src/controllers/ApiController.ts | 47 +++++---
.../core/src/controllers/OptionsController.ts | 8 +-
.../core/src/controllers/SnackController.ts | 29 ++++-
packages/core/src/utils/TypeUtil.ts | 5 +-
packages/ethers/src/client.ts | 22 +++-
packages/ethers5/src/client.ts | 22 +++-
packages/scaffold/src/client.ts | 36 +++++-
.../partials/w3m-account-activity/index.tsx | 4 +-
.../w3m-account-placeholder/index.tsx | 37 ------
.../partials/w3m-all-wallets-list/index.tsx | 50 +++++++--
.../partials/w3m-all-wallets-list/styles.ts | 7 ++
.../partials/w3m-all-wallets-search/index.tsx | 60 ++++++----
.../partials/w3m-all-wallets-search/styles.ts | 8 +-
.../src/partials/w3m-placeholder/index.tsx | 77 +++++++++++++
.../src/partials/w3m-snackbar/index.tsx | 25 +++--
.../src/views/w3m-all-wallets-view/index.tsx | 2 +-
.../components/all-wallet-list.tsx | 35 +++---
.../src/views/w3m-connect-view/index.tsx | 26 ++++-
.../index.tsx | 4 +-
packages/ui/src/components/wui-icon/index.tsx | 2 +-
.../ui/src/composites/wui-icon-box/index.tsx | 20 +++-
.../composites/wui-list-item-loader/index.tsx | 29 +++++
.../composites/wui-list-item-loader/styles.ts | 12 ++
.../ui/src/composites/wui-qr-code/index.tsx | 6 +-
packages/ui/src/index.ts | 1 +
packages/ui/src/utils/ThemeUtil.ts | 3 +-
packages/wagmi/src/client.ts | 29 ++++-
packages/wallet/src/AppKitAuthWebview.tsx | 13 ++-
packages/wallet/src/AppKitFrameProvider.ts | 42 ++++++-
packages/wallet/src/AppKitWebview.tsx | 6 +-
yarn.lock | 105 +++++++++++-------
40 files changed, 689 insertions(+), 198 deletions(-)
create mode 100644 .changeset/warm-camels-cheat.md
create mode 100644 .changeset/young-ducks-approve.md
create mode 100644 packages/common/src/utils/ErrorUtil.ts
delete mode 100644 packages/scaffold/src/partials/w3m-account-placeholder/index.tsx
create mode 100644 packages/scaffold/src/partials/w3m-placeholder/index.tsx
create mode 100644 packages/ui/src/composites/wui-list-item-loader/index.tsx
create mode 100644 packages/ui/src/composites/wui-list-item-loader/styles.ts
diff --git a/.changeset/warm-camels-cheat.md b/.changeset/warm-camels-cheat.md
new file mode 100644
index 000000000..58b91bbf5
--- /dev/null
+++ b/.changeset/warm-camels-cheat.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: show error message and retry button in case wallet fetch fails
diff --git a/.changeset/young-ducks-approve.md b/.changeset/young-ducks-approve.md
new file mode 100644
index 000000000..63a64ef38
--- /dev/null
+++ b/.changeset/young-ducks-approve.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+feat: improved provider error handling
diff --git a/apps/native/App.tsx b/apps/native/App.tsx
index d8036e3f8..ae99f40cf 100644
--- a/apps/native/App.tsx
+++ b/apps/native/App.tsx
@@ -63,10 +63,11 @@ createAppKit({
customWallets,
enableAnalytics: true,
metadata,
+ debug: true,
features: {
email: true,
socials: ['x', 'farcaster', 'discord', 'apple'],
- emailShowWallets: false
+ emailShowWallets: true
}
});
diff --git a/apps/native/package.json b/apps/native/package.json
index 835192799..acf2071ab 100644
--- a/apps/native/package.json
+++ b/apps/native/package.json
@@ -37,8 +37,8 @@
"react-native-web": "~0.19.10",
"react-native-webview": "13.8.6",
"uuid": "3.4.0",
- "viem": "2.21.37",
- "wagmi": "2.12.25"
+ "viem": "2.21.48",
+ "wagmi": "2.12.33"
},
"devDependencies": {
"@babel/core": "^7.24.0",
diff --git a/package.json b/package.json
index 57bc2f9c4..2a6ee1b41 100644
--- a/package.json
+++ b/package.json
@@ -69,8 +69,8 @@
"tsconfig": "*",
"turbo": "2.1.1",
"typescript": "5.2.2",
- "viem": "2.21.37",
- "wagmi": "2.12.25"
+ "viem": "2.21.48",
+ "wagmi": "2.12.33"
},
"packageManager": "yarn@4.0.2"
}
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 8f77cbeb7..13f28df44 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -5,5 +5,6 @@ export { NamesUtil } from './utils/NamesUtil';
export { NetworkUtil } from './utils/NetworkUtil';
export { NumberUtil } from './utils/NumberUtil';
export { StringUtil } from './utils/StringUtil';
+export { ErrorUtil } from './utils/ErrorUtil';
export { erc20ABI } from './contracts/erc20';
export * from './utils/TypeUtil';
diff --git a/packages/common/src/utils/ErrorUtil.ts b/packages/common/src/utils/ErrorUtil.ts
new file mode 100644
index 000000000..35bf4bc27
--- /dev/null
+++ b/packages/common/src/utils/ErrorUtil.ts
@@ -0,0 +1,35 @@
+export const ErrorUtil = {
+ UniversalProviderErrors: {
+ UNAUTHORIZED_DOMAIN_NOT_ALLOWED: {
+ message: 'Unauthorized: origin not allowed',
+ alertErrorKey: 'INVALID_APP_CONFIGURATION'
+ },
+ PROJECT_ID_NOT_CONFIGURED: {
+ message: 'Project ID is missing',
+ alertErrorKey: 'PROJECT_ID_NOT_CONFIGURED'
+ },
+ JWT_VALIDATION_ERROR: {
+ message: 'JWT validation error: JWT Token is not yet valid',
+ alertErrorKey: 'JWT_TOKEN_NOT_VALID'
+ }
+ },
+ ALERT_ERRORS: {
+ INVALID_APP_CONFIGURATION: {
+ shortMessage: 'Invalid App Configuration',
+ longMessage: `Bundle ID not found on Allowlist - Please verify that your bundle ID is allowed at https://cloud.reown.com`
+ },
+ SOCIALS_TIMEOUT: {
+ shortMessage: 'Invalid App Configuration',
+ longMessage:
+ 'There was an issue loading the embedded wallet. Please verify that your bundle ID is allowed at https://cloud.reown.com'
+ },
+ JWT_TOKEN_NOT_VALID: {
+ shortMessage: 'Session Expired',
+ longMessage: 'Invalid session found - please check your time settings and connect again'
+ },
+ PROJECT_ID_NOT_CONFIGURED: {
+ shortMessage: 'Project ID Not Configured',
+ longMessage: 'Project ID Not Configured - update configuration'
+ }
+ }
+};
diff --git a/packages/core/src/__tests__/controllers/OptionsController.test.ts b/packages/core/src/__tests__/controllers/OptionsController.test.ts
index 712d52c65..e0e536a32 100644
--- a/packages/core/src/__tests__/controllers/OptionsController.test.ts
+++ b/packages/core/src/__tests__/controllers/OptionsController.test.ts
@@ -16,7 +16,8 @@ describe('OptionsController', () => {
projectId: '',
sdkType: 'appkit',
sdkVersion: 'react-native-wagmi-undefined',
- features: ConstantsUtil.DEFAULT_FEATURES
+ features: ConstantsUtil.DEFAULT_FEATURES,
+ debug: false
});
});
diff --git a/packages/core/src/__tests__/controllers/SnackController.test.ts b/packages/core/src/__tests__/controllers/SnackController.test.ts
index 2192c454f..6a9aad79c 100644
--- a/packages/core/src/__tests__/controllers/SnackController.test.ts
+++ b/packages/core/src/__tests__/controllers/SnackController.test.ts
@@ -1,4 +1,7 @@
-import { SnackController } from '../../index';
+import { OptionsController, SnackController } from '../../index';
+
+// Setup
+OptionsController.state.debug = true;
// -- Tests --------------------------------------------------------------------
describe('SnackController', () => {
@@ -6,7 +9,8 @@ describe('SnackController', () => {
expect(SnackController.state).toEqual({
message: '',
variant: 'success',
- open: false
+ open: false,
+ long: false
});
});
@@ -15,16 +19,18 @@ describe('SnackController', () => {
expect(SnackController.state).toEqual({
message: 'Success Msg',
variant: 'success',
- open: true
+ open: true,
+ long: false
});
});
it('should update state correctly on hide()', () => {
SnackController.hide();
expect(SnackController.state).toEqual({
- message: 'Success Msg',
+ message: '',
variant: 'success',
- open: false
+ open: false,
+ long: false
});
});
@@ -33,7 +39,18 @@ describe('SnackController', () => {
expect(SnackController.state).toEqual({
message: 'Error Msg',
variant: 'error',
- open: true
+ open: true,
+ long: false
+ });
+ });
+
+ it('should update state correctly on showInternalError()', () => {
+ SnackController.showInternalError({ shortMessage: 'Error Msg', longMessage: 'Error Msg' });
+ expect(SnackController.state).toEqual({
+ message: 'Error Msg',
+ variant: 'error',
+ open: true,
+ long: true
});
});
});
diff --git a/packages/core/src/controllers/ApiController.ts b/packages/core/src/controllers/ApiController.ts
index dec37f8d3..db9766252 100644
--- a/packages/core/src/controllers/ApiController.ts
+++ b/packages/core/src/controllers/ApiController.ts
@@ -17,6 +17,7 @@ import { OptionsController } from './OptionsController';
import { ConnectorController } from './ConnectorController';
import { ConnectionController } from './ConnectionController';
import { ApiUtil } from '../utils/ApiUtil';
+import { SnackController } from './SnackController';
// -- Helpers ------------------------------------------- //
const baseUrl = CoreHelperUtil.getApiUrl();
@@ -27,6 +28,8 @@ const recommendedEntries = '4';
// -- Types --------------------------------------------- //
export interface ApiControllerState {
prefetchPromise?: Promise;
+ prefetchError?: boolean;
+ prefetchLoading?: boolean;
page: number;
count: number;
featured: WcWallet[];
@@ -326,23 +329,35 @@ export const ApiController = {
},
async prefetch() {
- // this fetch must resolve first so we filter them in the other wallet requests
- await ApiController.fetchInstalledWallets();
-
- const promises = [
- ApiController.fetchFeaturedWallets(),
- ApiController.fetchRecommendedWallets(),
- ApiController.fetchNetworkImages(),
- ApiController.fetchConnectorImages()
- ];
- if (OptionsController.state.enableAnalytics === undefined) {
- promises.push(ApiController.fetchAnalyticsConfig());
- }
+ try {
+ state.prefetchError = false;
+ state.prefetchLoading = true;
+ // this fetch must resolve first so we filter them in the other wallet requests
+ await ApiController.fetchInstalledWallets();
+
+ const promises = [
+ ApiController.fetchFeaturedWallets(),
+ ApiController.fetchRecommendedWallets(),
+ ApiController.fetchNetworkImages(),
+ ApiController.fetchConnectorImages()
+ ];
+ if (OptionsController.state.enableAnalytics === undefined) {
+ promises.push(ApiController.fetchAnalyticsConfig());
+ }
- state.prefetchPromise = Promise.race([
- CoreHelperUtil.allSettled(promises),
- CoreHelperUtil.wait(3000)
- ]);
+ state.prefetchPromise = Promise.race([
+ CoreHelperUtil.allSettled(promises),
+ CoreHelperUtil.wait(3000)
+ ]);
+
+ state.prefetchPromise.then(() => {
+ state.prefetchLoading = false;
+ });
+ } catch (error) {
+ state.prefetchError = true;
+ state.prefetchLoading = false;
+ SnackController.showError('Failed to load wallets');
+ }
},
async fetchAnalyticsConfig() {
diff --git a/packages/core/src/controllers/OptionsController.ts b/packages/core/src/controllers/OptionsController.ts
index 7140589ae..24fde94a9 100644
--- a/packages/core/src/controllers/OptionsController.ts
+++ b/packages/core/src/controllers/OptionsController.ts
@@ -29,6 +29,7 @@ export interface OptionsControllerState {
metadata?: Metadata;
isSiweEnabled?: boolean;
features?: Features;
+ debug?: boolean;
}
// -- State --------------------------------------------- //
@@ -36,7 +37,8 @@ const state = proxy({
projectId: '',
sdkType: 'appkit',
sdkVersion: 'react-native-wagmi-undefined',
- features: ConstantsUtil.DEFAULT_FEATURES
+ features: ConstantsUtil.DEFAULT_FEATURES,
+ debug: false
});
// -- Controller ---------------------------------------- //
@@ -91,6 +93,10 @@ export const OptionsController = {
state.features = { ...ConstantsUtil.DEFAULT_FEATURES, ...features };
},
+ setDebug(debug: OptionsControllerState['debug']) {
+ state.debug = debug;
+ },
+
isClipboardAvailable() {
return !!state._clipboardClient;
},
diff --git a/packages/core/src/controllers/SnackController.ts b/packages/core/src/controllers/SnackController.ts
index 331a5fd4d..8a0d91c98 100644
--- a/packages/core/src/controllers/SnackController.ts
+++ b/packages/core/src/controllers/SnackController.ts
@@ -1,17 +1,25 @@
import { proxy } from 'valtio';
+import { OptionsController } from './OptionsController';
// -- Types --------------------------------------------- //
+interface Message {
+ shortMessage: string;
+ longMessage?: string;
+}
+
export interface SnackControllerState {
message: string;
variant: 'error' | 'success';
open: boolean;
+ long: boolean;
}
// -- State --------------------------------------------- //
const state = proxy({
message: '',
variant: 'success',
- open: false
+ open: false,
+ long: false
});
// -- Controller ---------------------------------------- //
@@ -30,7 +38,26 @@ export const SnackController = {
state.open = true;
},
+ showInternalError(error: Message) {
+ const { debug } = OptionsController.state;
+
+ if (debug) {
+ state.message = error.shortMessage;
+ state.variant = 'error';
+ state.open = true;
+ state.long = true;
+ }
+
+ if (error.longMessage) {
+ // eslint-disable-next-line no-console
+ console.error(error.longMessage);
+ }
+ },
+
hide() {
state.open = false;
+ state.long = false;
+ state.message = '';
+ state.variant = 'success';
}
};
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index 6d7ce82a0..d91b2cc23 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -598,13 +598,14 @@ export interface AppKitFrameProvider {
type: AppKitFrameAccountType;
address: string;
}>;
+ setOnTimeout(callback: () => void): void;
getSmartAccountEnabledNetworks(): Promise<{
smartAccountEnabledNetworks: number[];
}>;
disconnect(): Promise;
request(req: any): Promise;
- AuthView: () => JSX.Element | null;
- Webview: () => JSX.Element | null;
+ AuthView: () => React.JSX.Element | null;
+ Webview: () => React.JSX.Element | null;
onSetPreferredAccount: (
callback: (values: { type: AppKitFrameAccountType; address: string }) => void
) => void;
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 499cfc2aa..0db093654 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -27,7 +27,7 @@ import {
type WriteContractArgs,
type AppKitFrameAccountType
} from '@reown/appkit-scaffold-react-native';
-import { erc20ABI, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
+import { erc20ABI, ErrorUtil, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import {
ConstantsUtil,
PresetsUtil,
@@ -47,6 +47,7 @@ import {
} from '@reown/appkit-scaffold-utils-react-native';
import EthereumProvider, { OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
import type { EthereumProviderOptions } from '@walletconnect/ethereum-provider';
+import { type JsonRpcError } from '@walletconnect/jsonrpc-types';
import { getAuthCaipNetworks, getWalletConnectCaipNetworks } from './utils/helpers';
import type { AppKitSIWEClient } from '@reown/appkit-siwe-react-native';
@@ -108,7 +109,7 @@ export class AppKit extends AppKitScaffold {
}
if (!appKitOptions.projectId) {
- throw new Error('appkit:constructor - projectId is undefined');
+ throw new Error(ErrorUtil.ALERT_ERRORS.PROJECT_ID_NOT_CONFIGURED.shortMessage);
}
const networkControllerClient: NetworkControllerClient = {
@@ -506,6 +507,7 @@ export class AppKit extends AppKitScaffold {
};
this.walletConnectProvider = await EthereumProvider.init(walletConnectProviderOptions);
+ this.addWalletConnectListeners(this.walletConnectProvider);
await this.checkActiveWalletConnectProvider();
}
@@ -965,5 +967,21 @@ export class AppKit extends AppKitScaffold {
}
this.setLoading(false);
});
+
+ authProvider.setOnTimeout(async () => {
+ this.handleAlertError(ErrorUtil.ALERT_ERRORS.SOCIALS_TIMEOUT);
+ });
+ }
+
+ private async addWalletConnectListeners(provider: EthereumProvider) {
+ if (provider) {
+ provider.signer.client.core.relayer.on('relayer_connect', () => {
+ provider.signer.client.core.relayer?.provider?.on('payload', (payload: JsonRpcError) => {
+ if (payload?.error) {
+ this.handleAlertError(payload?.error.message);
+ }
+ });
+ });
+ }
}
}
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index 56b233e77..d9ade873d 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -31,9 +31,10 @@ import {
type CombinedProviderType,
type AppKitFrameProvider
} from '@reown/appkit-scaffold-utils-react-native';
-import { erc20ABI, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
+import { erc20ABI, ErrorUtil, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import EthereumProvider, { OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
import type { EthereumProviderOptions } from '@walletconnect/ethereum-provider';
+import { type JsonRpcError } from '@walletconnect/jsonrpc-types';
import { getAuthCaipNetworks, getWalletConnectCaipNetworks } from './utils/helpers';
import type { AppKitSIWEClient } from '@reown/appkit-siwe-react-native';
@@ -95,7 +96,7 @@ export class AppKit extends AppKitScaffold {
}
if (!appKitOptions.projectId) {
- throw new Error('appkit:constructor - projectId is undefined');
+ throw new Error(ErrorUtil.ALERT_ERRORS.PROJECT_ID_NOT_CONFIGURED.shortMessage);
}
const networkControllerClient: NetworkControllerClient = {
@@ -486,6 +487,7 @@ export class AppKit extends AppKitScaffold {
};
this.walletConnectProvider = await EthereumProvider.init(walletConnectProviderOptions);
+ this.addWalletConnectListeners(this.walletConnectProvider);
await this.checkActiveWalletConnectProvider();
}
@@ -942,5 +944,21 @@ export class AppKit extends AppKitScaffold {
}
this.setLoading(false);
});
+
+ authProvider.setOnTimeout(async () => {
+ this.handleAlertError(ErrorUtil.ALERT_ERRORS.SOCIALS_TIMEOUT);
+ });
+ }
+
+ private async addWalletConnectListeners(provider: EthereumProvider) {
+ if (provider) {
+ provider.signer.client.core.relayer.on('relayer_connect', () => {
+ provider.signer.client.core.relayer?.provider?.on('payload', (payload: JsonRpcError) => {
+ if (payload?.error) {
+ this.handleAlertError(payload?.error.message);
+ }
+ });
+ });
+ }
}
}
diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts
index 18b863c2c..0af3bcef9 100644
--- a/packages/scaffold/src/client.ts
+++ b/packages/scaffold/src/client.ts
@@ -28,11 +28,12 @@ import {
NetworkController,
OptionsController,
PublicStateController,
+ SnackController,
StorageUtil,
ThemeController,
TransactionsController
} from '@reown/appkit-core-react-native';
-import { ConstantsUtil } from '@reown/appkit-common-react-native';
+import { ConstantsUtil, ErrorUtil } from '@reown/appkit-common-react-native';
// -- Types ---------------------------------------------------------------------
export interface LibraryOptions {
@@ -49,6 +50,7 @@ export interface LibraryOptions {
enableAnalytics?: OptionsControllerState['enableAnalytics'];
_sdkVersion: OptionsControllerState['sdkVersion'];
metadata?: OptionsControllerState['metadata'];
+ debug?: OptionsControllerState['debug'];
features?: Features;
}
@@ -64,6 +66,8 @@ export interface OpenOptions {
// -- Client --------------------------------------------------------------------
export class AppKitScaffold {
+ public reportedAlertErrors: Record = {};
+
public constructor(options: ScaffoldOptions) {
this.initControllers(options);
}
@@ -233,6 +237,35 @@ export class AppKitScaffold {
AccountController.setPreferredAccountType(preferredAccountType);
};
+ protected handleAlertError(error?: string | { shortMessage: string; longMessage: string }) {
+ if (!error) return;
+
+ if (typeof error === 'object') {
+ SnackController.showInternalError(error);
+
+ return;
+ }
+
+ // Check if the error is a universal provider error
+ const matchedUniversalProviderError = Object.entries(ErrorUtil.UniversalProviderErrors).find(
+ ([, { message }]) => error?.includes(message)
+ );
+
+ const [errorKey, errorValue] = matchedUniversalProviderError ?? [];
+
+ const { message, alertErrorKey } = errorValue ?? {};
+
+ if (errorKey && message && !this.reportedAlertErrors[errorKey]) {
+ const alertError =
+ ErrorUtil.ALERT_ERRORS[alertErrorKey as keyof typeof ErrorUtil.ALERT_ERRORS];
+
+ if (alertError) {
+ SnackController.showInternalError(alertError);
+ this.reportedAlertErrors[errorKey] = true;
+ }
+ }
+ }
+
// -- Private ------------------------------------------------------------------
private async initControllers(options: ScaffoldOptions) {
this.initAsyncValues(options);
@@ -247,6 +280,7 @@ export class AppKitScaffold {
OptionsController.setCustomWallets(options.customWallets);
OptionsController.setEnableAnalytics(options.enableAnalytics);
OptionsController.setSdkVersion(options._sdkVersion);
+ OptionsController.setDebug(options.debug);
if (options.clipboardClient) {
OptionsController.setClipboardClient(options.clipboardClient);
diff --git a/packages/scaffold/src/partials/w3m-account-activity/index.tsx b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
index 567b3acd9..2e784083f 100644
--- a/packages/scaffold/src/partials/w3m-account-activity/index.tsx
+++ b/packages/scaffold/src/partials/w3m-account-activity/index.tsx
@@ -19,7 +19,7 @@ import {
OptionsController,
TransactionsController
} from '@reown/appkit-core-react-native';
-import { AccountPlaceholder } from '../w3m-account-placeholder';
+import { Placeholder } from '../w3m-placeholder';
import { getTransactionListItemProps } from './utils';
import styles from './styles';
@@ -68,7 +68,7 @@ export function AccountActivity({ style }: Props) {
if (!Object.keys(transactionsByYear).length) {
return (
- ;
-}
-
-export function AccountPlaceholder({ icon, title, description, style }: Props) {
- return (
-
-
-
- {title}
-
-
- {description}
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- minHeight: 200
- },
- title: {
- marginTop: Spacing.xl,
- marginBottom: Spacing.xs
- },
- description: {
- maxWidth: '50%'
- }
-});
diff --git a/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx b/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
index bfb615385..fb9c009e0 100644
--- a/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
+++ b/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
@@ -1,7 +1,12 @@
import { useEffect, useState } from 'react';
import { useSnapshot } from 'valtio';
import { FlatList, View } from 'react-native';
-import { ApiController, AssetUtil, type WcWallet } from '@reown/appkit-core-react-native';
+import {
+ ApiController,
+ AssetUtil,
+ SnackController,
+ type WcWallet
+} from '@reown/appkit-core-react-native';
import {
CardSelect,
CardSelectLoader,
@@ -12,6 +17,7 @@ import {
import styles from './styles';
import { UiUtil } from '../../utils/UiUtil';
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
+import { Placeholder } from '../w3m-placeholder';
interface AllWalletsListProps {
columns: number;
@@ -21,6 +27,7 @@ interface AllWalletsListProps {
export function AllWalletsList({ columns, itemWidth, onItemPress }: AllWalletsListProps) {
const [loading, setLoading] = useState(false);
+ const [loadingError, setLoadingError] = useState(false);
const [pageLoading, setPageLoading] = useState(false);
const { maxWidth, padding } = useCustomDimensions();
const { installed, featured, recommended, wallets } = useSnapshot(ApiController.state);
@@ -80,16 +87,28 @@ export function AllWalletsList({ columns, itemWidth, onItemPress }: AllWalletsLi
};
const initialFetch = async () => {
- setLoading(true);
- await ApiController.fetchWallets({ page: 1 });
- UiUtil.createViewTransition();
- setLoading(false);
+ try {
+ setLoading(true);
+ setLoadingError(false);
+ await ApiController.fetchWallets({ page: 1 });
+ UiUtil.createViewTransition();
+ setLoading(false);
+ } catch (error) {
+ SnackController.showError('Failed to load wallets');
+ setLoading(false);
+ setLoadingError(true);
+ }
};
const fetchNextPage = async () => {
- if (walletList.length < ApiController.state.count && !pageLoading) {
- setPageLoading(true);
- await ApiController.fetchWallets({ page: ApiController.state.page + 1 });
+ try {
+ if (walletList.length < ApiController.state.count && !pageLoading) {
+ setPageLoading(true);
+ await ApiController.fetchWallets({ page: ApiController.state.page + 1 });
+ setPageLoading(false);
+ }
+ } catch (error) {
+ SnackController.showError('Failed to load more wallets');
setPageLoading(false);
}
};
@@ -104,6 +123,21 @@ export function AllWalletsList({ columns, itemWidth, onItemPress }: AllWalletsLi
return loadingTemplate(20);
}
+ if (loadingError) {
+ return (
+
+ );
+ }
+
return (
(false);
+ const [loadingError, setLoadingError] = useState(false);
const [prevSearchQuery, setPrevSearchQuery] = useState('');
const imageHeaders = ApiController._getApiHeaders();
const { maxWidth, padding, isLandscape } = useCustomDimensions();
@@ -69,28 +74,25 @@ export function AllWalletsSearch({
const emptyTemplate = () => {
return (
-
-
-
- No wallet found
-
-
+ />
);
};
const searchFetch = useCallback(async () => {
- setLoading(true);
- await ApiController.searchWallet({ search: searchQuery });
- setLoading(false);
+ try {
+ setLoading(true);
+ setLoadingError(false);
+ await ApiController.searchWallet({ search: searchQuery });
+ setLoading(false);
+ } catch (error) {
+ SnackController.showError('Failed to load wallets');
+ setLoading(false);
+ setLoadingError(true);
+ }
}, [searchQuery]);
useEffect(() => {
@@ -104,6 +106,21 @@ export function AllWalletsSearch({
return loadingTemplate(20);
}
+ if (loadingError) {
+ return (
+
+ );
+ }
+
if (ApiController.state.search.length === 0) {
return emptyTemplate();
}
@@ -118,7 +135,6 @@ export function AllWalletsSearch({
renderItem={walletTemplate}
style={styles.container}
contentContainerStyle={[styles.contentContainer, { paddingHorizontal: padding + Spacing.xs }]}
- ListEmptyComponent={emptyTemplate()}
keyExtractor={item => item.id}
getItemLayout={(_, index) => ({
length: ITEM_HEIGHT,
diff --git a/packages/scaffold/src/partials/w3m-all-wallets-search/styles.ts b/packages/scaffold/src/partials/w3m-all-wallets-search/styles.ts
index 95a07ebed..d425dea39 100644
--- a/packages/scaffold/src/partials/w3m-all-wallets-search/styles.ts
+++ b/packages/scaffold/src/partials/w3m-all-wallets-search/styles.ts
@@ -8,9 +8,13 @@ export default StyleSheet.create({
contentContainer: {
paddingBottom: Spacing['2xl']
},
+ placeholderContainer: {
+ flex: 0,
+ height: '90%'
+ },
emptyContainer: {
- height: '100%',
- paddingTop: '50%'
+ flex: 0,
+ height: '90%'
},
emptyLandscape: {
paddingTop: '10%'
diff --git a/packages/scaffold/src/partials/w3m-placeholder/index.tsx b/packages/scaffold/src/partials/w3m-placeholder/index.tsx
new file mode 100644
index 000000000..8fed2e110
--- /dev/null
+++ b/packages/scaffold/src/partials/w3m-placeholder/index.tsx
@@ -0,0 +1,77 @@
+import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
+import {
+ IconBox,
+ Text,
+ FlexView,
+ Spacing,
+ type IconType,
+ Button,
+ type ColorType
+} from '@reown/appkit-ui-react-native';
+
+interface Props {
+ icon?: IconType;
+ iconColor?: ColorType;
+ title?: string;
+ description?: string;
+ style?: StyleProp;
+ actionIcon?: IconType;
+ actionPress?: () => void;
+ actionTitle?: string;
+}
+
+export function Placeholder({
+ icon,
+ iconColor = 'fg-175',
+ title,
+ description,
+ style,
+ actionPress,
+ actionTitle,
+ actionIcon
+}: Props) {
+ return (
+
+ {icon && (
+
+ )}
+ {title && (
+
+ {title}
+
+ )}
+ {description && (
+
+ {description}
+
+ )}
+ {actionPress && (
+
+ {actionTitle ?? ''}
+
+ )}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ minHeight: 200
+ },
+ icon: {
+ marginBottom: Spacing.l
+ },
+ title: {
+ marginBottom: Spacing['2xs']
+ },
+ button: {
+ marginTop: Spacing.m
+ }
+});
diff --git a/packages/scaffold/src/partials/w3m-snackbar/index.tsx b/packages/scaffold/src/partials/w3m-snackbar/index.tsx
index 0ac420edf..7d0802c80 100644
--- a/packages/scaffold/src/partials/w3m-snackbar/index.tsx
+++ b/packages/scaffold/src/partials/w3m-snackbar/index.tsx
@@ -7,7 +7,7 @@ import { Snackbar as SnackbarComponent } from '@reown/appkit-ui-react-native';
import styles from './styles';
export function Snackbar() {
- const { open, message, variant } = useSnapshot(SnackController.state);
+ const { open, message, variant, long } = useSnapshot(SnackController.state);
const componentOpacity = useMemo(() => new Animated.Value(0), []);
useEffect(() => {
@@ -17,17 +17,20 @@ export function Snackbar() {
duration: 150,
useNativeDriver: true
}).start();
- setTimeout(() => {
- Animated.timing(componentOpacity, {
- toValue: 0,
- duration: 300,
- useNativeDriver: true
- }).start(() => {
- SnackController.hide();
- });
- }, 2200);
+ setTimeout(
+ () => {
+ Animated.timing(componentOpacity, {
+ toValue: 0,
+ duration: 300,
+ useNativeDriver: true
+ }).start(() => {
+ SnackController.hide();
+ });
+ },
+ long ? 15000 : 2200
+ );
}
- }, [open, componentOpacity]);
+ }, [open, long, componentOpacity]);
return (
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/all-wallet-list.tsx b/packages/scaffold/src/views/w3m-connect-view/components/all-wallet-list.tsx
index daf346718..581b00b5f 100644
--- a/packages/scaffold/src/views/w3m-connect-view/components/all-wallet-list.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/components/all-wallet-list.tsx
@@ -1,3 +1,4 @@
+import { type StyleProp, type ViewStyle } from 'react-native';
import { useSnapshot } from 'valtio';
import {
ApiController,
@@ -6,8 +7,7 @@ import {
type ConnectionControllerState,
type WcWallet
} from '@reown/appkit-core-react-native';
-import { ListWallet } from '@reown/appkit-ui-react-native';
-import type { StyleProp, ViewStyle } from 'react-native';
+import { ListItemLoader, ListWallet } from '@reown/appkit-ui-react-native';
import { UiUtil } from '../../../utils/UiUtil';
import { filterOutRecentWallets } from '../utils';
@@ -18,7 +18,7 @@ interface Props {
}
export function AllWalletList({ itemStyle, onWalletPress, isWalletConnectEnabled }: Props) {
- const { installed, featured, recommended } = useSnapshot(ApiController.state);
+ const { installed, featured, recommended, prefetchLoading } = useSnapshot(ApiController.state);
const { recentWallets } = useSnapshot(ConnectionController.state) as ConnectionControllerState;
const imageHeaders = ApiController._getApiHeaders();
const RECENT_COUNT = recentWallets?.length && installed.length ? 1 : recentWallets?.length ?? 0;
@@ -33,15 +33,22 @@ export function AllWalletList({ itemStyle, onWalletPress, isWalletConnectEnabled
return null;
}
- return list.map(wallet => (
- onWalletPress(wallet)}
- style={itemStyle}
- installed={!!installed.find(installedWallet => installedWallet.id === wallet.id)}
- />
- ));
+ return prefetchLoading ? (
+ <>
+
+
+ >
+ ) : (
+ list.map(wallet => (
+ onWalletPress(wallet)}
+ style={itemStyle}
+ installed={!!installed.find(installedWallet => installedWallet.id === wallet.id)}
+ />
+ ))
+ );
}
diff --git a/packages/scaffold/src/views/w3m-connect-view/index.tsx b/packages/scaffold/src/views/w3m-connect-view/index.tsx
index 4a52eca79..f1222cc8e 100644
--- a/packages/scaffold/src/views/w3m-connect-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/index.tsx
@@ -1,6 +1,7 @@
import { useSnapshot } from 'valtio';
import { Platform, ScrollView, View } from 'react-native';
import {
+ ApiController,
ConnectorController,
EventUtil,
EventsController,
@@ -12,18 +13,20 @@ import { FlexView, Icon, ListItem, Separator, Spacing, Text } from '@reown/appki
import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import { ConnectEmailInput } from './components/connect-email-input';
import { useKeyboard } from '../../hooks/useKeyboard';
+import { Placeholder } from '../../partials/w3m-placeholder';
import { ConnectorList } from './components/connectors-list';
import { CustomWalletList } from './components/custom-wallet-list';
import { AllWalletsButton } from './components/all-wallets-button';
import { AllWalletList } from './components/all-wallet-list';
import { RecentWalletList } from './components/recent-wallet-list';
import { SocialLoginList } from './components/social-login-list';
-import styles from './styles';
import { WalletGuide } from './components/wallet-guide';
+import styles from './styles';
export function ConnectView() {
const connectors = ConnectorController.state.connectors;
const { authLoading } = useSnapshot(ConnectorController.state);
+ const { prefetchError } = useSnapshot(ApiController.state);
const { features } = useSnapshot(OptionsController.state);
const { padding } = useCustomDimensions();
const { keyboardShown, keyboardHeight } = useKeyboard();
@@ -39,6 +42,8 @@ export function ConnectView() {
isAuthEnabled &&
(isEmailEnabled || isSocialEnabled) &&
(isWalletConnectEnabled || isCoinbaseEnabled);
+ const showLoadingError = !showConnectWalletsButton && prefetchError;
+ const showList = !showConnectWalletsButton && !showLoadingError;
const paddingBottom = Platform.select({
android: keyboardShown ? keyboardHeight + Spacing['2xl'] : Spacing['2xl'],
@@ -78,13 +83,28 @@ export function ConnectView() {
{showSeparator && }
- {showConnectWalletsButton ? (
+ {showConnectWalletsButton && (
Continue with a wallet
- ) : (
+ )}
+ {showLoadingError && (
+
+
+
+
+ )}
+ {showList && (
<>
))
) : (
- JSX.Element> = {
export type IconProps = SvgProps & {
name: IconType;
- size?: Exclude;
+ size?: SizeType;
color?: ColorType;
style?: SvgProps['style'];
};
diff --git a/packages/ui/src/composites/wui-icon-box/index.tsx b/packages/ui/src/composites/wui-icon-box/index.tsx
index 070656fc0..bbfb9e8ac 100644
--- a/packages/ui/src/composites/wui-icon-box/index.tsx
+++ b/packages/ui/src/composites/wui-icon-box/index.tsx
@@ -7,7 +7,7 @@ import styles from './styles';
export interface IconBoxProps {
icon: IconType;
- size?: Exclude;
+ size?: Exclude;
iconColor?: ColorType;
iconSize?: Exclude;
background?: boolean;
@@ -33,6 +33,9 @@ export function IconBox({
const Theme = useTheme();
let _iconSize: SizeType;
switch (size) {
+ case 'xl':
+ _iconSize = 'xl';
+ break;
case 'lg':
_iconSize = 'lg';
break;
@@ -48,6 +51,9 @@ export function IconBox({
let boxSize: number;
switch (size) {
+ case 'xl':
+ boxSize = 56;
+ break;
case 'lg':
boxSize = 40;
break;
@@ -58,7 +64,17 @@ export function IconBox({
boxSize = 24;
}
- const borderRadius = size === 'lg' ? 'xxs' : '3xl';
+ let borderRadius: keyof typeof BorderRadius;
+ switch (size) {
+ case 'xl':
+ borderRadius = 's';
+ break;
+ case 'lg':
+ borderRadius = 'xxs';
+ break;
+ default:
+ borderRadius = '3xl';
+ }
const backgroundStyle = {
backgroundColor:
diff --git a/packages/ui/src/composites/wui-list-item-loader/index.tsx b/packages/ui/src/composites/wui-list-item-loader/index.tsx
new file mode 100644
index 000000000..b3fb786cb
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-item-loader/index.tsx
@@ -0,0 +1,29 @@
+import type { StyleProp, ViewStyle } from 'react-native';
+import { BorderRadius, WalletImageSize } from '../../utils/ThemeUtil';
+import { useTheme } from '../../hooks/useTheme';
+import { Shimmer } from '../../components/wui-shimmer';
+import { FlexView } from '../../layout/wui-flex';
+import styles from './styles';
+
+export interface ListItemLoaderProps {
+ style?: StyleProp;
+}
+
+export function ListItemLoader({ style }: ListItemLoaderProps) {
+ const Theme = useTheme();
+
+ return (
+
+
+
+
+ );
+}
diff --git a/packages/ui/src/composites/wui-list-item-loader/styles.ts b/packages/ui/src/composites/wui-list-item-loader/styles.ts
new file mode 100644
index 000000000..f5a3b9381
--- /dev/null
+++ b/packages/ui/src/composites/wui-list-item-loader/styles.ts
@@ -0,0 +1,12 @@
+import { StyleSheet } from 'react-native';
+import { BorderRadius, Spacing } from '../../utils/ThemeUtil';
+
+export default StyleSheet.create({
+ container: {
+ borderRadius: BorderRadius.xs,
+ padding: Spacing.xs
+ },
+ text: {
+ marginLeft: Spacing.s
+ }
+});
diff --git a/packages/ui/src/composites/wui-qr-code/index.tsx b/packages/ui/src/composites/wui-qr-code/index.tsx
index 8f49da5e2..304ef336d 100644
--- a/packages/ui/src/composites/wui-qr-code/index.tsx
+++ b/packages/ui/src/composites/wui-qr-code/index.tsx
@@ -21,6 +21,8 @@ export interface QrCodeProps {
style?: StyleProp;
}
+const LABEL_HEIGHT = 15;
+
export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }: QrCodeProps) {
const Theme = LightTheme;
const containerPadding = Spacing.l;
@@ -75,7 +77,7 @@ export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }:
{logoTemplate()}
-
+
UX by{' '}
Reown
@@ -83,6 +85,6 @@ export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }:
) : (
-
+
);
}
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index ddea358d4..94c1bf2ab 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -40,6 +40,7 @@ export { InputNumeric, type InputNumericProps } from './composites/wui-input-num
export { InputText, type InputTextProps } from './composites/wui-input-text';
export { Link, type LinkProps } from './composites/wui-link';
export { ListItem, type ListItemProps } from './composites/wui-list-item';
+export { ListItemLoader, type ListItemLoaderProps } from './composites/wui-list-item-loader';
export { ListSocial, type ListSocialProps } from './composites/wui-list-social';
export { ListToken, type ListTokenProps } from './composites/wui-list-token';
export { ListTransaction, type ListTransactionProps } from './composites/wui-list-transaction';
diff --git a/packages/ui/src/utils/ThemeUtil.ts b/packages/ui/src/utils/ThemeUtil.ts
index 9c3fbcd7b..9671a12d8 100644
--- a/packages/ui/src/utils/ThemeUtil.ts
+++ b/packages/ui/src/utils/ThemeUtil.ts
@@ -164,7 +164,8 @@ export const IconSize = {
xs: 12,
sm: 14,
md: 16,
- lg: 20
+ lg: 20,
+ xl: 24
};
export const SpinnerSize = {
diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts
index f5cea75d3..46a75a3d3 100644
--- a/packages/wagmi/src/client.ts
+++ b/packages/wagmi/src/client.ts
@@ -22,7 +22,8 @@ import {
} from '@wagmi/core';
import { normalize } from 'viem/ens';
import { mainnet, type Chain } from '@wagmi/core/chains';
-import { EthereumProvider, OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
+import EthereumProvider, { OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
+import { type JsonRpcError } from '@walletconnect/jsonrpc-types';
import {
type CaipAddress,
type CaipNetwork,
@@ -44,7 +45,7 @@ import {
PresetsUtil,
StorageUtil
} from '@reown/appkit-scaffold-utils-react-native';
-import { NetworkUtil, NamesUtil } from '@reown/appkit-common-react-native';
+import { NetworkUtil, NamesUtil, ErrorUtil } from '@reown/appkit-common-react-native';
import { type AppKitSIWEClient } from '@reown/appkit-siwe-react-native';
import {
getCaipDefaultChain,
@@ -90,7 +91,7 @@ export class AppKit extends AppKitScaffold {
}
if (!appKitOptions.projectId) {
- throw new Error('appkit:constructor - projectId is undefined');
+ throw new Error(ErrorUtil.ALERT_ERRORS.PROJECT_ID_NOT_CONFIGURED.shortMessage);
}
const networkControllerClient: NetworkControllerClient = {
@@ -543,9 +544,27 @@ export class AppKit extends AppKitScaffold {
});
this.setConnectors(_connectors);
+ this.syncWalletConnectListeners(filteredConnectors);
this.syncAuthConnector(filteredConnectors);
}
+ private async syncWalletConnectListeners(
+ connectors: AppKitClientOptions['wagmiConfig']['connectors']
+ ) {
+ const connector = connectors.find(({ id }) => id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID);
+ if (connector) {
+ const provider = (await connector.getProvider()) as EthereumProvider;
+
+ provider.signer.client.core.relayer.on('relayer_connect', () => {
+ provider.signer.client.core.relayer?.provider?.on('payload', (payload: JsonRpcError) => {
+ if (payload?.error) {
+ this.handleAlertError(payload?.error.message);
+ }
+ });
+ });
+ }
+ }
+
private async syncAuthConnector(connectors: AppKitClientOptions['wagmiConfig']['connectors']) {
const authConnector = connectors.find(({ id }) => id === ConstantsUtil.AUTH_CONNECTOR_ID);
if (authConnector) {
@@ -574,5 +593,9 @@ export class AppKit extends AppKitScaffold {
await reconnect(this.wagmiConfig, { connectors: [connector] });
this.setLoading(false);
});
+
+ provider.setOnTimeout(async () => {
+ this.handleAlertError(ErrorUtil.ALERT_ERRORS.SOCIALS_TIMEOUT);
+ });
}
}
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index c77d79d1c..cd477f99c 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { memo, useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { Animated, Appearance, Linking, Platform, SafeAreaView, StyleSheet } from 'react-native';
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
@@ -12,8 +12,10 @@ import {
WebviewController,
AccountController,
NetworkController,
- ConnectionController
+ ConnectionController,
+ SnackController
} from '@reown/appkit-core-react-native';
+import { ErrorUtil } from '@reown/appkit-common-react-native';
import { useTheme, BorderRadius } from '@reown/appkit-ui-react-native';
import type { AppKitFrameProvider } from './AppKitFrameProvider';
import { AppKitFrameConstants } from './AppKitFrameConstants';
@@ -22,7 +24,7 @@ import type { AppKitFrameTypes } from './AppKitFrameTypes';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
-function _AuthWebview() {
+export function AuthWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
const authConnector = ConnectorController.getAuthConnector();
@@ -206,14 +208,15 @@ function _AuthWebview() {
onError={({ nativeEvent }) => {
provider?.onWebviewLoadError(nativeEvent.description);
}}
+ onHttpError={() => {
+ SnackController.showInternalError(ErrorUtil.ALERT_ERRORS.SOCIALS_TIMEOUT);
+ }}
/>
>
) : null;
}
-export const AuthWebview = memo(_AuthWebview);
-
const styles = StyleSheet.create({
backdrop: {
position: 'absolute',
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index 9ae9fb2a8..dea444feb 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -10,6 +10,9 @@ import { AppKitFrameSchema } from './AppKitFrameSchema';
import { AuthWebview } from './AppKitAuthWebview';
import { AppKitWebview } from './AppKitWebview';
+// -- Types -----------------------------------------------------------
+type AppEventType = Omit;
+
// -- Provider --------------------------------------------------------
export class AppKitFrameProvider {
private webviewRef: RefObject | undefined;
@@ -23,12 +26,16 @@ export class AppKitFrameProvider {
private username: string | undefined;
private rpcRequestHandler?: (request: AppKitFrameTypes.RPCRequest) => void;
+
private rpcSuccessHandler?: (
response: AppKitFrameTypes.RPCResponse,
request: AppKitFrameTypes.RPCRequest
) => void;
+
private rpcErrorHandler?: (error: Error, request: AppKitFrameTypes.RPCRequest) => void;
+ private onTimeout?: () => void;
+
public webviewLoadPromise: Promise;
public webviewLoadPromiseResolver:
@@ -76,6 +83,10 @@ export class AppKitFrameProvider {
this.webviewLoadPromiseResolver?.reject(error);
}
+ public setOnTimeout(callback: () => void) {
+ this.onTimeout = callback;
+ }
+
// -- Extended Methods ------------------------------------------------
public getSecureSiteURL() {
return `${AppKitFrameConstants.SECURE_SITE_SDK}?projectId=${this.projectId}`;
@@ -502,10 +513,34 @@ export class AppKitFrameProvider {
}
private async appEvent(
- event: Omit
+ event: AppEventType
): Promise {
await this.webviewLoadPromise;
- const type = event.type.replace('@w3m-app/', '');
+ let timer: NodeJS.Timeout;
+
+ function replaceEventType(type: AppEventType['type']) {
+ return type.replace('@w3m-app/', '');
+ }
+
+ const type = replaceEventType(event.type);
+
+ const shouldCheckForTimeout = [
+ AppKitFrameConstants.APP_IS_CONNECTED,
+ AppKitFrameConstants.APP_GET_USER,
+ AppKitFrameConstants.APP_CONNECT_EMAIL,
+ AppKitFrameConstants.APP_CONNECT_DEVICE,
+ AppKitFrameConstants.APP_CONNECT_OTP,
+ AppKitFrameConstants.APP_CONNECT_SOCIAL,
+ AppKitFrameConstants.APP_GET_SOCIAL_REDIRECT_URI,
+ AppKitFrameConstants.APP_GET_FARCASTER_URI
+ ]
+ .map(replaceEventType)
+ .includes(type);
+
+ if (shouldCheckForTimeout && this.onTimeout) {
+ // 15 seconds timeout
+ timer = setTimeout(this.onTimeout, 15000);
+ }
return new Promise((resolve, reject) => {
const id = Math.random().toString(36).substring(7);
@@ -527,6 +562,9 @@ export class AppKitFrameProvider {
function handler(frameEvent: AppKitFrameTypes.FrameEvent) {
if (frameEvent.type === `@w3m-frame/${type}_SUCCESS`) {
+ if (timer) {
+ clearTimeout(timer);
+ }
if ('payload' in frameEvent) {
resolve(frameEvent.payload);
}
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index 19b58e885..4c00eeb8a 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { memo, useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { Animated, SafeAreaView, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
@@ -14,7 +14,7 @@ import { AppKitFrameConstants } from './AppKitFrameConstants';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
-function _AppKitWebview() {
+export function AppKitWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
const authConnector = ConnectorController.getAuthConnector();
@@ -114,8 +114,6 @@ function _AppKitWebview() {
) : null;
}
-export const AppKitWebview = memo(_AppKitWebview);
-
const styles = StyleSheet.create({
backdrop: {
position: 'absolute',
diff --git a/yarn.lock b/yarn.lock
index e223f6c01..753d7b55b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -38,7 +38,7 @@ __metadata:
languageName: node
linkType: hard
-"@adraffy/ens-normalize@npm:1.11.0":
+"@adraffy/ens-normalize@npm:^1.10.1":
version: 1.11.0
resolution: "@adraffy/ens-normalize@npm:1.11.0"
checksum: 5111d0f1a273468cb5661ed3cf46ee58de8f32f84e2ebc2365652e66c1ead82649df94c736804e2b9cfa831d30ef24e1cc3575d970dbda583416d3a98d8870a6
@@ -121,8 +121,8 @@ __metadata:
react-native-webview: "npm:13.8.6"
typescript: "npm:~5.3.3"
uuid: "npm:3.4.0"
- viem: "npm:2.21.37"
- wagmi: "npm:2.12.25"
+ viem: "npm:2.21.48"
+ wagmi: "npm:2.12.33"
languageName: unknown
linkType: soft
@@ -3529,15 +3529,15 @@ __metadata:
languageName: node
linkType: hard
-"@coinbase/wallet-sdk@npm:4.1.0":
- version: 4.1.0
- resolution: "@coinbase/wallet-sdk@npm:4.1.0"
+"@coinbase/wallet-sdk@npm:4.2.3":
+ version: 4.2.3
+ resolution: "@coinbase/wallet-sdk@npm:4.2.3"
dependencies:
"@noble/hashes": "npm:^1.4.0"
clsx: "npm:^1.2.1"
eventemitter3: "npm:^5.0.1"
- preact: "npm:^10.16.0"
- checksum: 9ccd8171e8874a357f246fc3b8b9641cb015f12e0c8912c15b77c55cdca58c00ba59c68afdc3162d26421fedcaf8164a95ee39abce96e4dcde5b391e0920ca65
+ preact: "npm:^10.24.2"
+ checksum: ce27b5bfdcbc79e896cd262baf0483073ac854986b518e29a23af9c70b3bb6a75d6c15e5e34355095249d46fa8a8eda4682b63ec82812e92cbadba56b8706190
languageName: node
linkType: hard
@@ -6852,13 +6852,13 @@ __metadata:
languageName: node
linkType: hard
-"@safe-global/safe-apps-provider@npm:0.18.3":
- version: 0.18.3
- resolution: "@safe-global/safe-apps-provider@npm:0.18.3"
+"@safe-global/safe-apps-provider@npm:0.18.4":
+ version: 0.18.4
+ resolution: "@safe-global/safe-apps-provider@npm:0.18.4"
dependencies:
"@safe-global/safe-apps-sdk": "npm:^9.1.0"
events: "npm:^3.3.0"
- checksum: 7209d761919969c0859e8b9df90fd46d06c3f99424ecd5fd2e0b8080355a880504ee5c46cebcbaa94739f8be272f3f7102a9f40cf18e6c1a9e1d7dd29d77ee5e
+ checksum: 612c9816b75b86b73b95b5df35529f4d48da1a3a59b2b999f6ef836b28b10cda2142e159dbc97f0298fa8f5b76df82a1e08e34034fdf12f148e9fd4af2f72134
languageName: node
linkType: hard
@@ -6936,7 +6936,7 @@ __metadata:
languageName: node
linkType: hard
-"@scure/bip32@npm:1.5.0":
+"@scure/bip32@npm:1.5.0, @scure/bip32@npm:^1.5.0":
version: 1.5.0
resolution: "@scure/bip32@npm:1.5.0"
dependencies:
@@ -6967,7 +6967,7 @@ __metadata:
languageName: node
linkType: hard
-"@scure/bip39@npm:1.4.0":
+"@scure/bip39@npm:1.4.0, @scure/bip39@npm:^1.4.0":
version: 1.4.0
resolution: "@scure/bip39@npm:1.4.0"
dependencies:
@@ -8718,30 +8718,30 @@ __metadata:
languageName: node
linkType: hard
-"@wagmi/connectors@npm:5.3.3":
- version: 5.3.3
- resolution: "@wagmi/connectors@npm:5.3.3"
+"@wagmi/connectors@npm:5.4.0":
+ version: 5.4.0
+ resolution: "@wagmi/connectors@npm:5.4.0"
dependencies:
- "@coinbase/wallet-sdk": "npm:4.1.0"
+ "@coinbase/wallet-sdk": "npm:4.2.3"
"@metamask/sdk": "npm:0.30.1"
- "@safe-global/safe-apps-provider": "npm:0.18.3"
+ "@safe-global/safe-apps-provider": "npm:0.18.4"
"@safe-global/safe-apps-sdk": "npm:9.1.0"
"@walletconnect/ethereum-provider": "npm:2.17.0"
cbw-sdk: "npm:@coinbase/wallet-sdk@3.9.3"
peerDependencies:
- "@wagmi/core": 2.14.1
+ "@wagmi/core": 2.14.6
typescript: ">=5.0.4"
viem: 2.x
peerDependenciesMeta:
typescript:
optional: true
- checksum: 78789ed27fca0bc1d54a3a8282584ddcbdcee26f2d95b27d7dd9663a7cd02e2728e0bcdd0ce0aaae8983dfac3ad966c03243dd08ce11b80d908c314f0d139cb7
+ checksum: 6cb88b23f44a57cad6c3ab992a31764f364e5ea1c38640d207eaa7f7955675738e99f2a9d2d74ea5295f617717fca1204903c82ec293d690a95a913a13451251
languageName: node
linkType: hard
-"@wagmi/core@npm:2.14.1":
- version: 2.14.1
- resolution: "@wagmi/core@npm:2.14.1"
+"@wagmi/core@npm:2.14.6":
+ version: 2.14.6
+ resolution: "@wagmi/core@npm:2.14.6"
dependencies:
eventemitter3: "npm:5.0.1"
mipd: "npm:0.0.7"
@@ -8755,7 +8755,7 @@ __metadata:
optional: true
typescript:
optional: true
- checksum: 4cde494a8fcf218e79eb4e650fd598fbb273fcaa3cab52aa0a3b41a2a104de2bac602ed19d2d2c6b130f881300770d809b5e1bfd81a8375269bed7d4e9606fb0
+ checksum: bc79ba678f00da5e769526875698e9dc1464fc650f3db27ecf9865b78f0690b7006bb36b0ea0acf6deb9ea5d5a84d343fc8ec6efaa9e9a73868ddca9a8eb046e
languageName: node
linkType: hard
@@ -9450,7 +9450,7 @@ __metadata:
languageName: node
linkType: hard
-"abitype@npm:1.0.6":
+"abitype@npm:1.0.6, abitype@npm:^1.0.6":
version: 1.0.6
resolution: "abitype@npm:1.0.6"
peerDependencies:
@@ -9800,8 +9800,8 @@ __metadata:
tsconfig: "npm:*"
turbo: "npm:2.1.1"
typescript: "npm:5.2.2"
- viem: "npm:2.21.37"
- wagmi: "npm:2.12.25"
+ viem: "npm:2.21.48"
+ wagmi: "npm:2.12.33"
languageName: unknown
linkType: soft
@@ -18610,6 +18610,26 @@ __metadata:
languageName: node
linkType: hard
+"ox@npm:0.1.2":
+ version: 0.1.2
+ resolution: "ox@npm:0.1.2"
+ dependencies:
+ "@adraffy/ens-normalize": "npm:^1.10.1"
+ "@noble/curves": "npm:^1.6.0"
+ "@noble/hashes": "npm:^1.5.0"
+ "@scure/bip32": "npm:^1.5.0"
+ "@scure/bip39": "npm:^1.4.0"
+ abitype: "npm:^1.0.6"
+ eventemitter3: "npm:5.0.1"
+ peerDependencies:
+ typescript: ">=5.4.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 9d0615e9a95c316063587fe08dc268476e67429eea897598b2f69cb1509ac66739f888b0b9bc1cfd0b4bd2f1a3fd0af4d3e81d40ba0bf3abd53e36a6f5b21323
+ languageName: node
+ linkType: hard
+
"p-filter@npm:^2.1.0":
version: 2.1.0
resolution: "p-filter@npm:2.1.0"
@@ -19169,6 +19189,13 @@ __metadata:
languageName: node
linkType: hard
+"preact@npm:^10.24.2":
+ version: 10.24.3
+ resolution: "preact@npm:10.24.3"
+ checksum: c863df6d7be6a660480189762d8a8f2d4148733fc2bb9efbd9d2fd27315d2c7ede850a16077d716c91666c915c0349bd3c9699733e4f08457226a0519f408761
+ languageName: node
+ linkType: hard
+
"preferred-pm@npm:^3.0.0":
version: 3.1.2
resolution: "preferred-pm@npm:3.1.2"
@@ -22847,17 +22874,17 @@ __metadata:
languageName: node
linkType: hard
-"viem@npm:2.21.37":
- version: 2.21.37
- resolution: "viem@npm:2.21.37"
+"viem@npm:2.21.48":
+ version: 2.21.48
+ resolution: "viem@npm:2.21.48"
dependencies:
- "@adraffy/ens-normalize": "npm:1.11.0"
"@noble/curves": "npm:1.6.0"
"@noble/hashes": "npm:1.5.0"
"@scure/bip32": "npm:1.5.0"
"@scure/bip39": "npm:1.4.0"
abitype: "npm:1.0.6"
isows: "npm:1.0.6"
+ ox: "npm:0.1.2"
webauthn-p256: "npm:0.0.10"
ws: "npm:8.18.0"
peerDependencies:
@@ -22865,7 +22892,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 573bacabc42f9e6b7050ce7fe62c2a41fe878bb9659888904d9f1acbc91a051fa4a4528eafd5c04242ddba99919cd2f5fab8987f299aa2936145254fb5caa951
+ checksum: e9b2799535263a859bddda25d962b13d2c76aec191e1849dd0f268c32a43eb65932a05cc5be270c92e19d79aafda73884690c0b0fbdb9311266a01ea3f659082
languageName: node
linkType: hard
@@ -22898,12 +22925,12 @@ __metadata:
languageName: node
linkType: hard
-"wagmi@npm:2.12.25":
- version: 2.12.25
- resolution: "wagmi@npm:2.12.25"
+"wagmi@npm:2.12.33":
+ version: 2.12.33
+ resolution: "wagmi@npm:2.12.33"
dependencies:
- "@wagmi/connectors": "npm:5.3.3"
- "@wagmi/core": "npm:2.14.1"
+ "@wagmi/connectors": "npm:5.4.0"
+ "@wagmi/core": "npm:2.14.6"
use-sync-external-store: "npm:1.2.0"
peerDependencies:
"@tanstack/react-query": ">=5.0.0"
@@ -22913,7 +22940,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 18510c1a7528c28b013130ec84fefc5792ee3d4105d60b0b598075b5b6620d51ad0e890e936c6e549e44de4eb6a36e975d14745551dcff3d1d8a963e4d29b8df
+ checksum: dca024324acdc85f602c6755243dfa61ab1dee51fa844957139af7aba50217fad1e1547227a1bdc7a465fc1921710489c9bb8d5dd354c6ee01c85c73326cc279
languageName: node
linkType: hard
From 5f7b88c220a312b07c1787dbd8aae2ee8d3a1120 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 20 Nov 2024 15:40:33 -0300
Subject: [PATCH 099/114] chore: small changes (#272)
---
.changeset/mean-elephants-kick.md | 18 +++++++++++++++++
apps/native/index.js | 1 +
apps/native/package.json | 1 +
package.json | 1 +
packages/core/src/utils/ApiUtil.ts | 20 +++++++++++++------
.../src/modal/w3m-account-button/index.tsx | 2 +-
packages/ui/src/assets/visual/Profile.tsx | 4 ++--
.../components/wui-lean-text/index.web.tsx | 3 +++
.../components/wui-lean-view/index.web.tsx | 3 +++
.../ui/src/composites/wui-qr-code/index.tsx | 2 +-
yarn.lock | 10 ++++++++++
11 files changed, 55 insertions(+), 10 deletions(-)
create mode 100644 .changeset/mean-elephants-kick.md
create mode 100644 packages/ui/src/components/wui-lean-text/index.web.tsx
create mode 100644 packages/ui/src/components/wui-lean-view/index.web.tsx
diff --git a/.changeset/mean-elephants-kick.md b/.changeset/mean-elephants-kick.md
new file mode 100644
index 000000000..4092e90d0
--- /dev/null
+++ b/.changeset/mean-elephants-kick.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+chore: small changes for web
diff --git a/apps/native/index.js b/apps/native/index.js
index 1d6e981ef..67732634f 100644
--- a/apps/native/index.js
+++ b/apps/native/index.js
@@ -1,3 +1,4 @@
+import '@expo/metro-runtime';
import { registerRootComponent } from 'expo';
import App from './App';
diff --git a/apps/native/package.json b/apps/native/package.json
index acf2071ab..e3a094c0c 100644
--- a/apps/native/package.json
+++ b/apps/native/package.json
@@ -15,6 +15,7 @@
"eas:update": "eas update --branch preview"
},
"dependencies": {
+ "@expo/metro-runtime": "~3.2.3",
"@react-native-async-storage/async-storage": "1.23.1",
"@react-native-community/netinfo": "11.3.1",
"@reown/appkit-auth-wagmi-react-native": "1.0.2",
diff --git a/package.json b/package.json
index 2a6ee1b41..0392016c5 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"gallery": "turbo run dev:gallery",
"android": "cd apps/native && yarn android",
"ios": "cd apps/native && yarn ios",
+ "web": "cd apps/native && yarn web",
"build": "turbo build",
"build:gallery": "turbo run build:gallery",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
diff --git a/packages/core/src/utils/ApiUtil.ts b/packages/core/src/utils/ApiUtil.ts
index cf689514e..bcf778f05 100644
--- a/packages/core/src/utils/ApiUtil.ts
+++ b/packages/core/src/utils/ApiUtil.ts
@@ -6,13 +6,21 @@ export const ApiUtil = {
return CoreHelperUtil.getBundleId();
},
- getUserAgent() {
- const reactNativeVersion = [
- Platform.constants.reactNativeVersion.major,
- Platform.constants.reactNativeVersion.minor,
- Platform.constants.reactNativeVersion.patch
+ getReactNativeVersion() {
+ return [
+ Platform.constants?.reactNativeVersion?.major,
+ Platform.constants?.reactNativeVersion?.minor,
+ Platform.constants?.reactNativeVersion?.patch
].join('.');
+ },
+
+ getUserAgent() {
+ const rnVersion = Platform.select({
+ ios: this.getReactNativeVersion(),
+ android: this.getReactNativeVersion(),
+ default: 'undefined'
+ });
- return `${Platform.OS}-${Platform.Version}@rn-${reactNativeVersion}`;
+ return `${Platform.OS}-${Platform.Version}@rn-${rnVersion}`;
}
};
diff --git a/packages/scaffold/src/modal/w3m-account-button/index.tsx b/packages/scaffold/src/modal/w3m-account-button/index.tsx
index 4f3186407..329ffb3b2 100644
--- a/packages/scaffold/src/modal/w3m-account-button/index.tsx
+++ b/packages/scaffold/src/modal/w3m-account-button/index.tsx
@@ -33,7 +33,7 @@ export function AccountButton({ balance, disabled, style, testID }: AccountButto
return (
ModalController.open()}
address={address}
profileName={profileName}
networkSrc={networkImage}
diff --git a/packages/ui/src/assets/visual/Profile.tsx b/packages/ui/src/assets/visual/Profile.tsx
index 3c0d3ced9..764583136 100644
--- a/packages/ui/src/assets/visual/Profile.tsx
+++ b/packages/ui/src/assets/visual/Profile.tsx
@@ -13,8 +13,8 @@ const SvgProfile = (props: SvgProps) => (
diff --git a/packages/ui/src/components/wui-lean-text/index.web.tsx b/packages/ui/src/components/wui-lean-text/index.web.tsx
new file mode 100644
index 000000000..13643b5bb
--- /dev/null
+++ b/packages/ui/src/components/wui-lean-text/index.web.tsx
@@ -0,0 +1,3 @@
+import { Text } from 'react-native';
+
+export { Text as LeanText };
diff --git a/packages/ui/src/components/wui-lean-view/index.web.tsx b/packages/ui/src/components/wui-lean-view/index.web.tsx
new file mode 100644
index 000000000..77c67cd3b
--- /dev/null
+++ b/packages/ui/src/components/wui-lean-view/index.web.tsx
@@ -0,0 +1,3 @@
+import { View } from 'react-native';
+
+export { View as LeanView };
diff --git a/packages/ui/src/composites/wui-qr-code/index.tsx b/packages/ui/src/composites/wui-qr-code/index.tsx
index 304ef336d..67f0a69aa 100644
--- a/packages/ui/src/composites/wui-qr-code/index.tsx
+++ b/packages/ui/src/composites/wui-qr-code/index.tsx
@@ -21,7 +21,7 @@ export interface QrCodeProps {
style?: StyleProp;
}
-const LABEL_HEIGHT = 15;
+const LABEL_HEIGHT = 18;
export function QrCode({ size, uri, imageSrc, testID, arenaClear, icon, style }: QrCodeProps) {
const Theme = LightTheme;
diff --git a/yarn.lock b/yarn.lock
index 753d7b55b..a619a74b6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -95,6 +95,7 @@ __metadata:
resolution: "@apps/native@workspace:apps/native"
dependencies:
"@babel/core": "npm:^7.24.0"
+ "@expo/metro-runtime": "npm:~3.2.3"
"@react-native-async-storage/async-storage": "npm:1.23.1"
"@react-native-community/netinfo": "npm:11.3.1"
"@reown/appkit-auth-wagmi-react-native": "npm:1.0.2"
@@ -4526,6 +4527,15 @@ __metadata:
languageName: node
linkType: hard
+"@expo/metro-runtime@npm:~3.2.3":
+ version: 3.2.3
+ resolution: "@expo/metro-runtime@npm:3.2.3"
+ peerDependencies:
+ react-native: "*"
+ checksum: a5357c32663e516833feed8f6fd899e1a6ab6acf79b198e860bb82076512e07f95730420eefc87a354d4004d9482b29fbecadcbdcf59b6f8737bba4da03e405e
+ languageName: node
+ linkType: hard
+
"@expo/osascript@npm:^2.0.31":
version: 2.0.33
resolution: "@expo/osascript@npm:2.0.33"
From aa3ba464c88cf38aae54b5e2185b64b513418b1b Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 20 Nov 2024 16:37:00 -0300
Subject: [PATCH 100/114] fix: refresh balance (#273)
---
.changeset/gold-beers-applaud.md | 18 ++++++++++++++++++
.../src/views/w3m-account-view/index.tsx | 12 ++++++++++++
2 files changed, 30 insertions(+)
create mode 100644 .changeset/gold-beers-applaud.md
diff --git a/.changeset/gold-beers-applaud.md b/.changeset/gold-beers-applaud.md
new file mode 100644
index 000000000..40ba2799d
--- /dev/null
+++ b/.changeset/gold-beers-applaud.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: watch token balance
diff --git a/packages/scaffold/src/views/w3m-account-view/index.tsx b/packages/scaffold/src/views/w3m-account-view/index.tsx
index 661e0f5d2..14e19d858 100644
--- a/packages/scaffold/src/views/w3m-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-view/index.tsx
@@ -51,6 +51,18 @@ export function AccountView() {
SendController.resetSend();
}, []);
+ useEffect(() => {
+ AccountController.fetchTokenBalance();
+
+ const balanceInterval = setInterval(() => {
+ AccountController.fetchTokenBalance();
+ }, 10000);
+
+ return () => {
+ clearInterval(balanceInterval);
+ };
+ }, []);
+
return (
Date: Wed, 20 Nov 2024 17:20:46 -0300
Subject: [PATCH 101/114] fix: show custom wallets (#274)
---
.changeset/mean-spoons-confess.md | 18 ++++++++++++++++++
.../partials/w3m-all-wallets-list/index.tsx | 4 ++++
2 files changed, 22 insertions(+)
create mode 100644 .changeset/mean-spoons-confess.md
diff --git a/.changeset/mean-spoons-confess.md b/.changeset/mean-spoons-confess.md
new file mode 100644
index 000000000..92772f25e
--- /dev/null
+++ b/.changeset/mean-spoons-confess.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: show custom wallets in all wallets view
diff --git a/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx b/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
index fb9c009e0..94d20443d 100644
--- a/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
+++ b/packages/scaffold/src/partials/w3m-all-wallets-list/index.tsx
@@ -4,7 +4,9 @@ import { FlatList, View } from 'react-native';
import {
ApiController,
AssetUtil,
+ OptionsController,
SnackController,
+ type OptionsControllerState,
type WcWallet
} from '@reown/appkit-core-react-native';
import {
@@ -31,11 +33,13 @@ export function AllWalletsList({ columns, itemWidth, onItemPress }: AllWalletsLi
const [pageLoading, setPageLoading] = useState(false);
const { maxWidth, padding } = useCustomDimensions();
const { installed, featured, recommended, wallets } = useSnapshot(ApiController.state);
+ const { customWallets } = useSnapshot(OptionsController.state) as OptionsControllerState;
const imageHeaders = ApiController._getApiHeaders();
const preloadedWallets = installed.length + featured.length + recommended.length;
const loadingItems = columns - ((100 + preloadedWallets) % columns);
const walletList = [
+ ...(customWallets ?? []),
...installed,
...featured,
...recommended,
From 2cb59a46a90bea3b919f47f4be8f485d867890ef Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 20 Nov 2024 17:28:30 -0300
Subject: [PATCH 102/114] fix: social login improvement (#275)
---
.changeset/nervous-apes-laugh.md | 18 ++++++++++++++++++
.../w3m-connecting-farcaster-view/index.tsx | 11 ++++++++++-
.../views/w3m-connecting-social-view/index.tsx | 8 ++++++--
packages/wallet/src/AppKitFrameProvider.ts | 2 +-
4 files changed, 35 insertions(+), 4 deletions(-)
create mode 100644 .changeset/nervous-apes-laugh.md
diff --git a/.changeset/nervous-apes-laugh.md b/.changeset/nervous-apes-laugh.md
new file mode 100644
index 000000000..c82d4d74a
--- /dev/null
+++ b/.changeset/nervous-apes-laugh.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: improved loading message in social connections
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
index fa54e0797..aba7b5ff7 100644
--- a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
@@ -28,6 +28,7 @@ export function ConnectingFarcasterView() {
const { maxWidth: width } = useCustomDimensions();
const authConnector = ConnectorController.getAuthConnector();
const [error, setError] = useState(false);
+ const [processing, setProcessing] = useState(false);
const [url, setUrl] = useState();
const showCopy = OptionsController.isClipboardAvailable();
const socialProvider = data?.socialProvider;
@@ -41,6 +42,7 @@ export function ConnectingFarcasterView() {
setUrl(farcasterUrl);
Linking.openURL(farcasterUrl);
await provider.connectFarcaster();
+ setProcessing(true);
await ConnectionController.connectExternal(authConnector);
ConnectionController.setConnectedSocialProvider(socialProvider);
EventsController.sendEvent({
@@ -49,6 +51,7 @@ export function ConnectingFarcasterView() {
properties: { provider: socialProvider }
});
WebviewController.setConnecting(false);
+ setProcessing(false);
ModalController.close();
}
} catch (e) {
@@ -59,6 +62,7 @@ export function ConnectingFarcasterView() {
});
SnackController.showError('Something went wrong');
setError(true);
+ setProcessing(false);
}
}, [provider, socialProvider, authConnector]);
@@ -96,7 +100,12 @@ export function ConnectingFarcasterView() {
)}
- Continue in Farcaster
+ {processing ? 'Loading user data' : 'Continue in Farcaster'}
+
+
+ {processing
+ ? 'Please wait a moment while we load your data'
+ : 'Connect in the Farcaster app'}
{showCopy && (
- {`Continue with ${StringUtil.capitalize(socialProvider)}`}
+ {processingAuth
+ ? 'Loading user data'
+ : `Continue with ${StringUtil.capitalize(socialProvider)}`}
- {processingAuth ? 'Retrieving user data' : 'Connect in the provider window'}
+ {processingAuth
+ ? 'Please wait a moment while we load your data'
+ : 'Connect in the provider window'}
);
diff --git a/packages/wallet/src/AppKitFrameProvider.ts b/packages/wallet/src/AppKitFrameProvider.ts
index dea444feb..b9d1fd2c0 100644
--- a/packages/wallet/src/AppKitFrameProvider.ts
+++ b/packages/wallet/src/AppKitFrameProvider.ts
@@ -539,7 +539,7 @@ export class AppKitFrameProvider {
if (shouldCheckForTimeout && this.onTimeout) {
// 15 seconds timeout
- timer = setTimeout(this.onTimeout, 15000);
+ timer = setTimeout(this.onTimeout, 30000);
}
return new Promise((resolve, reject) => {
From 1fe0f3fa0f96d14f63f2ffc96092b2bc239c4f92 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 20 Nov 2024 18:36:16 -0300
Subject: [PATCH 103/114] fix/siwe imports (#276)
---
.changeset/big-planes-admire.md | 18 ++++++++++++++++++
packages/ethers/src/client.ts | 11 ++++++-----
packages/ethers5/src/client.ts | 11 ++++++-----
packages/scaffold/src/client.ts | 4 +---
.../scaffold/src/modal/w3m-modal/index.tsx | 12 +++++-------
.../src/views/w3m-connecting-view/index.tsx | 2 +-
packages/wagmi/src/client.ts | 11 ++++++-----
7 files changed, 43 insertions(+), 26 deletions(-)
create mode 100644 .changeset/big-planes-admire.md
diff --git a/.changeset/big-planes-admire.md b/.changeset/big-planes-admire.md
new file mode 100644
index 000000000..eb8f422d1
--- /dev/null
+++ b/.changeset/big-planes-admire.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: changed siwe imports to solve issues on some android devices
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 0db093654..79c0370f4 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -45,12 +45,17 @@ import {
type CombinedProviderType,
type AppKitFrameProvider
} from '@reown/appkit-scaffold-utils-react-native';
+import {
+ type AppKitSIWEClient,
+ SIWEController,
+ getDidChainId,
+ getDidAddress
+} from '@reown/appkit-siwe-react-native';
import EthereumProvider, { OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
import type { EthereumProviderOptions } from '@walletconnect/ethereum-provider';
import { type JsonRpcError } from '@walletconnect/jsonrpc-types';
import { getAuthCaipNetworks, getWalletConnectCaipNetworks } from './utils/helpers';
-import type { AppKitSIWEClient } from '@reown/appkit-siwe-react-native';
// -- Types ---------------------------------------------------------------------
export interface AppKitClientOptions extends Omit {
@@ -170,9 +175,6 @@ export class AppKit extends AppKitScaffold {
// SIWE
const params = await siweConfig?.getMessageParams?.();
if (siweConfig?.options?.enabled && params && Object.keys(params).length > 0) {
- const { SIWEController, getDidChainId, getDidAddress } = await import(
- '@reown/appkit-siwe-react-native'
- );
const result = await WalletConnectProvider.authenticate({
nonce: await siweConfig.getNonce(),
methods: OPTIONAL_METHODS,
@@ -255,7 +257,6 @@ export class AppKit extends AppKitScaffold {
const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID];
if (siweConfig?.options?.signOutOnDisconnect) {
- const { SIWEController } = await import('@reown/appkit-siwe-react-native');
await SIWEController.signOut();
}
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index d9ade873d..0f48b56e1 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -31,13 +31,18 @@ import {
type CombinedProviderType,
type AppKitFrameProvider
} from '@reown/appkit-scaffold-utils-react-native';
+import {
+ SIWEController,
+ getDidChainId,
+ getDidAddress,
+ type AppKitSIWEClient
+} from '@reown/appkit-siwe-react-native';
import { erc20ABI, ErrorUtil, NamesUtil, NetworkUtil } from '@reown/appkit-common-react-native';
import EthereumProvider, { OPTIONAL_METHODS } from '@walletconnect/ethereum-provider';
import type { EthereumProviderOptions } from '@walletconnect/ethereum-provider';
import { type JsonRpcError } from '@walletconnect/jsonrpc-types';
import { getAuthCaipNetworks, getWalletConnectCaipNetworks } from './utils/helpers';
-import type { AppKitSIWEClient } from '@reown/appkit-siwe-react-native';
// -- Types ---------------------------------------------------------------------
export interface AppKitClientOptions extends Omit {
@@ -157,9 +162,6 @@ export class AppKit extends AppKitScaffold {
// SIWE
const params = await siweConfig?.getMessageParams?.();
if (siweConfig?.options?.enabled && params && Object.keys(params).length > 0) {
- const { SIWEController, getDidChainId, getDidAddress } = await import(
- '@reown/appkit-siwe-react-native'
- );
const result = await WalletConnectProvider.authenticate({
nonce: await siweConfig.getNonce(),
methods: OPTIONAL_METHODS,
@@ -241,7 +243,6 @@ export class AppKit extends AppKitScaffold {
const authType = PresetsUtil.ConnectorTypesMap[ConstantsUtil.AUTH_CONNECTOR_ID];
if (siweConfig?.options?.signOutOnDisconnect) {
- const { SIWEController } = await import('@reown/appkit-siwe-react-native');
await SIWEController.signOut();
}
diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts
index 0af3bcef9..80d682707 100644
--- a/packages/scaffold/src/client.ts
+++ b/packages/scaffold/src/client.ts
@@ -16,7 +16,7 @@ import type {
ConnectedWalletInfo,
Features
} from '@reown/appkit-core-react-native';
-import type { SIWEControllerClient } from '@reown/appkit-siwe-react-native';
+import { SIWEController, type SIWEControllerClient } from '@reown/appkit-siwe-react-native';
import {
AccountController,
BlockchainApiController,
@@ -299,8 +299,6 @@ export class AppKitScaffold {
}
if (options.siweControllerClient) {
- const { SIWEController } = await import('@reown/appkit-siwe-react-native');
-
SIWEController.setSIWEClient(options.siweControllerClient);
}
diff --git a/packages/scaffold/src/modal/w3m-modal/index.tsx b/packages/scaffold/src/modal/w3m-modal/index.tsx
index eae3b380f..d4a9c4cae 100644
--- a/packages/scaffold/src/modal/w3m-modal/index.tsx
+++ b/packages/scaffold/src/modal/w3m-modal/index.tsx
@@ -18,6 +18,7 @@ import {
type AppKitFrameProvider,
WebviewController
} from '@reown/appkit-core-react-native';
+import { SIWEController } from '@reown/appkit-siwe-react-native';
import { AppKitRouter } from '../w3m-router';
import { Header } from '../../partials/w3m-header';
@@ -30,7 +31,6 @@ export function AppKit() {
const { connectors, connectedConnector } = useSnapshot(ConnectorController.state);
const { caipAddress, isConnected } = useSnapshot(AccountController.state);
const { frameViewVisible, webviewVisible } = useSnapshot(WebviewController.state);
- const { isSiweEnabled } = OptionsController.state;
const { height } = useWindowDimensions();
const { isLandscape } = useCustomDimensions();
const portraitHeight = height - 120;
@@ -54,9 +54,7 @@ export function AppKit() {
};
const handleClose = async () => {
- if (isSiweEnabled) {
- const { SIWEController } = await import('@reown/appkit-siwe-react-native');
-
+ if (OptionsController.state.isSiweEnabled) {
if (SIWEController.state.status !== 'success' && AccountController.state.isConnected) {
await ConnectionController.disconnect();
}
@@ -73,9 +71,9 @@ export function AppKit() {
TransactionsController.resetTransactions();
TransactionsController.fetchTransactions(newAddress, true);
- if (isSiweEnabled) {
+ if (OptionsController.state.isSiweEnabled) {
const newNetworkId = CoreHelperUtil.getNetworkId(address);
- const { SIWEController } = await import('@reown/appkit-siwe-react-native');
+
const { signOutOnAccountChange, signOutOnNetworkChange } =
SIWEController.state._client?.options ?? {};
const session = await SIWEController.getSession();
@@ -98,7 +96,7 @@ export function AppKit() {
}
}
},
- [isSiweEnabled, isConnected, loading]
+ [isConnected, loading]
);
const onSiweNavigation = () => {
diff --git a/packages/scaffold/src/views/w3m-connecting-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-view/index.tsx
index 82a501ce6..44ee537c9 100644
--- a/packages/scaffold/src/views/w3m-connecting-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-view/index.tsx
@@ -14,6 +14,7 @@ import {
EventsController,
ConnectorController
} from '@reown/appkit-core-react-native';
+import { SIWEController } from '@reown/appkit-siwe-react-native';
import { ConnectingQrCode } from '../../partials/w3m-connecting-qrcode';
import { ConnectingMobile } from '../../partials/w3m-connecting-mobile';
@@ -53,7 +54,6 @@ export function ConnectingView() {
AccountController.setIsConnected(true);
if (OptionsController.state.isSiweEnabled) {
- const { SIWEController } = await import('@reown/appkit-siwe-react-native');
if (SIWEController.state.status === 'success') {
ModalController.close();
} else {
diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts
index 46a75a3d3..eb5d42c79 100644
--- a/packages/wagmi/src/client.ts
+++ b/packages/wagmi/src/client.ts
@@ -46,7 +46,12 @@ import {
StorageUtil
} from '@reown/appkit-scaffold-utils-react-native';
import { NetworkUtil, NamesUtil, ErrorUtil } from '@reown/appkit-common-react-native';
-import { type AppKitSIWEClient } from '@reown/appkit-siwe-react-native';
+import {
+ SIWEController,
+ getDidChainId,
+ getDidAddress,
+ type AppKitSIWEClient
+} from '@reown/appkit-siwe-react-native';
import {
getCaipDefaultChain,
getAuthCaipNetworks,
@@ -159,9 +164,6 @@ export class AppKit extends AppKitScaffold {
siweParams &&
Object.keys(siweParams || {}).length > 0
) {
- const { SIWEController, getDidChainId, getDidAddress } = await import(
- '@reown/appkit-siwe-react-native'
- );
// @ts-expect-error - setting requested chains beforehand avoids wagmi auto disconnecting the session when `connect` is called because it things chains are stale
await connector.setRequestedChainsIds(siweParams.chains);
const result = await provider.authenticate(
@@ -242,7 +244,6 @@ export class AppKit extends AppKitScaffold {
this.setClientId(null);
if (siweConfig?.options?.signOutOnDisconnect) {
- const { SIWEController } = await import('@reown/appkit-siwe-react-native');
await SIWEController.signOut();
}
},
From 285a64bfb310913c79b1ba9a85a82387e41a63ff Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 21 Nov 2024 11:52:36 -0300
Subject: [PATCH 104/114] fix: ui changes in social webview to solve android
issues (#277)
---
.changeset/violet-lamps-chew.md | 18 ++++++++++++++++++
packages/wallet/src/AppKitWebview.tsx | 22 ++++++----------------
2 files changed, 24 insertions(+), 16 deletions(-)
create mode 100644 .changeset/violet-lamps-chew.md
diff --git a/.changeset/violet-lamps-chew.md b/.changeset/violet-lamps-chew.md
new file mode 100644
index 000000000..e69e3d5f6
--- /dev/null
+++ b/.changeset/violet-lamps-chew.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+fix: ui changes in social webview to solve android issues
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index 4c00eeb8a..df38e1ffc 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -20,15 +20,10 @@ export function AppKitWebview() {
const authConnector = ConnectorController.getAuthConnector();
const { webviewVisible, webviewUrl } = useSnapshot(WebviewController.state);
const [isBackdropVisible, setIsBackdropVisible] = useState(false);
- const animatedHeight = useRef(new Animated.Value(0));
const backdropOpacity = useRef(new Animated.Value(0));
const webviewOpacity = useRef(new Animated.Value(0));
const provider = authConnector?.provider as AppKitFrameProvider;
-
- const show = animatedHeight.current.interpolate({
- inputRange: [0, 1],
- outputRange: ['0%', '80%']
- });
+ const display = webviewVisible ? 'flex' : 'none';
const onClose = () => {
WebviewController.setWebviewVisible(false);
@@ -38,16 +33,10 @@ export function AppKitWebview() {
};
useEffect(() => {
- Animated.timing(animatedHeight.current, {
- toValue: webviewVisible ? 1 : 0,
- duration: 200,
- useNativeDriver: false
- }).start();
-
Animated.timing(webviewOpacity.current, {
toValue: webviewVisible ? 1 : 0,
duration: 300,
- useNativeDriver: false
+ useNativeDriver: true
}).start(({ finished }) => {
if (finished && !webviewVisible) {
WebviewController.setWebviewUrl('');
@@ -61,9 +50,9 @@ export function AppKitWebview() {
Animated.timing(backdropOpacity.current, {
toValue: webviewVisible ? 0.7 : 0,
duration: 300,
- useNativeDriver: false
+ useNativeDriver: true
}).start(() => setIsBackdropVisible(webviewVisible));
- }, [animatedHeight, backdropOpacity, webviewVisible, setIsBackdropVisible]);
+ }, [backdropOpacity, webviewVisible, setIsBackdropVisible]);
if (!webviewUrl) return null;
@@ -79,7 +68,7 @@ export function AppKitWebview() {
Date: Fri, 29 Nov 2024 14:36:52 -0300
Subject: [PATCH 105/114] chore: removed lean components in favor of
compatibility (#279)
* chore: removed lean components in favor of compatibility
---
packages/ui/src/__tests__/wui-text.test.tsx | 9 ---------
packages/ui/src/components/wui-lean-text/index.tsx | 10 ----------
.../ui/src/components/wui-lean-text/index.web.tsx | 3 ---
packages/ui/src/components/wui-lean-view/index.tsx | 10 ----------
.../ui/src/components/wui-lean-view/index.web.tsx | 3 ---
packages/ui/src/components/wui-text/index.tsx | 7 +++----
packages/ui/src/composites/wui-list-wallet/index.tsx | 11 +++++------
packages/ui/src/layout/wui-flex/index.tsx | 5 ++---
packages/ui/src/layout/wui-separator/index.tsx | 11 ++++-------
9 files changed, 14 insertions(+), 55 deletions(-)
delete mode 100644 packages/ui/src/components/wui-lean-text/index.tsx
delete mode 100644 packages/ui/src/components/wui-lean-text/index.web.tsx
delete mode 100644 packages/ui/src/components/wui-lean-view/index.tsx
delete mode 100644 packages/ui/src/components/wui-lean-view/index.web.tsx
diff --git a/packages/ui/src/__tests__/wui-text.test.tsx b/packages/ui/src/__tests__/wui-text.test.tsx
index 7475ecb83..e39bae272 100644
--- a/packages/ui/src/__tests__/wui-text.test.tsx
+++ b/packages/ui/src/__tests__/wui-text.test.tsx
@@ -1,15 +1,6 @@
import { render } from '@testing-library/react-native';
-import { configureInternal } from '@testing-library/react-native/build/config';
import { Text } from '../components/wui-text';
-configureInternal({
- hostComponentNames: {
- text: 'RCTText',
- textInput: 'RCTTextInput',
- switch: 'RCTSwitch'
- }
-});
-
test('Text render', () => {
const label = 'Hello World';
const { getAllByText } = render({label});
diff --git a/packages/ui/src/components/wui-lean-text/index.tsx b/packages/ui/src/components/wui-lean-text/index.tsx
deleted file mode 100644
index 98fe33a25..000000000
--- a/packages/ui/src/components/wui-lean-text/index.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { type ComponentType, createElement, forwardRef } from 'react';
-import type { TextProps } from 'react-native';
-
-const LeanText = forwardRef((props, ref) => {
- return createElement('RCTText', { ...props, ref });
-}) as ComponentType;
-
-LeanText.displayName = 'RCTText';
-
-export { LeanText };
diff --git a/packages/ui/src/components/wui-lean-text/index.web.tsx b/packages/ui/src/components/wui-lean-text/index.web.tsx
deleted file mode 100644
index 13643b5bb..000000000
--- a/packages/ui/src/components/wui-lean-text/index.web.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { Text } from 'react-native';
-
-export { Text as LeanText };
diff --git a/packages/ui/src/components/wui-lean-view/index.tsx b/packages/ui/src/components/wui-lean-view/index.tsx
deleted file mode 100644
index 8bcda5fdb..000000000
--- a/packages/ui/src/components/wui-lean-view/index.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { type ComponentType, createElement, forwardRef } from 'react';
-import type { ViewProps } from 'react-native';
-
-const LeanView = forwardRef((props, ref) => {
- return createElement('RCTView', { ...props, ref });
-}) as ComponentType;
-
-LeanView.displayName = 'RCTView';
-
-export { LeanView };
diff --git a/packages/ui/src/components/wui-lean-view/index.web.tsx b/packages/ui/src/components/wui-lean-view/index.web.tsx
deleted file mode 100644
index 77c67cd3b..000000000
--- a/packages/ui/src/components/wui-lean-view/index.web.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { View } from 'react-native';
-
-export { View as LeanView };
diff --git a/packages/ui/src/components/wui-text/index.tsx b/packages/ui/src/components/wui-text/index.tsx
index a728a292f..41d32ef1c 100644
--- a/packages/ui/src/components/wui-text/index.tsx
+++ b/packages/ui/src/components/wui-text/index.tsx
@@ -1,6 +1,5 @@
-import { type TextProps as NativeProps } from 'react-native';
+import { Text as NativeText, type TextProps as NativeProps } from 'react-native';
import { useTheme } from '../../hooks/useTheme';
-import { LeanText } from '../wui-lean-text';
import type { ColorType, TextType } from '../../utils/TypesUtil';
import styles from './styles';
@@ -21,7 +20,7 @@ export function Text({
const Theme = useTheme();
return (
-
{children}
-
+
);
}
diff --git a/packages/ui/src/composites/wui-list-wallet/index.tsx b/packages/ui/src/composites/wui-list-wallet/index.tsx
index c8a28665d..ace660e13 100644
--- a/packages/ui/src/composites/wui-list-wallet/index.tsx
+++ b/packages/ui/src/composites/wui-list-wallet/index.tsx
@@ -1,4 +1,4 @@
-import { Animated, Pressable, type StyleProp, type ViewStyle } from 'react-native';
+import { Animated, Pressable, type StyleProp, type ViewStyle, View } from 'react-native';
import { Text } from '../../components/wui-text';
import useAnimatedValue from '../../hooks/useAnimatedValue';
import { useTheme } from '../../hooks/useTheme';
@@ -6,7 +6,6 @@ import type { IconType, TagType } from '../../utils/TypesUtil';
import { Tag } from '../wui-tag';
import { WalletImage } from '../wui-wallet-image';
import { Icon } from '../../components/wui-icon';
-import { LeanView } from '../../components/wui-lean-view';
import { IconBox } from '../wui-icon-box';
import styles from './styles';
@@ -68,7 +67,7 @@ export function ListWallet({
function imageTemplate() {
return (
-
+
{templateInstalled()}
-
+
);
}
@@ -117,12 +116,12 @@ export function ListWallet({
onPressOut={setStartValue}
testID={testID}
>
-
+
{imageTemplate()}
{name}
-
+
{iconTemplate()}
);
diff --git a/packages/ui/src/layout/wui-flex/index.tsx b/packages/ui/src/layout/wui-flex/index.tsx
index c810bd6e1..e155cd4b0 100644
--- a/packages/ui/src/layout/wui-flex/index.tsx
+++ b/packages/ui/src/layout/wui-flex/index.tsx
@@ -1,4 +1,4 @@
-import { type StyleProp, type ViewStyle } from 'react-native';
+import { type StyleProp, type ViewStyle, View } from 'react-native';
import type {
FlexAlignType,
@@ -10,7 +10,6 @@ import type {
SpacingType
} from '../../utils/TypesUtil';
import { UiUtil } from '../../utils/UiUtil';
-import { LeanView } from '../../components/wui-lean-view';
export interface FlexViewProps {
children?: React.ReactNode;
@@ -45,5 +44,5 @@ export function FlexView(props: FlexViewProps) {
marginLeft: props.margin && UiUtil.getSpacingStyles(props.margin, 3)
};
- return {props.children};
+ return {props.children};
}
diff --git a/packages/ui/src/layout/wui-separator/index.tsx b/packages/ui/src/layout/wui-separator/index.tsx
index 3dd59ff8b..b438c59ab 100644
--- a/packages/ui/src/layout/wui-separator/index.tsx
+++ b/packages/ui/src/layout/wui-separator/index.tsx
@@ -1,6 +1,5 @@
-import { type StyleProp, type ViewStyle } from 'react-native';
+import { type StyleProp, type ViewStyle, View } from 'react-native';
import { Text } from '../../components/wui-text';
-import { LeanView } from '../../components/wui-lean-view';
import { FlexView } from '../../layout/wui-flex';
import { useTheme } from '../../hooks/useTheme';
import styles from './styles';
@@ -14,20 +13,18 @@ export function Separator({ text, style }: SeparatorProps) {
const Theme = useTheme();
if (!text) {
- return (
-
- );
+ return ;
}
return (
-
{text}
-
From b2f40ab57bf2ac99b3663b07cbb7551201a5f511 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 4 Dec 2024 16:22:40 -0300
Subject: [PATCH 106/114] chore: send new social events (#280)
* chore: send new social events
---
.../src/controllers/ConnectionController.ts | 7 +++-
.../core/src/controllers/RouterController.ts | 2 -
packages/core/src/utils/TypeUtil.ts | 14 +++++++
.../src/partials/w3m-header/index.tsx | 39 +++++++++++++-----
.../views/w3m-connect-socials-view/index.tsx | 6 ++-
.../components/social-login-list.tsx | 12 +++---
.../w3m-connecting-farcaster-view/index.tsx | 22 +++++-----
.../w3m-connecting-social-view/index.tsx | 41 ++++++++++++-------
packages/wallet/src/AppKitWebview.tsx | 18 ++++++--
9 files changed, 113 insertions(+), 48 deletions(-)
diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts
index 4e0087901..f0c7c8758 100644
--- a/packages/core/src/controllers/ConnectionController.ts
+++ b/packages/core/src/controllers/ConnectionController.ts
@@ -48,6 +48,7 @@ export interface ConnectionControllerState {
wcError?: boolean;
pressedWallet?: WcWallet;
recentWallets?: WcWallet[];
+ selectedSocialProvider?: SocialProvider;
connectedWalletImageUrl?: string;
connectedSocialProvider?: SocialProvider;
}
@@ -122,6 +123,10 @@ export const ConnectionController = {
state.recentWallets = wallets;
},
+ setSelectedSocialProvider(provider: ConnectionControllerState['selectedSocialProvider']) {
+ state.selectedSocialProvider = provider;
+ },
+
async setConnectedWalletImageUrl(url: ConnectionControllerState['connectedWalletImageUrl']) {
state.connectedWalletImageUrl = url;
@@ -176,7 +181,7 @@ export const ConnectionController = {
resetWcConnection() {
this.clearUri();
state.pressedWallet = undefined;
- ConnectionController.setConnectedSocialProvider(undefined);
+ state.selectedSocialProvider = undefined;
ConnectionController.setConnectedWalletImageUrl(undefined);
ConnectorController.setConnectedConnector(undefined);
StorageUtil.removeWalletConnectDeepLink();
diff --git a/packages/core/src/controllers/RouterController.ts b/packages/core/src/controllers/RouterController.ts
index a472288ed..e84195189 100644
--- a/packages/core/src/controllers/RouterController.ts
+++ b/packages/core/src/controllers/RouterController.ts
@@ -1,6 +1,5 @@
import { proxy } from 'valtio';
import type { WcWallet, CaipNetwork, Connector } from '../utils/TypeUtil';
-import type { SocialProvider } from '@reown/appkit-common-react-native';
// -- Types --------------------------------------------- //
type TransactionAction = {
@@ -50,7 +49,6 @@ export interface RouterControllerState {
network?: CaipNetwork;
email?: string;
newEmail?: string;
- socialProvider?: SocialProvider;
};
transactionStack: TransactionAction[];
}
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index d91b2cc23..d0bce97b0 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -485,6 +485,20 @@ export type Event =
provider: SocialProvider;
};
}
+ | {
+ type: 'track';
+ event: 'SOCIAL_LOGIN_REQUEST_USER_DATA';
+ properties: {
+ provider: SocialProvider;
+ };
+ }
+ | {
+ type: 'track';
+ event: 'SOCIAL_LOGIN_CANCELED';
+ properties: {
+ provider: SocialProvider;
+ };
+ }
| {
type: 'track';
event: 'SOCIAL_LOGIN_ERROR';
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index e084bcd37..ec39d7ddb 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -3,7 +3,8 @@ import {
RouterController,
ModalController,
EventsController,
- type RouterControllerState
+ type RouterControllerState,
+ ConnectionController
} from '@reown/appkit-core-react-native';
import { IconLink, Text, FlexView } from '@reown/appkit-ui-react-native';
import { StringUtil } from '@reown/appkit-common-react-native';
@@ -21,8 +22,8 @@ export function Header() {
const connectorName = _data?.connector?.name;
const walletName = _data?.wallet?.name;
const networkName = _data?.network?.name;
- const socialName = _data?.socialProvider
- ? StringUtil.capitalize(_data?.socialProvider)
+ const socialName = ConnectionController.state.selectedSocialProvider
+ ? StringUtil.capitalize(ConnectionController.state.selectedSocialProvider)
: undefined;
return {
@@ -60,6 +61,29 @@ export function Header() {
const header = headings(data, view);
+ const checkSocial = () => {
+ if (
+ RouterController.state.view === 'ConnectingFarcaster' ||
+ RouterController.state.view === 'ConnectingSocial'
+ ) {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_CANCELED',
+ properties: { provider: ConnectionController.state.selectedSocialProvider! }
+ });
+ }
+ };
+
+ const handleGoBack = () => {
+ checkSocial();
+ RouterController.goBack();
+ };
+
+ const handleClose = () => {
+ checkSocial();
+ ModalController.close();
+ };
+
const dynamicButtonTemplate = () => {
const noButtonViews = ['ConnectingSiwe'];
@@ -70,12 +94,7 @@ export function Header() {
const showBack = RouterController.state.history.length > 1;
return showBack ? (
-
+
) : (
);
@@ -96,7 +115,7 @@ export function Header() {
{header}
-
+
);
}
diff --git a/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx b/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
index 668123d88..228bc143e 100644
--- a/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connect-socials-view/index.tsx
@@ -3,6 +3,7 @@ import { useSnapshot } from 'valtio';
import { ScrollView } from 'react-native';
import { StringUtil, type SocialProvider } from '@reown/appkit-common-react-native';
import {
+ ConnectionController,
EventsController,
OptionsController,
RouterController,
@@ -19,15 +20,16 @@ export function ConnectSocialsView() {
const socialProviders = (features?.socials ?? []) as SocialProvider[];
const onItemPress = (provider: SocialProvider) => {
+ ConnectionController.setSelectedSocialProvider(provider);
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_STARTED',
properties: { provider }
});
if (provider === 'farcaster') {
- RouterController.push('ConnectingFarcaster', { socialProvider: provider });
+ RouterController.push('ConnectingFarcaster');
} else {
- RouterController.push('ConnectingSocial', { socialProvider: provider });
+ RouterController.push('ConnectingSocial');
}
};
diff --git a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
index cc1e45a2b..ea2740dbf 100644
--- a/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
+++ b/packages/scaffold/src/views/w3m-connect-view/components/social-login-list.tsx
@@ -2,6 +2,7 @@ import { StyleSheet } from 'react-native';
import { FlexView, ListSocial, LogoSelect, Spacing, Text } from '@reown/appkit-ui-react-native';
import { type SocialProvider, StringUtil } from '@reown/appkit-common-react-native';
import {
+ ConnectionController,
EventsController,
RouterController,
WebviewController
@@ -21,18 +22,19 @@ export function SocialLoginList({ options, disabled }: SocialLoginListProps) {
let bottomSocials = showBigSocial ? options.slice(1) : options;
bottomSocials = showMoreButton ? bottomSocials.slice(0, MAX_OPTIONS - 2) : bottomSocials;
- const onItemPress = (social: SocialProvider) => {
+ const onItemPress = (provider: SocialProvider) => {
+ ConnectionController.setSelectedSocialProvider(provider);
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_STARTED',
- properties: { provider: social }
+ properties: { provider }
});
WebviewController.setConnecting(false);
- if (social === 'farcaster') {
- RouterController.push('ConnectingFarcaster', { socialProvider: social });
+ if (provider === 'farcaster') {
+ RouterController.push('ConnectingFarcaster');
} else {
- RouterController.push('ConnectingSocial', { socialProvider: social });
+ RouterController.push('ConnectingSocial');
}
};
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
index aba7b5ff7..bea4029db 100644
--- a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
@@ -6,9 +6,7 @@ import {
EventsController,
ModalController,
OptionsController,
- RouterController,
SnackController,
- WebviewController,
type AppKitFrameProvider
} from '@reown/appkit-core-react-native';
import {
@@ -24,33 +22,37 @@ import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
export function ConnectingFarcasterView() {
- const { data } = RouterController.state;
const { maxWidth: width } = useCustomDimensions();
const authConnector = ConnectorController.getAuthConnector();
const [error, setError] = useState(false);
const [processing, setProcessing] = useState(false);
const [url, setUrl] = useState();
const showCopy = OptionsController.isClipboardAvailable();
- const socialProvider = data?.socialProvider;
const provider = authConnector?.provider as AppKitFrameProvider;
const onConnect = useCallback(async () => {
try {
- if (!WebviewController.state.connecting && provider && socialProvider && authConnector) {
+ if (provider && authConnector) {
setError(false);
const { url: farcasterUrl } = await provider.getFarcasterUri();
setUrl(farcasterUrl);
Linking.openURL(farcasterUrl);
+
await provider.connectFarcaster();
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_REQUEST_USER_DATA',
+ properties: { provider: 'farcaster' }
+ });
setProcessing(true);
await ConnectionController.connectExternal(authConnector);
- ConnectionController.setConnectedSocialProvider(socialProvider);
+ ConnectionController.setConnectedSocialProvider('farcaster');
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_SUCCESS',
- properties: { provider: socialProvider }
+ properties: { provider: 'farcaster' }
});
- WebviewController.setConnecting(false);
+
setProcessing(false);
ModalController.close();
}
@@ -58,13 +60,13 @@ export function ConnectingFarcasterView() {
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_ERROR',
- properties: { provider: socialProvider! }
+ properties: { provider: 'farcaster' }
});
SnackController.showError('Something went wrong');
setError(true);
setProcessing(false);
}
- }, [provider, socialProvider, authConnector]);
+ }, [provider, authConnector]);
const onCopyUrl = () => {
if (url) {
diff --git a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
index 1f15870d5..dc7b0aaa2 100644
--- a/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-social-view/index.tsx
@@ -18,27 +18,31 @@ import { useCustomDimensions } from '../../hooks/useCustomDimensions';
import styles from './styles';
export function ConnectingSocialView() {
- const { data } = RouterController.state;
const { maxWidth: width } = useCustomDimensions();
const { processingAuth } = useSnapshot(WebviewController.state);
+ const { selectedSocialProvider } = useSnapshot(ConnectionController.state);
const authConnector = ConnectorController.getAuthConnector();
const [error, setError] = useState(false);
- const socialProvider = data?.socialProvider;
const provider = authConnector?.provider as AppKitFrameProvider;
const onConnect = useCallback(async () => {
try {
- if (!WebviewController.state.connecting && provider && socialProvider) {
+ if (
+ !WebviewController.state.connecting &&
+ provider &&
+ ConnectionController.state.selectedSocialProvider
+ ) {
const { uri } = await provider.getSocialRedirectUri({
- provider: socialProvider
+ provider: ConnectionController.state.selectedSocialProvider
});
WebviewController.setWebviewUrl(uri);
- const isNativeApple = socialProvider === 'apple' && Platform.OS === 'ios';
+ const isNativeApple =
+ ConnectionController.state.selectedSocialProvider === 'apple' && Platform.OS === 'ios';
WebviewController.setWebviewVisible(!isNativeApple);
WebviewController.setConnecting(true);
- WebviewController.setConnectingProvider(socialProvider);
+ WebviewController.setConnectingProvider(ConnectionController.state.selectedSocialProvider);
}
} catch (e) {
WebviewController.setWebviewVisible(false);
@@ -48,29 +52,38 @@ export function ConnectingSocialView() {
SnackController.showError('Something went wrong');
setError(true);
}
- }, [provider, socialProvider]);
+ }, [provider]);
const socialMessageHandler = useCallback(
async (url: string) => {
try {
if (
url.includes('/sdk/oauth') &&
- socialProvider &&
+ ConnectionController.state.selectedSocialProvider &&
authConnector &&
!WebviewController.state.processingAuth
) {
WebviewController.setProcessingAuth(true);
WebviewController.setWebviewVisible(false);
const parsedUrl = new URL(url);
+
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_REQUEST_USER_DATA',
+ properties: { provider: ConnectionController.state.selectedSocialProvider }
+ });
+
await provider?.connectSocial(parsedUrl.search);
await ConnectionController.connectExternal(authConnector);
- ConnectionController.setConnectedSocialProvider(socialProvider);
+ ConnectionController.setConnectedSocialProvider(
+ ConnectionController.state.selectedSocialProvider
+ );
WebviewController.setConnecting(false);
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_SUCCESS',
- properties: { provider: socialProvider }
+ properties: { provider: ConnectionController.state.selectedSocialProvider }
});
ModalController.close();
@@ -80,14 +93,14 @@ export function ConnectingSocialView() {
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_ERROR',
- properties: { provider: socialProvider! }
+ properties: { provider: ConnectionController.state.selectedSocialProvider! }
});
WebviewController.reset();
RouterController.goBack();
SnackController.showError('Something went wrong');
}
},
- [socialProvider, authConnector, provider]
+ [authConnector, provider]
);
useEffect(() => {
@@ -112,7 +125,7 @@ export function ConnectingSocialView() {
style={{ width }}
>
-
+
{error && (
{processingAuth
? 'Loading user data'
- : `Continue with ${StringUtil.capitalize(socialProvider)}`}
+ : `Continue with ${StringUtil.capitalize(selectedSocialProvider)}`}
{processingAuth
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index df38e1ffc..bbbd648c0 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -1,10 +1,11 @@
import { useSnapshot } from 'valtio';
import { useEffect, useRef, useState } from 'react';
-import { Animated, SafeAreaView, StyleSheet } from 'react-native';
+import { Animated, Pressable, SafeAreaView, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
-
import {
+ ConnectionController,
ConnectorController,
+ EventsController,
RouterController,
WebviewController
} from '@reown/appkit-core-react-native';
@@ -13,6 +14,7 @@ import type { AppKitFrameProvider } from './AppKitFrameProvider';
import { AppKitFrameConstants } from './AppKitFrameConstants';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
+const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
export function AppKitWebview() {
const webviewRef = useRef(null);
@@ -26,6 +28,12 @@ export function AppKitWebview() {
const display = webviewVisible ? 'flex' : 'none';
const onClose = () => {
+ EventsController.sendEvent({
+ type: 'track',
+ event: 'SOCIAL_LOGIN_CANCELED',
+ properties: { provider: ConnectionController.state.selectedSocialProvider! }
+ });
+
WebviewController.setWebviewVisible(false);
WebviewController.setConnecting(false);
WebviewController.setConnectingProvider(undefined);
@@ -58,7 +66,8 @@ export function AppKitWebview() {
return provider ? (
<>
-
Date: Tue, 10 Dec 2024 11:09:40 -0300
Subject: [PATCH 107/114] fix: farcaster login refresh (#281)
* fix: added temporary workaround to reload auth site if farcaster flow is closed
* chore: code styling
---
.../scaffold/src/partials/w3m-header/index.tsx | 13 ++++++++++++-
.../views/w3m-connecting-farcaster-view/index.tsx | 14 ++++++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index ec39d7ddb..6f280bd72 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -4,7 +4,9 @@ import {
ModalController,
EventsController,
type RouterControllerState,
- ConnectionController
+ ConnectionController,
+ ConnectorController,
+ type AppKitFrameProvider
} from '@reown/appkit-core-react-native';
import { IconLink, Text, FlexView } from '@reown/appkit-ui-react-native';
import { StringUtil } from '@reown/appkit-common-react-native';
@@ -66,6 +68,15 @@ export function Header() {
RouterController.state.view === 'ConnectingFarcaster' ||
RouterController.state.view === 'ConnectingSocial'
) {
+ const socialProvider = ConnectionController.state.selectedSocialProvider;
+ const authProvider = ConnectorController.getAuthConnector()?.provider as AppKitFrameProvider;
+
+ if (authProvider && socialProvider === 'farcaster') {
+ // TODO: remove this once Farcaster session refresh is implemented
+ // @ts-expect-error
+ authProvider.webviewRef?.current?.reload();
+ }
+
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_CANCELED',
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
index bea4029db..ce726591f 100644
--- a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
@@ -62,6 +62,9 @@ export function ConnectingFarcasterView() {
event: 'SOCIAL_LOGIN_ERROR',
properties: { provider: 'farcaster' }
});
+ // TODO: remove this once Farcaster session refresh is implemented
+ // @ts-expect-error
+ provider?.webviewRef?.current?.reload();
SnackController.showError('Something went wrong');
setError(true);
setProcessing(false);
@@ -75,6 +78,17 @@ export function ConnectingFarcasterView() {
}
};
+ useEffect(() => {
+ return () => {
+ // TODO: remove this once Farcaster session refresh is implemented
+ if (!ModalController.state.open) {
+ // @ts-expect-error
+ provider.webviewRef?.current?.reload();
+ }
+ };
+ // @ts-expect-error
+ }, [provider.webviewRef]);
+
useEffect(() => {
onConnect();
}, [onConnect]);
From 10723571e64acc43b8c68dfb724462bcba06cf9d Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Thu, 12 Dec 2024 16:35:01 -0300
Subject: [PATCH 108/114] feat: add e2e tests (#283)
* feat: add tests using playwright
* chore: added github action
---
.github/workflows/e2e.yml | 98 ++++--
.github/workflows/verify.yml | 8 +-
.maestro/w3m-connect-flow.yaml | 12 +-
.maestro/w3m-ui-flow.yaml | 6 +-
apps/native/.github/workflows/playwright.yml | 27 ++
apps/native/.gitignore | 4 +
apps/native/App.tsx | 22 +-
apps/native/app.json | 7 +-
apps/native/package.json | 11 +-
apps/native/playwright.config.ts | 68 +++++
.../src/components/DisconnectButton.tsx | 21 ++
apps/native/src/components/OpenButton.tsx | 22 ++
apps/native/src/utils/ToastUtils.ts | 18 ++
apps/native/src/views/AccountView.tsx | 33 ++-
apps/native/src/views/ActionsView.tsx | 65 +++-
apps/native/tests/basic-tests.spec.ts | 56 ++++
apps/native/tests/shared/constants/index.ts | 11 +
.../native/tests/shared/constants/timeouts.ts | 1 +
.../tests/shared/fixtures/timing-fixture.ts | 11 +
.../tests/shared/fixtures/w3m-fixture.ts | 34 +++
.../shared/fixtures/w3m-wallet-fixture.ts | 99 +++++++
apps/native/tests/shared/pages/ModalPage.ts | 279 ++++++++++++++++++
apps/native/tests/shared/pages/WalletPage.ts | 125 ++++++++
apps/native/tests/shared/types/index.ts | 9 +
apps/native/tests/shared/utils/logs.ts | 17 ++
apps/native/tests/shared/utils/timeouts.ts | 9 +
.../tests/shared/validators/ModalValidator.ts | 165 +++++++++++
.../shared/validators/WalletValidator.ts | 68 +++++
apps/native/tests/wallet.spec.ts | 126 ++++++++
.../controllers/SnackController.test.ts | 3 +
packages/ethers/src/client.ts | 1 +
packages/ethers5/src/client.ts | 1 +
packages/scaffold/src/hooks/useTimeout.ts | 10 +-
.../scaffold/src/modal/w3m-button/index.tsx | 4 +-
.../scaffold/src/modal/w3m-modal/index.tsx | 1 +
.../src/modal/w3m-network-button/index.tsx | 1 +
.../partials/w3m-all-wallets-search/index.tsx | 1 +
.../partials/w3m-connecting-qrcode/index.tsx | 2 +-
.../src/partials/w3m-header/index.tsx | 6 +-
.../views/w3m-account-default-view/index.tsx | 15 +-
.../src/views/w3m-all-wallets-view/index.tsx | 2 +-
.../components/all-wallets-button.tsx | 2 +-
.../w3m-connecting-farcaster-view/index.tsx | 2 +-
.../src/views/w3m-get-wallet-view/index.tsx | 7 +-
.../src/views/w3m-networks-view/index.tsx | 9 +-
.../index.tsx | 2 +-
.../views/w3m-what-is-a-wallet-view/index.tsx | 8 +-
.../views/w3m-connecting-siwe-view/index.tsx | 2 +-
.../src/composites/wui-card-select/index.tsx | 5 +-
.../src/composites/wui-input-text/index.tsx | 2 +-
.../composites/wui-network-button/index.tsx | 5 +-
.../src/composites/wui-search-bar/index.tsx | 5 +-
.../ui/src/composites/wui-snackbar/index.tsx | 7 +-
packages/wagmi/src/client.ts | 1 +
packages/wallet/src/AppKitWebview.tsx | 2 +-
yarn.lock | 165 ++++++++++-
56 files changed, 1604 insertions(+), 99 deletions(-)
create mode 100644 apps/native/.github/workflows/playwright.yml
create mode 100644 apps/native/playwright.config.ts
create mode 100644 apps/native/src/components/DisconnectButton.tsx
create mode 100644 apps/native/src/components/OpenButton.tsx
create mode 100644 apps/native/src/utils/ToastUtils.ts
create mode 100644 apps/native/tests/basic-tests.spec.ts
create mode 100644 apps/native/tests/shared/constants/index.ts
create mode 100644 apps/native/tests/shared/constants/timeouts.ts
create mode 100644 apps/native/tests/shared/fixtures/timing-fixture.ts
create mode 100644 apps/native/tests/shared/fixtures/w3m-fixture.ts
create mode 100644 apps/native/tests/shared/fixtures/w3m-wallet-fixture.ts
create mode 100644 apps/native/tests/shared/pages/ModalPage.ts
create mode 100644 apps/native/tests/shared/pages/WalletPage.ts
create mode 100644 apps/native/tests/shared/types/index.ts
create mode 100644 apps/native/tests/shared/utils/logs.ts
create mode 100644 apps/native/tests/shared/utils/timeouts.ts
create mode 100644 apps/native/tests/shared/validators/ModalValidator.ts
create mode 100644 apps/native/tests/shared/validators/WalletValidator.ts
create mode 100644 apps/native/tests/wallet.spec.ts
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 19617cf19..2d2bf6450 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -1,38 +1,86 @@
-name: e2e
+name: E2E Tests
+
on:
workflow_dispatch:
- pull_request:
- branches:
- - main
+ workflow_call:
+ inputs:
+ branch:
+ description: 'The branch to use'
+ default: 'main'
+ required: false
+ type: string
+ base-url:
+ description: 'The AppKit App url'
+ default: 'http://localhost:8081/'
+ required: false
+ type: string
+ wallet-url:
+ description: 'The wallet url'
+ default: 'https://react-wallet.walletconnect.com/'
+ required: false
+ type: string
+ skip_setup:
+ description: 'Skip setup steps if already done'
+ type: boolean
+ default: false
+ secrets:
+ CLOUD_PROJECT_ID:
+ required: true
jobs:
- maestro-cloud:
+ e2e_tests:
+ name: 'Playwright Tests'
runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: apps/native-cli
- outputs:
- app: app/build/outputs/apk/release
steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Install Java 11
- uses: actions/setup-java@v3
+ - name: checkout
+ if: ${{ !inputs.skip_setup }}
+ uses: actions/checkout@v4
with:
- java-version: 11
- distribution: 'temurin'
- cache: gradle
-
- - run: touch .env && echo "PROJECT_ID=${{ secrets.CLOUD_PROJECT_ID }}" >> .env
+ repository: reown-com/appkit-react-native
+ ref: ${{ inputs.branch }}
- name: Setup
+ if: ${{ !inputs.skip_setup }}
uses: ./.github/actions/setup
- - run: yarn android:build
+ - name: Build SDK
+ if: ${{ !inputs.skip_setup }}
+ run: |
+ echo "Building SDK..."
+ yarn build
+
+ - name: Create ENV file in apps/native
+ working-directory: ./apps/native/
+ run: echo "EXPO_PUBLIC_PROJECT_ID=${{ secrets.CLOUD_PROJECT_ID }}" >> .env
+
+ - name: Install Playwright Browsers
+ working-directory: ./apps/native/
+ run: yarn playwright install chromium
+
+ ## Uncomment to build the web and add ./apps/native/dist to upload the artifact
+ # - name: Build web app
+ # working-directory: ./apps/native/
+ # run: |
+ # echo "Building web app..."
+ # yarn build:web
+
+ - name: Run Playwright tests
+ working-directory: ./apps/native/
+ env:
+ BASE_URL: ${{ inputs.base-url }}
+ WALLET_URL: ${{ inputs.wallet-url }}
+
+ ## Uncomment to see better logs in the terminal
+ # DEBUG: pw:api
+ run: |
+ echo "Running tests against $BASE_URL"
+ yarn playwright:test
- - uses: mobile-dev-inc/action-maestro-cloud@v1
+ - uses: actions/upload-artifact@v4
+ if: failure()
with:
- api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
- app-file: apps/native-cli/android/app/build/outputs/apk/release/app-release.apk
- android-api-level: 31
+ name: playwright-report
+ path: |
+ ./apps/native/playwright-report/
+ ./apps/native/test-results/
+ retention-days: 7
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index f09faad03..95a8d345d 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -22,5 +22,11 @@ jobs:
- name: Build
run: yarn build
- - name: Test
+ - name: Package Tests
run: yarn test
+
+ - name: E2E Tests
+ uses: ./.github/workflows/e2e.yml
+ with:
+ skip_setup: true # Skip redundant setup steps
+ secrets: inherit
diff --git a/.maestro/w3m-connect-flow.yaml b/.maestro/w3m-connect-flow.yaml
index 11cf64d54..155431e5a 100644
--- a/.maestro/w3m-connect-flow.yaml
+++ b/.maestro/w3m-connect-flow.yaml
@@ -9,7 +9,7 @@ appId: com.walletconnect.web3modal.rnclisdk
- tapOn: 'Connect'
- tapOn:
- id: 'button-all-wallets'
+ id: 'all-wallets'
- tapOn:
id: 'button-qr-code'
@@ -18,7 +18,7 @@ appId: com.walletconnect.web3modal.rnclisdk
id: 'qr-code'
- tapOn:
- id: 'button-copy-uri'
+ id: 'copy-link'
- openLink:
link: https://react-wallet.walletconnect.com/walletconnect
@@ -54,10 +54,10 @@ appId: com.walletconnect.web3modal.rnclisdk
- back
- tapOn:
- id: 'button-account'
+ id: 'account-button'
- tapOn:
- id: 'button-network'
+ id: 'w3m-account-select-network'
- tapOn:
text: 'Polygon'
@@ -68,7 +68,7 @@ appId: com.walletconnect.web3modal.rnclisdk
text: 'Polygon'
- tapOn:
- id: 'button-disconnect'
+ id: 'disconnect-button'
- assertVisible:
- id: 'button-connect'
+ id: 'connect-button'
diff --git a/.maestro/w3m-ui-flow.yaml b/.maestro/w3m-ui-flow.yaml
index 465b6bf7e..161afd6bc 100644
--- a/.maestro/w3m-ui-flow.yaml
+++ b/.maestro/w3m-ui-flow.yaml
@@ -19,7 +19,7 @@ appId: com.walletconnect.web3modal.rnclisdk
id: 'button-back'
- tapOn:
- id: 'button-all-wallets'
+ id: 'all-wallets'
- tapOn:
id: 'button-qr-code'
@@ -31,7 +31,7 @@ appId: com.walletconnect.web3modal.rnclisdk
id: 'button-back'
- tapOn:
- id: 'input-search'
+ id: 'search-wallet-input'
# Get a wallet that doesn't come in the first page
- inputText: 'Abra Wallet'
@@ -57,7 +57,7 @@ appId: com.walletconnect.web3modal.rnclisdk
text: 'Open'
- tapOn:
- id: 'button-close'
+ id: 'header-close'
- assertNotVisible:
text: 'Abra Wallet'
diff --git a/apps/native/.github/workflows/playwright.yml b/apps/native/.github/workflows/playwright.yml
new file mode 100644
index 000000000..a94b6417a
--- /dev/null
+++ b/apps/native/.github/workflows/playwright.yml
@@ -0,0 +1,27 @@
+name: Playwright Tests
+on:
+ push:
+ branches: [ main, master ]
+ pull_request:
+ branches: [ main, master ]
+jobs:
+ test:
+ timeout-minutes: 60
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: lts/*
+ - name: Install dependencies
+ run: npm install -g yarn && yarn
+ - name: Install Playwright Browsers
+ run: yarn playwright install --with-deps
+ - name: Run Playwright tests
+ run: yarn playwright test
+ - uses: actions/upload-artifact@v4
+ if: ${{ !cancelled() }}
+ with:
+ name: playwright-report
+ path: playwright-report/
+ retention-days: 30
diff --git a/apps/native/.gitignore b/apps/native/.gitignore
index e8be304f9..502848c55 100644
--- a/apps/native/.gitignore
+++ b/apps/native/.gitignore
@@ -14,3 +14,7 @@ web-build/
.DS_Store
.env
+/test-results/
+/playwright-report/
+/blob-report/
+/playwright/.cache/
diff --git a/apps/native/App.tsx b/apps/native/App.tsx
index ae99f40cf..ea1abcdd9 100644
--- a/apps/native/App.tsx
+++ b/apps/native/App.tsx
@@ -1,9 +1,10 @@
-import { StyleSheet, View, useColorScheme } from 'react-native';
+import { Platform, SafeAreaView, StyleSheet, useColorScheme } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import * as Clipboard from 'expo-clipboard';
import '@walletconnect/react-native-compat';
import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import Toast from 'react-native-toast-message';
import {
AppKit,
@@ -21,6 +22,8 @@ import { AccountView } from './src/views/AccountView';
import { ActionsView } from './src/views/ActionsView';
import { getCustomWallets } from './src/utils/misc';
import { chains } from './src/utils/WagmiUtils';
+import { OpenButton } from './src/components/OpenButton';
+import { DisconnectButton } from './src/components/DisconnectButton';
const projectId = process.env.EXPO_PUBLIC_PROJECT_ID ?? '';
@@ -44,11 +47,17 @@ const clipboardClient = {
const auth = authConnector({ projectId, metadata });
+const extraConnectors = Platform.select({
+ ios: [auth],
+ android: [auth],
+ default: []
+});
+
const wagmiConfig = defaultWagmiConfig({
chains,
projectId,
metadata,
- extraConnectors: [auth]
+ extraConnectors
});
const queryClient = new QueryClient();
@@ -77,7 +86,7 @@ export default function Native() {
return (
-
+
-
+
+
+
-
+
+
);
diff --git a/apps/native/app.json b/apps/native/app.json
index 52c6b4f97..cd0024e83 100644
--- a/apps/native/app.json
+++ b/apps/native/app.json
@@ -74,7 +74,12 @@
}
},
"web": {
- "favicon": "./assets/favicon.png"
+ "favicon": "./assets/favicon.png",
+ "output": "single",
+ "bundler": "metro"
+ },
+ "experiments": {
+ "baseUrl": "."
},
"extra": {
"eas": {
diff --git a/apps/native/package.json b/apps/native/package.json
index e3a094c0c..7afbad09e 100644
--- a/apps/native/package.json
+++ b/apps/native/package.json
@@ -12,7 +12,11 @@
"dev:android": "expo start --android",
"eas:build": "eas build --platform all",
"eas:build:local": "eas build --local --platform all",
- "eas:update": "eas update --branch preview"
+ "eas:update": "eas update --branch preview",
+ "playwright:test": "playwright test",
+ "playwright:install": "playwright install chromium",
+ "deploy": "gh-pages --nojekyll -d dist",
+ "build:web": "expo export -p web"
},
"dependencies": {
"@expo/metro-runtime": "~3.2.3",
@@ -35,6 +39,7 @@
"react-native-get-random-values": "~1.11.0",
"react-native-modal": "13.0.1",
"react-native-svg": "15.2.0",
+ "react-native-toast-message": "2.2.1",
"react-native-web": "~0.19.10",
"react-native-webview": "13.8.6",
"uuid": "3.4.0",
@@ -43,9 +48,13 @@
},
"devDependencies": {
"@babel/core": "^7.24.0",
+ "@playwright/test": "^1.49.1",
+ "@types/gh-pages": "^6",
+ "@types/node": "^22.10.1",
"@types/react": "~18.2.79",
"@types/react-native": "0.72.2",
"babel-plugin-module-resolver": "^5.0.0",
+ "gh-pages": "^6.2.0",
"typescript": "~5.3.3"
}
}
diff --git a/apps/native/playwright.config.ts b/apps/native/playwright.config.ts
new file mode 100644
index 000000000..081c8bed3
--- /dev/null
+++ b/apps/native/playwright.config.ts
@@ -0,0 +1,68 @@
+import { defineConfig, devices } from '@playwright/test';
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// import dotenv from 'dotenv';
+// import path from 'path';
+// dotenv.config({ path: path.resolve(__dirname, '.env') });
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+ testDir: './tests',
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: [['html'], ['list']],
+
+ use: {
+ baseURL: process.env.BASE_URL || 'http://localhost:8081',
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+
+ /* Take a screenshot when the test fails */
+ screenshot: 'only-on-failure',
+
+ permissions: ['clipboard-read', 'clipboard-write'],
+ navigationTimeout: 30000,
+ actionTimeout: 30000,
+ video: 'retain-on-failure'
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'], channel: 'chromium' }
+ }
+ ],
+
+ /* Run your local dev server before starting the tests */
+ webServer: {
+ command: 'yarn web',
+ url: 'http://localhost:8081',
+ reuseExistingServer: !process.env.CI,
+ timeout: 30000
+
+ /* Uncomment to see better logs in the terminal */
+ // stdout: 'pipe',
+ // stderr: 'pipe'
+ },
+
+ globalTimeout: 600000,
+ expect: {
+ timeout: 10000
+ }
+});
diff --git a/apps/native/src/components/DisconnectButton.tsx b/apps/native/src/components/DisconnectButton.tsx
new file mode 100644
index 000000000..d2c002ba7
--- /dev/null
+++ b/apps/native/src/components/DisconnectButton.tsx
@@ -0,0 +1,21 @@
+import { StyleSheet } from 'react-native';
+import { Button } from '@reown/appkit-ui-react-native';
+import { useAccount, useDisconnect } from 'wagmi';
+
+export function DisconnectButton() {
+ const { isConnected } = useAccount();
+ const { disconnect } = useDisconnect();
+
+ return isConnected ? (
+ disconnect()}>
+ Disconnect hook
+
+ ) : null;
+}
+
+const styles = StyleSheet.create({
+ button: {
+ height: 40,
+ marginVertical: 8
+ }
+});
diff --git a/apps/native/src/components/OpenButton.tsx b/apps/native/src/components/OpenButton.tsx
new file mode 100644
index 000000000..c79b2ed9a
--- /dev/null
+++ b/apps/native/src/components/OpenButton.tsx
@@ -0,0 +1,22 @@
+import { StyleSheet } from 'react-native';
+import { Button } from '@reown/appkit-ui-react-native';
+import { useAppKit } from '@reown/appkit-wagmi-react-native';
+import { useAccount } from 'wagmi';
+
+export function OpenButton() {
+ const { open } = useAppKit();
+ const { isConnected } = useAccount();
+
+ return !isConnected ? (
+ open()}>
+ Open hook
+
+ ) : null;
+}
+
+const styles = StyleSheet.create({
+ button: {
+ height: 40,
+ marginVertical: 8
+ }
+});
diff --git a/apps/native/src/utils/ToastUtils.ts b/apps/native/src/utils/ToastUtils.ts
new file mode 100644
index 000000000..178adc04d
--- /dev/null
+++ b/apps/native/src/utils/ToastUtils.ts
@@ -0,0 +1,18 @@
+import Toast from 'react-native-toast-message';
+
+export const ToastUtils = {
+ showSuccessToast: (title: string, message: string) => {
+ Toast.show({
+ type: 'success',
+ text1: title,
+ text2: message
+ });
+ },
+ showErrorToast: (title: string, message: string) => {
+ Toast.show({
+ type: 'error',
+ text1: title,
+ text2: message
+ });
+ }
+};
diff --git a/apps/native/src/views/AccountView.tsx b/apps/native/src/views/AccountView.tsx
index 1f5c8d975..c75c2896b 100644
--- a/apps/native/src/views/AccountView.tsx
+++ b/apps/native/src/views/AccountView.tsx
@@ -1,5 +1,5 @@
-import { View } from 'react-native';
-import { Text } from '@reown/appkit-ui-react-native';
+import { StyleSheet } from 'react-native';
+import { Text, FlexView } from '@reown/appkit-ui-react-native';
import { useAccount, useBalance } from 'wagmi';
export function AccountView() {
@@ -7,15 +7,28 @@ export function AccountView() {
const { data, isLoading } = useBalance({ address });
return isConnected ? (
-
- Wagmi Account Info
- {isConnected && {address}}
- {isLoading && Fetching balance...}
+
+ Wagmi Account Info
+
+ Address:
+ {isConnected && {address}}
+
+ {isLoading && Fetching balance...}
{data && (
-
- Balance: {data?.formatted} {data?.symbol}
-
+
+ Balance:
+
+ {data?.formatted} {data?.symbol}
+
+
)}
-
+
) : null;
}
+
+const styles = StyleSheet.create({
+ container: {
+ marginTop: 32,
+ gap: 8
+ }
+});
diff --git a/apps/native/src/views/ActionsView.tsx b/apps/native/src/views/ActionsView.tsx
index 39cb70c22..ba284e2b0 100644
--- a/apps/native/src/views/ActionsView.tsx
+++ b/apps/native/src/views/ActionsView.tsx
@@ -1,39 +1,76 @@
-import { Button, Text } from '@reown/appkit-ui-react-native';
-import { View } from 'react-native';
+import { Button, Text, FlexView } from '@reown/appkit-ui-react-native';
+import { StyleSheet } from 'react-native';
import { useSignMessage, useAccount, useSendTransaction, useEstimateGas } from 'wagmi';
import { Hex, parseEther } from 'viem';
+import { SendTransactionData, SignMessageData } from 'wagmi/query';
+import { ToastUtils } from '../utils/ToastUtils';
export function ActionsView() {
const { isConnected } = useAccount();
- const { data, isError, isPending, isSuccess, signMessage } = useSignMessage();
+
+ const onSignSuccess = (data: SignMessageData) => {
+ ToastUtils.showSuccessToast('Signature successful', data);
+ };
+
+ const onSignError = (error: Error) => {
+ ToastUtils.showErrorToast('Signature failed', error.message);
+ };
+
+ const onSendSuccess = (data: SendTransactionData) => {
+ ToastUtils.showSuccessToast('Transaction successful', data);
+ };
+
+ const onSendError = (error: Error) => {
+ ToastUtils.showErrorToast('Transaction failed', error.message);
+ };
+
+ const { isPending, signMessage } = useSignMessage({
+ mutation: {
+ onSuccess: onSignSuccess,
+ onError: onSignError
+ }
+ });
const TX = {
- to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' as Hex, // vitalik.eth
+ to: '0x704457b418E9Fb723e1Bc0cB98106a6B8Cf87689' as Hex, // Test wallet
value: parseEther('0.001'),
data: '0x' as Hex
};
+
const { data: gas, isError: isGasError } = useEstimateGas(TX);
const {
- data: sendData,
isPending: isSending,
- isSuccess: isSendSuccess,
+
sendTransaction
- } = useSendTransaction();
+ } = useSendTransaction({
+ mutation: {
+ onSuccess: onSendSuccess,
+ onError: onSendError
+ }
+ });
return isConnected ? (
-
- Wagmi Actions
- signMessage({ message: 'Hello AppKit!' })}>
+
+ Wagmi Actions
+ signMessage({ message: 'Hello AppKit!' })}
+ >
Sign
- {isSuccess && Signature: {data}}
{isGasError && Error estimating gas}
- {isError && Error signing message}
sendTransaction({ ...TX, gas })}>
Send
{isSending && Check Wallet}
- {isSendSuccess && Transaction: {JSON.stringify(sendData)}}
-
+
) : null;
}
+
+const styles = StyleSheet.create({
+ container: {
+ marginTop: 16,
+ gap: 8
+ }
+});
diff --git a/apps/native/tests/basic-tests.spec.ts b/apps/native/tests/basic-tests.spec.ts
new file mode 100644
index 000000000..22eacb035
--- /dev/null
+++ b/apps/native/tests/basic-tests.spec.ts
@@ -0,0 +1,56 @@
+import { test, BrowserContext, Page } from '@playwright/test';
+import { ModalPage } from './shared/pages/ModalPage';
+import { ModalValidator } from './shared/validators/ModalValidator';
+
+const METAMASK_WALLET_ID = 'c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96';
+
+let context: BrowserContext;
+let browserPage: Page;
+let modalPage: ModalPage;
+let modalValidator: ModalValidator;
+
+test.beforeAll(async ({ browser }) => {
+ context = await browser.newContext();
+ browserPage = await context.newPage();
+
+ modalPage = new ModalPage(browserPage);
+ modalValidator = new ModalValidator(modalPage.page);
+
+ await modalPage.load();
+});
+
+test('Should be able to open modal', async () => {
+ await modalPage.openConnectModal();
+ await modalValidator.expectConnectScreen();
+ await modalPage.closeModal();
+});
+
+test('Should be able to open network view', async () => {
+ await modalPage.openNetworkModal();
+ await modalValidator.expectNetworkScreen();
+ await modalPage.closeModal();
+});
+
+test('Should be able to open modal with the open hook', async () => {
+ const openHookButton = modalPage.page.getByTestId('open-hook-button');
+ await openHookButton.click();
+ await modalValidator.expectConnectScreen();
+ await modalPage.closeModal();
+});
+
+test('it should display what is a wallet view', async () => {
+ await modalPage.openConnectModal();
+ await modalValidator.expectWhatIsAWalletButton();
+ await modalPage.clickWhatIsAWalletButton();
+ await modalValidator.expectWhatIsAWalletView();
+ await modalPage.clickGetAWalletButton();
+ await modalValidator.expectGetAWalletView();
+ await modalPage.closeModal();
+});
+
+test('it should search for a wallet', async () => {
+ await modalPage.openConnectModal();
+ await modalValidator.expectConnectScreen();
+ await modalPage.searchWalletFlow(modalPage, 'MetaMask', METAMASK_WALLET_ID);
+ await modalPage.closeModal();
+});
diff --git a/apps/native/tests/shared/constants/index.ts b/apps/native/tests/shared/constants/index.ts
new file mode 100644
index 000000000..dc2550fef
--- /dev/null
+++ b/apps/native/tests/shared/constants/index.ts
@@ -0,0 +1,11 @@
+import type { SessionParams } from '../types';
+
+// Allow localhost
+export const BASE_URL = process.env.BASE_URL || 'http://localhost:8081/';
+export const WALLET_URL = process.env.WALLET_URL || 'https://react-wallet.walletconnect.com/';
+export const DEFAULT_SESSION_PARAMS: SessionParams = {
+ reqAccounts: ['1', '2'],
+ optAccounts: ['1', '2'],
+ accept: true
+};
+export const DEFAULT_CHAIN_NAME = process.env.DEFAULT_CHAIN_NAME || 'Ethereum';
diff --git a/apps/native/tests/shared/constants/timeouts.ts b/apps/native/tests/shared/constants/timeouts.ts
new file mode 100644
index 000000000..03ff123ce
--- /dev/null
+++ b/apps/native/tests/shared/constants/timeouts.ts
@@ -0,0 +1 @@
+export const MAXIMUM_WAIT_CONNECTIONS = 30 * 1000;
diff --git a/apps/native/tests/shared/fixtures/timing-fixture.ts b/apps/native/tests/shared/fixtures/timing-fixture.ts
new file mode 100644
index 000000000..5c4d3d2bd
--- /dev/null
+++ b/apps/native/tests/shared/fixtures/timing-fixture.ts
@@ -0,0 +1,11 @@
+import { test as base } from '@playwright/test';
+
+export type TimingRecords = { item: string; timeMs: number }[];
+
+export interface TimingFixture {
+ timingRecords: TimingRecords;
+}
+
+export const timingFixture = base.extend({
+ timingRecords: []
+});
diff --git a/apps/native/tests/shared/fixtures/w3m-fixture.ts b/apps/native/tests/shared/fixtures/w3m-fixture.ts
new file mode 100644
index 000000000..86e6ab924
--- /dev/null
+++ b/apps/native/tests/shared/fixtures/w3m-fixture.ts
@@ -0,0 +1,34 @@
+/* eslint no-console: 0 */
+
+import { ModalPage } from '../pages/ModalPage';
+import { timeStart, timeEnd } from '../utils/logs';
+import { timingFixture } from './timing-fixture';
+
+// Declare the types of fixtures to use
+export interface ModalFixture {
+ modalPage: ModalPage;
+ library: string;
+}
+
+// M -> test Modal
+export const testM = timingFixture.extend({
+ modalPage: async ({ page }, use) => {
+ timeStart('new ModalPage');
+ const modalPage = new ModalPage(page);
+ timeEnd('new ModalPage');
+ timeStart('modalPage.load');
+ await modalPage.load();
+ timeEnd('modalPage.load');
+ await use(modalPage);
+ }
+});
+
+export const testMSiwe = timingFixture.extend({
+ modalPage: async ({ page }, use) => {
+ const modalPage = new ModalPage(page);
+ await modalPage.load();
+ await use(modalPage);
+ }
+});
+
+export { expect } from '@playwright/test';
diff --git a/apps/native/tests/shared/fixtures/w3m-wallet-fixture.ts b/apps/native/tests/shared/fixtures/w3m-wallet-fixture.ts
new file mode 100644
index 000000000..ba2bd8ddb
--- /dev/null
+++ b/apps/native/tests/shared/fixtures/w3m-wallet-fixture.ts
@@ -0,0 +1,99 @@
+/* eslint no-console: 0 */
+
+import { testM as base, testMSiwe as siwe } from './w3m-fixture';
+import { WalletPage } from '../pages/WalletPage';
+import { WalletValidator } from '../validators/WalletValidator';
+
+import { DEFAULT_SESSION_PARAMS } from '../constants';
+import { timeEnd, timeStart } from '../utils/logs';
+
+// Declare the types of fixtures to use
+interface ModalWalletFixture {
+ walletPage: WalletPage;
+ walletValidator: WalletValidator;
+}
+
+// MW -> test Modal + Wallet
+export const testConnectedMW = base.extend({
+ walletPage: async ({ context, modalPage, timingRecords }, use) => {
+ // Setup
+ let pairingCreatedTime: Date | null = null;
+ let verificationStartedTime: Date | null = null;
+
+ timeStart('new WalletPage');
+ const walletPage = new WalletPage(await context.newPage());
+ timeEnd('new WalletPage');
+
+ walletPage.page.on('console', msg => {
+ if (msg.text().includes('set') && msg.text().includes('core/pairing/pairing')) {
+ pairingCreatedTime = new Date();
+ }
+ if (msg.text().includes('resolving attestation')) {
+ verificationStartedTime = new Date();
+ }
+ if (msg.text().includes('session_proposal') && msg.text().includes('verifyContext')) {
+ // For some reason this log is emitted twice; so only recording the time once
+ if (verificationStartedTime) {
+ const verificationEndedTime = new Date();
+ timingRecords.push({
+ item: 'sessionProposalVerification',
+ timeMs: verificationEndedTime.getTime() - verificationStartedTime.getTime()
+ });
+ verificationStartedTime = null;
+ }
+ }
+ });
+
+ timeStart('walletPage.load');
+ await walletPage.load();
+ timeEnd('walletPage.load');
+
+ // Initiate connection
+ timeStart('modalPage.getConnectUri');
+ const uri = await modalPage.getConnectUri(timingRecords);
+ timeEnd('modalPage.getConnectUri');
+
+ timeStart('walletPage.connectWithUri');
+ await walletPage.connectWithUri(uri);
+ timeEnd('walletPage.connectWithUri');
+
+ const connectionInitiated = new Date();
+
+ // Handle session proposal
+ timeStart('walletPage.handleSessionProposal');
+ await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS);
+ timeEnd('walletPage.handleSessionProposal');
+
+ const proposalReceived = new Date();
+
+ timingRecords.push({
+ item: 'receiveSessionProposal',
+ timeMs: proposalReceived.getTime() - connectionInitiated.getTime()
+ });
+
+ if (pairingCreatedTime) {
+ timingRecords.push({
+ item: 'pairingReceiveSessionProposal',
+ timeMs: proposalReceived.getTime() - (pairingCreatedTime as Date).getTime()
+ });
+ }
+
+ const walletValidator = new WalletValidator(walletPage.page);
+
+ timeStart('walletValidator.expectConnected');
+ await walletValidator.expectConnected();
+ timeEnd('walletValidator.expectConnected');
+
+ await use(walletPage);
+ }
+});
+
+export const testMWSiwe = siwe.extend({
+ walletPage: async ({ context }, use) => {
+ const walletPage = new WalletPage(await context.newPage());
+ await walletPage.load();
+ await use(walletPage);
+ }
+});
+
+export { expect } from '@playwright/test';
diff --git a/apps/native/tests/shared/pages/ModalPage.ts b/apps/native/tests/shared/pages/ModalPage.ts
new file mode 100644
index 000000000..a8840f21a
--- /dev/null
+++ b/apps/native/tests/shared/pages/ModalPage.ts
@@ -0,0 +1,279 @@
+import type { Locator, Page } from '@playwright/test';
+import { expect } from '@playwright/test';
+import { BASE_URL, DEFAULT_SESSION_PARAMS } from '../constants';
+import { WalletValidator } from '../validators/WalletValidator';
+import { WalletPage } from './WalletPage';
+import { TimingRecords } from '../types';
+import { ModalValidator } from '../validators/ModalValidator';
+
+export class ModalPage {
+ private readonly connectButton: Locator;
+ private readonly url: string;
+
+ constructor(public readonly page: Page) {
+ this.connectButton = this.page.getByTestId('connect-button');
+ this.url = BASE_URL;
+ }
+
+ async load() {
+ await this.page.goto(this.url);
+ }
+
+ assertDefined(value: T | undefined | null): T {
+ expect(value).toBeDefined();
+
+ return value!;
+ }
+
+ async getConnectUri(timingRecords?: TimingRecords): Promise {
+ await this.connectButton.click();
+ await this.openAllWallets();
+ await this.openQrCodeView();
+ const qrLoadInitiatedTime = new Date();
+
+ const qrCode = this.page.getByTestId('qr-code');
+ await expect(qrCode).toBeVisible();
+ const uri = await this.clickCopyLink();
+
+ const qrLoadedTime = new Date();
+ if (timingRecords) {
+ timingRecords.push({
+ item: 'qrLoad',
+ timeMs: qrLoadedTime.getTime() - qrLoadInitiatedTime.getTime()
+ });
+ }
+
+ return uri;
+ }
+
+ async getImmidiateConnectUri(timingRecords?: TimingRecords): Promise {
+ await this.connectButton.click();
+ const qrLoadInitiatedTime = new Date();
+
+ const qrCode = this.page.getByTestId('qr-code');
+ await expect(qrCode).toBeVisible();
+ const uri = await this.clickCopyLink();
+ const qrLoadedTime = new Date();
+ if (timingRecords) {
+ timingRecords.push({
+ item: 'qrLoad',
+ timeMs: qrLoadedTime.getTime() - qrLoadInitiatedTime.getTime()
+ });
+ }
+
+ return uri;
+ }
+
+ async qrCodeFlow(page: ModalPage, walletPage: WalletPage, immediate?: boolean): Promise {
+ let uri: string;
+ await walletPage.load();
+ if (immediate) {
+ uri = await page.getImmidiateConnectUri();
+ } else {
+ uri = await page.getConnectUri();
+ }
+ await walletPage.connectWithUri(uri);
+
+ await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS);
+ const walletValidator = new WalletValidator(walletPage.page);
+ await walletValidator.expectConnected();
+ }
+
+ async searchWalletFlow(page: ModalPage, walletName: string, walletId: string) {
+ await this.openAllWallets();
+ await this.search(walletName);
+ await this.page.waitForTimeout(1000);
+ const modalValidator = new ModalValidator(page.page);
+ await modalValidator.expectAllWalletsListSearchItem(walletId);
+ }
+
+ async disconnect() {
+ const accountBtn = this.page.getByTestId('account-button');
+ await expect(accountBtn, 'Account button should be visible').toBeVisible();
+ await expect(accountBtn, 'Account button should be enabled').toBeEnabled();
+ await accountBtn.click();
+ const disconnectBtn = this.page.getByTestId('disconnect-button');
+ await expect(disconnectBtn, 'Disconnect button should be visible').toBeVisible();
+ await expect(disconnectBtn, 'Disconnect button should be enabled').toBeEnabled();
+ await disconnectBtn.click();
+ }
+
+ async sign() {
+ const signButton = this.page.getByTestId('sign-message-button');
+ await signButton.scrollIntoViewIfNeeded();
+ await signButton.click();
+ }
+
+ async clickWhatIsAWalletButton() {
+ await this.page.getByTestId('help-button').click();
+ }
+
+ async clickGetAWalletButton() {
+ await this.page.getByTestId('get-a-wallet-button').click();
+ }
+
+ // async promptSiwe() {
+ // const siweSign = this.page.getByTestId('w3m-connecting-siwe-sign');
+ // await expect(siweSign, 'Siwe prompt sign button should be visible').toBeVisible({
+ // timeout: 10_000
+ // });
+ // await expect(siweSign, 'Siwe prompt sign button should be enabled').toBeEnabled();
+ // await siweSign.click();
+ // }
+
+ // async cancelSiwe() {
+ // await this.page.getByTestId('w3m-connecting-siwe-cancel').click();
+ // }
+
+ async switchNetwork(network: string) {
+ await this.openAccountModal();
+ await this.page.getByTestId('w3m-account-select-network').click();
+ await this.page.getByTestId(`w3m-network-switch-${network}`).click();
+ // The state is chaing too fast and test runner doesn't wait the loading page. It's fastly checking the network selection button and detect that it's switched already.
+ await this.page.waitForTimeout(300);
+ }
+
+ // async clickWalletDeeplink() {
+ // await this.connectButton.click();
+ // await this.page.getByTestId('wallet-selector-react-wallet-v2').click();
+ // await this.page.getByTestId('tab-desktop').click();
+ // }
+
+ async openAccountModal() {
+ await this.page.getByTestId('account-button').click();
+ }
+
+ async openConnectModal() {
+ await this.page.getByTestId('connect-button').click();
+ }
+
+ async openNetworkModal() {
+ await this.page.getByTestId('network-button').click();
+ }
+
+ async closeModal() {
+ await this.page.getByTestId('header-close')?.click?.();
+ // Wait for the modal fade out animation
+ await this.page.waitForTimeout(300);
+ }
+
+ // async switchNetworkWithNetworkButton(networkName: string) {
+ // const networkButton = this.page.getByTestId('wui-network-button');
+ // await networkButton.click();
+
+ // const networkToSwitchButton = this.page.getByTestId(`w3m-network-switch-${networkName}`);
+ // await networkToSwitchButton.click();
+ // }
+
+ async openAllWallets() {
+ const allWallets = this.page.getByTestId('all-wallets');
+ await expect(allWallets, 'All wallets should be visible').toBeVisible();
+ await allWallets.click();
+ }
+
+ async openQrCodeView() {
+ const qrCodeButton = this.page.getByTestId('button-qr-code');
+ await expect(qrCodeButton, 'QR code view should be visible').toBeVisible();
+ await qrCodeButton.click();
+ }
+
+ // async clickAllWalletsListSearchItem(id: string) {
+ // const allWalletsListSearchItem = this.page.getByTestId(`wallet-search-item-${id}`);
+ // await expect(allWalletsListSearchItem).toBeVisible();
+ // await allWalletsListSearchItem.click();
+ // }
+
+ // async clickTabWebApp() {
+ // const tabWebApp = this.page.getByTestId('tab-webapp');
+ // await expect(tabWebApp).toBeVisible();
+ // await tabWebApp.click();
+ // }
+
+ async clickHookDisconnectButton() {
+ const disconnectHookButton = this.page.getByTestId('disconnect-hook-button');
+ await expect(disconnectHookButton).toBeVisible();
+ await disconnectHookButton.click();
+ }
+
+ async clickCopyLink() {
+ const copyLink = this.page.getByTestId('copy-link');
+ await expect(copyLink).toBeVisible();
+
+ let hasCopied = false;
+
+ while (!hasCopied) {
+ await copyLink.click();
+ await this.page.waitForTimeout(500);
+
+ const snackbarMessage = this.page.getByTestId('wui-snackbar-message');
+ const snackbarMessageText = await snackbarMessage.textContent();
+
+ if (snackbarMessageText && snackbarMessageText.startsWith('Link copied')) {
+ hasCopied = true;
+ }
+ }
+
+ return this.page.evaluate(() => navigator.clipboard.readText());
+ }
+
+ // async clickOpenWebApp() {
+ // let url = '';
+
+ // const openButton = this.page.getByTestId('w3m-connecting-widget-secondary-button');
+ // await expect(openButton).toBeVisible();
+ // await expect(openButton).toHaveText('Open');
+
+ // while (!url) {
+ // await openButton.click();
+ // await this.page.waitForTimeout(500);
+
+ // const pages = this.page.context().pages();
+
+ // // Check if more than 1 tab is open
+ // if (pages.length > 1) {
+ // const lastTab = pages[pages.length - 1];
+
+ // if (lastTab) {
+ // url = lastTab.url();
+ // break;
+ // }
+ // }
+ // }
+
+ // return url;
+ // }
+
+ async search(value: string) {
+ const searchInput = this.page.getByTestId('wui-input-text');
+ await expect(searchInput, 'Search input should be visible').toBeVisible();
+ await searchInput.click();
+ await searchInput.fill(value);
+ }
+
+ async openNetworks() {
+ await this.page.getByTestId('w3m-account-select-network').click();
+ await expect(this.page.getByText('Select network')).toBeVisible();
+ }
+
+ // async openProfileView() {
+ // await this.page.getByTestId('wui-profile-button').click();
+ // }
+
+ // async getAddress(): Promise<`0x${string}`> {
+ // const address = await this.page.getByTestId('w3m-address').textContent();
+ // expect(address, 'Address should be present').toBeTruthy();
+
+ // return address as `0x${string}`;
+ // }
+
+ // async getChainId(): Promise {
+ // const chainId = await this.page.getByTestId('w3m-chain-id').textContent();
+ // expect(chainId, 'Chain ID should be present').toBeTruthy();
+
+ // return Number(chainId);
+ // }
+
+ // async switchNetworkWithHook() {
+ // await this.page.getByTestId('switch-network-hook-button').click();
+ // }
+}
diff --git a/apps/native/tests/shared/pages/WalletPage.ts b/apps/native/tests/shared/pages/WalletPage.ts
new file mode 100644
index 000000000..49f5a2038
--- /dev/null
+++ b/apps/native/tests/shared/pages/WalletPage.ts
@@ -0,0 +1,125 @@
+import { expect, type Locator, type Page } from '@playwright/test';
+import { WALLET_URL } from '../constants';
+import type { SessionParams } from '../types';
+
+export class WalletPage {
+ private readonly baseURL = WALLET_URL;
+
+ private gotoHome: Locator;
+ private vercelPreview: Locator;
+
+ public connectToSingleAccount = false;
+
+ constructor(public page: Page) {
+ this.gotoHome = this.page.getByTestId('wc-connect');
+ this.vercelPreview = this.page.locator('css=vercel-live-feedback');
+ }
+
+ async load() {
+ await this.page.goto(this.baseURL);
+ }
+
+ loadNewPage(page: Page) {
+ this.page = page;
+ this.gotoHome = this.page.getByTestId('wc-connect');
+ this.vercelPreview = this.page.locator('css=vercel-live-feedback');
+ }
+
+ /**
+ * Connect by inserting provided URI into the input element
+ */
+
+ async connectWithUri(uri: string) {
+ const isVercelPreview = (await this.vercelPreview.count()) > 0;
+ if (isVercelPreview) {
+ await this.vercelPreview.evaluate((iframe: HTMLIFrameElement) => iframe.remove());
+ }
+ /*
+ * If connecting to a single account manually navigate.
+ * Otherwise click the home button.
+ */
+ if (this.connectToSingleAccount) {
+ await this.page.goto(`${this.baseURL}/walletconnect?addressesToApprove=1`);
+ } else {
+ await this.gotoHome.click();
+ }
+ const input = this.page.getByTestId('uri-input');
+ await input.waitFor({
+ state: 'visible',
+ timeout: 5000
+ });
+ await input.fill(uri);
+ const connectButton = this.page.getByTestId('uri-connect-button');
+ await expect(connectButton, 'Connect button should be enabled').toBeEnabled({
+ timeout: 5000
+ });
+ await connectButton.click();
+ }
+
+ /**
+ * Handle a session proposal event in the wallet
+ * @param reqAccounts - required account numbers to select ex/ ['1', '2']
+ * @param optAccounts - optional account numbers to select ex/ ['1', '2']
+ * @param accept - accept or reject the session
+ */
+ async handleSessionProposal(opts: SessionParams) {
+ const variant = opts.accept ? `approve` : `reject`;
+ // `.click` doesn't work here, so we use `.focus` and `Space`
+ await this.performRequestAction(variant);
+ }
+
+ async handleRequest({ accept }: { accept: boolean }) {
+ const variant = accept ? `approve` : `reject`;
+ // `.click` doesn't work here, so we use `.focus` and `Space`
+ await this.performRequestAction(variant);
+ }
+
+ async performRequestAction(variant: string) {
+ await this.page.waitForLoadState();
+ const btn = this.page.getByTestId(`session-${variant}-button`);
+ await expect(btn, `Session ${variant} element should be visible`).toBeVisible({
+ timeout: 30000
+ });
+ await expect(btn).toBeEnabled();
+ await btn.focus();
+ await this.page.keyboard.press('Space');
+ }
+
+ /**
+ * Enables testnets in the wallet settings
+ */
+ async enableTestnets() {
+ await this.page.waitForLoadState();
+ const settingsButton = this.page.getByTestId('settings');
+ await settingsButton.click();
+ const testnetSwitch = this.page.getByTestId('settings-toggle-testnets');
+ await testnetSwitch.click();
+ expect(testnetSwitch).toHaveAttribute('data-state', 'checked');
+ }
+
+ /**
+ * Switches the network in the wallet
+ * @param network the network id to switch (e.g. eip155:1 for Ethereum Mainnet)
+ */
+ async switchNetwork(network: string) {
+ await this.page.waitForLoadState();
+ const networkButton = this.page.getByTestId('accounts');
+ await networkButton.click();
+ const switchNetworkButton = this.page.getByTestId(`chain-switch-button${network}`);
+ await switchNetworkButton.click();
+ await expect(switchNetworkButton).toHaveText('✅');
+ }
+
+ /**
+ * Disconnects the current connection in the wallet
+ */
+ async disconnectConnection() {
+ await this.page.waitForLoadState();
+ const sessionsButton = this.page.getByTestId('sessions');
+ await sessionsButton.click();
+ const sessionCard = this.page.getByTestId(`session-card`);
+ await sessionCard.click();
+ const disconnectButton = this.page.getByText('Delete');
+ await disconnectButton.click();
+ }
+}
diff --git a/apps/native/tests/shared/types/index.ts b/apps/native/tests/shared/types/index.ts
new file mode 100644
index 000000000..abf6bc54f
--- /dev/null
+++ b/apps/native/tests/shared/types/index.ts
@@ -0,0 +1,9 @@
+export interface SessionParams {
+ reqAccounts: string[];
+ optAccounts: string[];
+ accept: boolean;
+}
+
+export type TimingRecords = { item: string; timeMs: number }[];
+
+export type CaipNetworkId = `${string}:${string}`;
diff --git a/apps/native/tests/shared/utils/logs.ts b/apps/native/tests/shared/utils/logs.ts
new file mode 100644
index 000000000..7bb561477
--- /dev/null
+++ b/apps/native/tests/shared/utils/logs.ts
@@ -0,0 +1,17 @@
+/* eslint no-console: 0 */
+
+const TIMING_LOGS_ENABLED = process.env.TIMING_LOGS === 'true' || false;
+
+export function timeStart(label?: string | undefined) {
+ if (!TIMING_LOGS_ENABLED) {
+ return;
+ }
+ console.time(label);
+}
+
+export function timeEnd(label?: string | undefined) {
+ if (!TIMING_LOGS_ENABLED) {
+ return;
+ }
+ console.timeEnd(label);
+}
diff --git a/apps/native/tests/shared/utils/timeouts.ts b/apps/native/tests/shared/utils/timeouts.ts
new file mode 100644
index 000000000..a74e5eee4
--- /dev/null
+++ b/apps/native/tests/shared/utils/timeouts.ts
@@ -0,0 +1,9 @@
+import { MAXIMUM_WAIT_CONNECTIONS } from '../constants/timeouts';
+
+export function getMaximumWaitConnections(): number {
+ if (process.env.CI) {
+ return MAXIMUM_WAIT_CONNECTIONS;
+ }
+
+ return MAXIMUM_WAIT_CONNECTIONS * 2;
+}
diff --git a/apps/native/tests/shared/validators/ModalValidator.ts b/apps/native/tests/shared/validators/ModalValidator.ts
new file mode 100644
index 000000000..d27de8fbe
--- /dev/null
+++ b/apps/native/tests/shared/validators/ModalValidator.ts
@@ -0,0 +1,165 @@
+import { expect } from '@playwright/test';
+import type { Page } from '@playwright/test';
+import { getMaximumWaitConnections } from '../utils/timeouts';
+
+const MAX_WAIT = getMaximumWaitConnections();
+
+export class ModalValidator {
+ constructor(public readonly page: Page) {}
+
+ async expectConnected() {
+ const accountButton = this.page.getByTestId('account-button');
+ await expect(accountButton, 'Account button should be present').toBeAttached({
+ timeout: MAX_WAIT
+ });
+ await expect(
+ this.page.getByTestId('connect-button'),
+ 'Connect button should not be present'
+ ).toBeHidden({
+ timeout: MAX_WAIT
+ });
+ await this.page.waitForTimeout(500);
+ }
+
+ async expectBalanceFetched(currency: 'SOL' | 'ETH') {
+ const accountButton = this.page.getByTestId('account-button');
+ await expect(accountButton, `Account button should show balance as ${currency}`).toContainText(
+ `0.000 ${currency}`
+ );
+ }
+
+ async expectAuthenticated() {
+ await expect(
+ this.page.getByTestId('w3m-authentication-status'),
+ 'Authentication status should be: authenticated'
+ ).toContainText('authenticated');
+ }
+
+ async expectOnSignInEventCalled(toBe: boolean) {
+ await expect(this.page.getByTestId('siwe-event-onSignIn')).toContainText(`${toBe}`);
+ }
+
+ async expectUnauthenticated() {
+ await expect(
+ this.page.getByTestId('w3m-authentication-status'),
+ 'Authentication status should be: unauthenticated'
+ ).toContainText('unauthenticated');
+ }
+
+ async expectOnSignOutEventCalled(toBe: boolean) {
+ await expect(this.page.getByTestId('siwe-event-onSignOut')).toContainText(`${toBe}`);
+ }
+
+ async expectSignatureDeclined() {
+ await expect(
+ this.page.getByText('Signature declined'),
+ 'Signature declined should be visible'
+ ).toBeVisible();
+ }
+
+ async expectDisconnected() {
+ await expect(
+ this.page.getByTestId('connect-button'),
+ 'Connect button should be present'
+ ).toBeVisible({
+ timeout: MAX_WAIT
+ });
+ }
+
+ async expectConnectScreen() {
+ await expect(this.page.getByText('Connect wallet')).toBeVisible({
+ timeout: MAX_WAIT
+ });
+ }
+
+ async expectNetworkScreen() {
+ await expect(this.page.getByTestId('what-is-a-network-button')).toBeVisible();
+ }
+
+ async expectAddress(expectedAddress: string) {
+ const address = this.page.getByTestId('w3m-address');
+
+ await expect(address, 'Correct address should be present').toHaveText(expectedAddress);
+ }
+
+ // async expectNetwork(network: string) {
+ // const networkButton = this.page.getByTestId('w3m-account-select-network');
+ // await expect(networkButton, `Network button should contain text ${network}`).toHaveText(
+ // network,
+ // {
+ // timeout: 5000
+ // }
+ // );
+ // }
+
+ async expectAcceptedSign() {
+ await expect(this.page.getByText('Signature successful')).toBeVisible({
+ timeout: 30 * 1000
+ });
+ }
+
+ async expectRejectedSign() {
+ await expect(this.page.getByText('Signature failed')).toBeVisible();
+ }
+
+ async expectSwitchedNetwork(network: string) {
+ const switchNetworkButton = this.page.getByTestId(`w3m-account-select-network-text`);
+ await expect(switchNetworkButton).toContainText(network);
+ }
+
+ async expectAllWalletsListSearchItem(id: string) {
+ const allWalletsListSearchItem = this.page.getByTestId(`wallet-search-item-${id}`);
+ await expect(allWalletsListSearchItem).toBeVisible();
+ }
+
+ async expectAllWallets() {
+ const allWallets = this.page.getByTestId('all-wallets');
+ await expect(allWallets).toBeVisible();
+ }
+
+ async expectWhatIsAWalletButton() {
+ const whatIsAWalletButton = this.page.getByTestId('help-button');
+ await expect(whatIsAWalletButton).toBeVisible();
+ }
+
+ async expectWhatIsAWalletView() {
+ const whatIsAWalletView = this.page.getByTestId('what-is-a-wallet-view');
+ await expect(whatIsAWalletView).toBeVisible();
+ }
+
+ async expectGetAWalletView() {
+ const getAWalletView = this.page.getByTestId('get-a-wallet-view');
+ await expect(getAWalletView).toBeVisible();
+ }
+
+ // async expectHeaderText(text: string) {
+ // const headerText = this.page.getByTestId('header-text');
+ // await expect(headerText).toHaveText(text);
+ // }
+
+ async expectNetworksDisabled(name: string) {
+ const disabledNetworkButton = this.page.getByTestId(`w3m-network-switch-${name}`);
+ disabledNetworkButton.click();
+ await expect(this.page.getByText('Select network')).toBeVisible();
+ }
+
+ async expectToBeConnectedInstantly() {
+ const accountButton = this.page.getByTestId('account-button');
+ await expect(accountButton, 'Account button should be present').toBeAttached({
+ timeout: 1000
+ });
+ }
+
+ async expectModalNotVisible() {
+ const modal = this.page.getByTestId('w3m-modal');
+ await expect(modal).toBeHidden({
+ timeout: 2000
+ });
+ }
+
+ // async expectSnackbar(message: string) {
+ // await expect(this.page.getByTestId('wui-snackbar-message')).toHaveText(message, {
+ // timeout: MAX_WAIT
+ // });
+ // }
+}
diff --git a/apps/native/tests/shared/validators/WalletValidator.ts b/apps/native/tests/shared/validators/WalletValidator.ts
new file mode 100644
index 000000000..c6e292e58
--- /dev/null
+++ b/apps/native/tests/shared/validators/WalletValidator.ts
@@ -0,0 +1,68 @@
+import { expect } from '@playwright/test';
+import type { Locator, Page } from '@playwright/test';
+import { getMaximumWaitConnections } from '../utils/timeouts';
+
+const MAX_WAIT = getMaximumWaitConnections();
+
+export class WalletValidator {
+ private gotoSessions: Locator;
+
+ constructor(public page: Page) {
+ this.gotoSessions = this.page.getByTestId('sessions');
+ }
+
+ loadNewPage(page: Page) {
+ this.page = page;
+ this.gotoSessions = this.page.getByTestId('sessions');
+ }
+
+ async expectConnected() {
+ await expect(
+ this.gotoSessions,
+ 'Approve screen should be closed and sessions tab visible'
+ ).toBeVisible();
+ await this.gotoSessions.click();
+ await this.expectSessionCard({ visible: true });
+ }
+
+ async expectSessionCard({ visible = true }: { visible?: boolean }) {
+ if (visible) {
+ await expect(
+ this.page.getByTestId('session-card'),
+ 'Session card should be visible'
+ ).toBeVisible({
+ timeout: MAX_WAIT
+ });
+ } else {
+ await expect(
+ this.page.getByTestId('session-card'),
+ 'Session card should not be visible'
+ ).not.toBeVisible({
+ timeout: MAX_WAIT
+ });
+ }
+ }
+
+ async expectDisconnected() {
+ await this.gotoSessions.click();
+ await expect(
+ this.page.getByTestId('session-card'),
+ 'Session card should not be visible'
+ ).not.toBeVisible({
+ timeout: MAX_WAIT
+ });
+ }
+
+ async expectReceivedSign({ chainName = 'Ethereum' }) {
+ await expect(
+ this.page.getByTestId('session-approve-button'),
+ 'Session approve button should be visible'
+ ).toBeVisible({
+ timeout: MAX_WAIT
+ });
+ await expect(
+ this.page.getByTestId('request-details-chain'),
+ 'Request details should contain chain name'
+ ).toContainText(chainName);
+ }
+}
diff --git a/apps/native/tests/wallet.spec.ts b/apps/native/tests/wallet.spec.ts
new file mode 100644
index 000000000..6f5eb68ca
--- /dev/null
+++ b/apps/native/tests/wallet.spec.ts
@@ -0,0 +1,126 @@
+import { test, type BrowserContext } from '@playwright/test';
+import { WalletPage } from './shared/pages/WalletPage';
+import { WalletValidator } from './shared/validators/WalletValidator';
+import { ModalPage } from './shared/pages/ModalPage';
+import { ModalValidator } from './shared/validators/ModalValidator';
+import { DEFAULT_CHAIN_NAME } from './shared/constants';
+
+let modalPage: ModalPage;
+let modalValidator: ModalValidator;
+let walletPage: WalletPage;
+let walletValidator: WalletValidator;
+let context: BrowserContext;
+
+// -- Setup --------------------------------------------------------------------
+const sampleWalletTest = test.extend<{ library: string }>({
+ library: ['wagmi', { option: true }]
+});
+
+sampleWalletTest.describe.configure({ mode: 'serial' });
+
+sampleWalletTest.beforeAll(async ({ browser }) => {
+ context = await browser.newContext();
+ const browserPage = await context.newPage();
+
+ modalPage = new ModalPage(browserPage);
+ walletPage = new WalletPage(await context.newPage());
+ modalValidator = new ModalValidator(browserPage);
+ walletValidator = new WalletValidator(walletPage.page);
+
+ await modalPage.load();
+ await modalPage.qrCodeFlow(modalPage, walletPage);
+ await modalValidator.expectConnected();
+});
+
+sampleWalletTest.afterAll(async () => {
+ await modalPage.page.close();
+});
+
+// -- Tests --------------------------------------------------------------------
+sampleWalletTest('it should be connected instantly after page refresh', async () => {
+ await modalPage.page.reload();
+ await modalValidator.expectToBeConnectedInstantly();
+});
+
+sampleWalletTest('it should show disabled networks', async () => {
+ const disabledNetworks = 'Gnosis';
+ await modalPage.openAccountModal();
+ await modalPage.openNetworks();
+ await modalValidator.expectNetworksDisabled(disabledNetworks);
+ await modalPage.closeModal();
+});
+
+sampleWalletTest('it should switch networks and sign', async () => {
+ const chains = ['Polygon', 'Ethereum'];
+
+ async function processChain(index: number) {
+ if (index >= chains.length) {
+ return;
+ }
+
+ const chainName = chains[index] ?? DEFAULT_CHAIN_NAME;
+
+ // -- Switch network --------------------------------------------------------
+ const chainNameOnWalletPage = chainName;
+ await modalPage.switchNetwork(chainName);
+ await modalValidator.expectSwitchedNetwork(chainName);
+ await modalPage.closeModal();
+
+ // -- Sign ------------------------------------------------------------------
+ await modalPage.sign();
+ await walletValidator.expectReceivedSign({ chainName: chainNameOnWalletPage });
+ await walletPage.handleRequest({ accept: true });
+ await modalValidator.expectAcceptedSign();
+
+ await processChain(index + 1);
+ }
+
+ // Start processing from the first chain
+ await processChain(0);
+});
+
+sampleWalletTest('it should show last connected network after refreshing', async () => {
+ const chainName = 'Polygon';
+
+ await modalPage.switchNetwork(chainName);
+ await modalValidator.expectSwitchedNetwork(chainName);
+ await modalPage.closeModal();
+
+ await modalPage.page.reload();
+
+ await modalPage.openAccountModal();
+ await modalValidator.expectSwitchedNetwork(chainName);
+ await modalPage.closeModal();
+});
+
+sampleWalletTest('it should reject sign', async () => {
+ const chainName = 'Polygon';
+ await modalPage.sign();
+ await walletValidator.expectReceivedSign({ chainName });
+ await walletPage.handleRequest({ accept: false });
+ await modalValidator.expectRejectedSign();
+});
+
+sampleWalletTest('it should disconnect using hook', async () => {
+ await modalValidator.expectConnected();
+ await modalPage.clickHookDisconnectButton();
+ await modalValidator.expectDisconnected();
+});
+
+sampleWalletTest('it should disconnect and close modal when connecting from wallet', async () => {
+ await modalValidator.expectDisconnected();
+ await modalPage.qrCodeFlow(modalPage, walletPage);
+ await modalValidator.expectConnected();
+ await modalPage.openAccountModal();
+ await walletPage.disconnectConnection();
+ await walletValidator.expectSessionCard({ visible: false });
+ await modalValidator.expectModalNotVisible();
+ await walletPage.page.waitForTimeout(500);
+});
+
+sampleWalletTest('it should disconnect as expected', async () => {
+ await modalPage.qrCodeFlow(modalPage, walletPage);
+ await modalValidator.expectConnected();
+ await modalPage.disconnect();
+ await modalValidator.expectDisconnected();
+});
diff --git a/packages/core/src/__tests__/controllers/SnackController.test.ts b/packages/core/src/__tests__/controllers/SnackController.test.ts
index 6a9aad79c..ec10a043b 100644
--- a/packages/core/src/__tests__/controllers/SnackController.test.ts
+++ b/packages/core/src/__tests__/controllers/SnackController.test.ts
@@ -3,6 +3,9 @@ import { OptionsController, SnackController } from '../../index';
// Setup
OptionsController.state.debug = true;
+// eslint-disable-next-line no-console
+console.error = jest.fn();
+
// -- Tests --------------------------------------------------------------------
describe('SnackController', () => {
it('should have valid default state', () => {
diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts
index 79c0370f4..0e564e183 100644
--- a/packages/ethers/src/client.ts
+++ b/packages/ethers/src/client.ts
@@ -703,6 +703,7 @@ export class AppKit extends AppKitScaffold {
]);
this.hasSyncedConnectedAccount = true;
} else if (!isConnected && this.hasSyncedConnectedAccount) {
+ this.close();
this.resetAccount();
this.resetWcConnection();
this.resetNetwork();
diff --git a/packages/ethers5/src/client.ts b/packages/ethers5/src/client.ts
index 0f48b56e1..23f42933c 100644
--- a/packages/ethers5/src/client.ts
+++ b/packages/ethers5/src/client.ts
@@ -683,6 +683,7 @@ export class AppKit extends AppKitScaffold {
]);
this.hasSyncedConnectedAccount = true;
} else if (!isConnected && this.hasSyncedConnectedAccount) {
+ this.close();
this.resetAccount();
this.resetWcConnection();
this.resetNetwork();
diff --git a/packages/scaffold/src/hooks/useTimeout.ts b/packages/scaffold/src/hooks/useTimeout.ts
index e99448a0c..90e027955 100644
--- a/packages/scaffold/src/hooks/useTimeout.ts
+++ b/packages/scaffold/src/hooks/useTimeout.ts
@@ -13,13 +13,19 @@ function useTimeout(delay: number) {
timeLeftRef.current -= 1;
setTimeLeft(timeLeftRef.current);
} else {
- clearInterval(interval.current);
+ if (typeof interval.current === 'number') {
+ clearInterval(interval.current);
+ }
}
}, 1000);
}, []);
useEffect(() => {
- return () => clearInterval(interval.current);
+ return () => {
+ if (typeof interval.current === 'number') {
+ clearInterval(interval.current);
+ }
+ };
}, [interval]);
return { timeLeft, startTimer };
diff --git a/packages/scaffold/src/modal/w3m-button/index.tsx b/packages/scaffold/src/modal/w3m-button/index.tsx
index 830655db2..e6bf0481d 100644
--- a/packages/scaffold/src/modal/w3m-button/index.tsx
+++ b/packages/scaffold/src/modal/w3m-button/index.tsx
@@ -30,7 +30,7 @@ export function AppKitButton({
style={accountStyle}
balance={balance}
disabled={disabled}
- testID="button-account"
+ testID="account-button"
/>
) : (
);
}
diff --git a/packages/scaffold/src/modal/w3m-modal/index.tsx b/packages/scaffold/src/modal/w3m-modal/index.tsx
index d4a9c4cae..036d6a576 100644
--- a/packages/scaffold/src/modal/w3m-modal/index.tsx
+++ b/packages/scaffold/src/modal/w3m-modal/index.tsx
@@ -128,6 +128,7 @@ export function AppKit() {
onModalHide={handleClose}
onBackdropPress={ModalController.close}
onBackButtonPress={onBackButtonPress}
+ testID="w3m-modal"
>
diff --git a/packages/scaffold/src/modal/w3m-network-button/index.tsx b/packages/scaffold/src/modal/w3m-network-button/index.tsx
index 89f25b6bb..ddffa20f2 100644
--- a/packages/scaffold/src/modal/w3m-network-button/index.tsx
+++ b/packages/scaffold/src/modal/w3m-network-button/index.tsx
@@ -36,6 +36,7 @@ export function NetworkButton({ disabled, style }: NetworkButtonProps) {
style={style}
onPress={onNetworkPress}
loading={loading}
+ testID="network-button"
>
{caipNetwork?.name ?? (isConnected ? 'Unknown Network' : 'Select Network')}
diff --git a/packages/scaffold/src/partials/w3m-all-wallets-search/index.tsx b/packages/scaffold/src/partials/w3m-all-wallets-search/index.tsx
index 2e08ba2e0..172f3b09c 100644
--- a/packages/scaffold/src/partials/w3m-all-wallets-search/index.tsx
+++ b/packages/scaffold/src/partials/w3m-all-wallets-search/index.tsx
@@ -49,6 +49,7 @@ export function AllWalletsSearch({
name={item?.name ?? 'Unknown'}
onPress={() => onItemPress(item)}
installed={!!isInstalled}
+ testID={`wallet-search-item-${item?.id}`}
/>
);
diff --git a/packages/scaffold/src/partials/w3m-connecting-qrcode/index.tsx b/packages/scaffold/src/partials/w3m-connecting-qrcode/index.tsx
index e887b7b1b..3a035706b 100644
--- a/packages/scaffold/src/partials/w3m-connecting-qrcode/index.tsx
+++ b/packages/scaffold/src/partials/w3m-connecting-qrcode/index.tsx
@@ -65,7 +65,7 @@ export function ConnectingQrCode() {
color="fg-200"
style={styles.copyButton}
onPress={onCopyAddress}
- testID="button-copy-uri"
+ testID="copy-link"
>
Copy link
diff --git a/packages/scaffold/src/partials/w3m-header/index.tsx b/packages/scaffold/src/partials/w3m-header/index.tsx
index 6f280bd72..846272c83 100644
--- a/packages/scaffold/src/partials/w3m-header/index.tsx
+++ b/packages/scaffold/src/partials/w3m-header/index.tsx
@@ -107,7 +107,7 @@ export function Header() {
return showBack ? (
) : (
-
+
);
};
@@ -123,10 +123,10 @@ export function Header() {
padding={['l', 'xl', bottomPadding, 'xl']}
>
{dynamicButtonTemplate()}
-
+
{header}
-
+
);
}
diff --git a/packages/scaffold/src/views/w3m-account-default-view/index.tsx b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
index 8988f3ed8..22b90082b 100644
--- a/packages/scaffold/src/views/w3m-account-default-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-account-default-view/index.tsx
@@ -158,7 +158,12 @@ export function AccountDefaultView() {
{showBack && (
)}
-
+
@@ -227,10 +232,10 @@ export function AccountDefaultView() {
imageSrc={networkImage}
imageHeaders={ApiController._getApiHeaders()}
onPress={onNetworkPress}
- testID="button-network"
+ testID="w3m-account-select-network"
style={styles.actionButton}
>
-
+
{caipNetwork?.name}
@@ -252,7 +257,7 @@ export function AccountDefaultView() {
chevron
icon="swapHorizontal"
onPress={onSwitchAccountType}
- testID="button-account-type"
+ testID="account-button-type"
style={styles.actionButton}
loading={loading}
>
@@ -266,7 +271,7 @@ export function AccountDefaultView() {
onPress={onDisconnect}
loading={disconnecting}
iconBackgroundColor="gray-glass-010"
- testID="button-disconnect"
+ testID="disconnect-button"
>
Disconnect
diff --git a/packages/scaffold/src/views/w3m-all-wallets-view/index.tsx b/packages/scaffold/src/views/w3m-all-wallets-view/index.tsx
index 287c7bd95..bd8a76245 100644
--- a/packages/scaffold/src/views/w3m-all-wallets-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-all-wallets-view/index.tsx
@@ -62,7 +62,7 @@ export function AllWalletsView() {
{ backgroundColor: Theme['bg-100'], shadowColor: Theme['bg-100'], width: maxWidth }
]}
>
-
+
);
}
diff --git a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
index ce726591f..fd7cb308d 100644
--- a/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-connecting-farcaster-view/index.tsx
@@ -129,7 +129,7 @@ export function ConnectingFarcasterView() {
color="fg-200"
style={styles.copyButton}
onPress={onCopyUrl}
- testID="button-copy-uri"
+ testID="copy-link"
>
Copy link
diff --git a/packages/scaffold/src/views/w3m-get-wallet-view/index.tsx b/packages/scaffold/src/views/w3m-get-wallet-view/index.tsx
index 0295b6e78..3cc7478a1 100644
--- a/packages/scaffold/src/views/w3m-get-wallet-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-get-wallet-view/index.tsx
@@ -30,7 +30,12 @@ export function GetWalletView() {
};
return (
-
+
{listTemplate()}
Your connected wallet may not support some of the networks available for this dApp
-
+
What is a network?
diff --git a/packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/index.tsx b/packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/index.tsx
index fc6e96913..ce042b10f 100644
--- a/packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-upgrade-to-smart-account-view/index.tsx
@@ -67,7 +67,7 @@ export function UpgradeToSmartAccountView() {
icon="close"
size="md"
onPress={onClose}
- testID="button-close"
+ testID="header-close"
style={styles.closeButton}
/>
diff --git a/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx b/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx
index 953af32ce..17cdcc556 100644
--- a/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx
+++ b/packages/scaffold/src/views/w3m-what-is-a-wallet-view/index.tsx
@@ -13,7 +13,12 @@ export function WhatIsAWalletView() {
};
return (
-
+
@@ -53,6 +58,7 @@ export function WhatIsAWalletView() {
iconLeft="walletSmall"
style={styles.getWalletButton}
onPress={onGetWalletPress}
+ testID="get-a-wallet-button"
>
Get a wallet
diff --git a/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx b/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx
index db9825873..e5a56f950 100644
--- a/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx
+++ b/packages/siwe/src/scaffold/views/w3m-connecting-siwe-view/index.tsx
@@ -90,7 +90,7 @@ export function ConnectingSiweView() {
icon="close"
size="md"
onPress={onCancel}
- testID="button-close"
+ testID="header-close"
style={styles.closeButton}
/>
diff --git a/packages/ui/src/composites/wui-card-select/index.tsx b/packages/ui/src/composites/wui-card-select/index.tsx
index 3c9a2c8e8..fd4f50458 100644
--- a/packages/ui/src/composites/wui-card-select/index.tsx
+++ b/packages/ui/src/composites/wui-card-select/index.tsx
@@ -25,6 +25,7 @@ export interface CardSelectProps {
type?: CardSelectType;
onPress?: () => void;
style?: StyleProp;
+ testID?: string;
}
function _CardSelect({
@@ -36,7 +37,8 @@ function _CardSelect({
disabled,
installed,
selected,
- style
+ style,
+ testID
}: CardSelectProps) {
const Theme = useTheme();
const normalbackgroundColor = getBackgroundColor({ selected, disabled, pressed: false });
@@ -77,6 +79,7 @@ function _CardSelect({
onPressOut={setStartValue}
disabled={disabled}
style={[styles.container, { backgroundColor: animatedValue }, style]}
+ testID={testID}
>
(
style={[styles.outerBorder, { borderColor: outerBorder, borderRadius: outerRadius }]}
disabled={disabled}
onPress={() => inputRef.current?.focus()}
- testID={rest.testID}
>
(
underlineColorAndroid="transparent"
selectTextOnFocus={false}
editable={!disabled}
+ testID="wui-input-text"
{...rest}
/>
{children}
diff --git a/packages/ui/src/composites/wui-network-button/index.tsx b/packages/ui/src/composites/wui-network-button/index.tsx
index b5c37a01a..53a6a1e5b 100644
--- a/packages/ui/src/composites/wui-network-button/index.tsx
+++ b/packages/ui/src/composites/wui-network-button/index.tsx
@@ -19,6 +19,7 @@ export interface NetworkButtonProps {
imageHeaders?: Record;
loading?: boolean;
style?: StyleProp;
+ testID?: string;
}
export function NetworkButton({
@@ -29,7 +30,8 @@ export function NetworkButton({
imageSrc,
imageHeaders,
loading,
- style
+ style,
+ testID
}: NetworkButtonProps) {
const Theme = useTheme();
const textColor = disabled ? 'fg-300' : 'fg-100';
@@ -49,6 +51,7 @@ export function NetworkButton({
onPressIn={setEndValue}
onPressOut={setStartValue}
disabled={disabled}
+ testID={testID}
>
(null);
@@ -38,7 +36,6 @@ export function SearchBar({
inputStyle={inputStyle}
returnKeyType="search"
disableFullscreenUI
- testID={testID}
>
{showClear && (
-
+
{message}
diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts
index eb5d42c79..0fde4faed 100644
--- a/packages/wagmi/src/client.ts
+++ b/packages/wagmi/src/client.ts
@@ -419,6 +419,7 @@ export class AppKit extends AppKitScaffold {
]);
this.hasSyncedConnectedAccount = true;
} else if (!isConnected && this.hasSyncedConnectedAccount) {
+ this.close();
this.resetAccount();
this.resetWcConnection();
this.resetNetwork();
diff --git a/packages/wallet/src/AppKitWebview.tsx b/packages/wallet/src/AppKitWebview.tsx
index bbbd648c0..6682daab3 100644
--- a/packages/wallet/src/AppKitWebview.tsx
+++ b/packages/wallet/src/AppKitWebview.tsx
@@ -84,7 +84,7 @@ export function AppKitWebview() {
icon="close"
size="md"
onPress={onClose}
- testID="button-close"
+ testID="header-close"
style={styles.closeButton}
iconColor="inverse-100"
backgroundColor="gray-glass-030"
diff --git a/yarn.lock b/yarn.lock
index a619a74b6..6cb7d561f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -96,6 +96,7 @@ __metadata:
dependencies:
"@babel/core": "npm:^7.24.0"
"@expo/metro-runtime": "npm:~3.2.3"
+ "@playwright/test": "npm:^1.49.1"
"@react-native-async-storage/async-storage": "npm:1.23.1"
"@react-native-community/netinfo": "npm:11.3.1"
"@reown/appkit-auth-wagmi-react-native": "npm:1.0.2"
@@ -103,6 +104,8 @@ __metadata:
"@tanstack/query-async-storage-persister": "npm:^5.40.0"
"@tanstack/react-query": "npm:5.56.2"
"@tanstack/react-query-persist-client": "npm:5.56.2"
+ "@types/gh-pages": "npm:^6"
+ "@types/node": "npm:^22.10.1"
"@types/react": "npm:~18.2.79"
"@types/react-native": "npm:0.72.2"
"@walletconnect/react-native-compat": "npm:2.17.1"
@@ -112,12 +115,14 @@ __metadata:
expo-clipboard: "npm:~6.0.3"
expo-status-bar: "npm:~1.12.1"
expo-updates: "npm:~0.25.21"
+ gh-pages: "npm:^6.2.0"
react: "npm:18.2.0"
react-dom: "npm:18.2.0"
react-native: "npm:0.74.3"
react-native-get-random-values: "npm:~1.11.0"
react-native-modal: "npm:13.0.1"
react-native-svg: "npm:15.2.0"
+ react-native-toast-message: "npm:2.2.1"
react-native-web: "npm:~0.19.10"
react-native-webview: "npm:13.8.6"
typescript: "npm:~5.3.3"
@@ -5826,6 +5831,17 @@ __metadata:
languageName: node
linkType: hard
+"@playwright/test@npm:^1.49.1":
+ version: 1.49.1
+ resolution: "@playwright/test@npm:1.49.1"
+ dependencies:
+ playwright: "npm:1.49.1"
+ bin:
+ playwright: cli.js
+ checksum: 2fca0bb7b334f7a23c7c5dfa5dbe37b47794c56f39b747c8d74a2f95c339e7902a296f2f1dd32c47bdd723cfa92cee05219f1a5876725dc89a1871b9137a286d
+ languageName: node
+ linkType: hard
+
"@react-native-async-storage/async-storage@npm:1.23.1":
version: 1.23.1
resolution: "@react-native-async-storage/async-storage@npm:1.23.1"
@@ -8083,6 +8099,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/gh-pages@npm:^6":
+ version: 6.1.0
+ resolution: "@types/gh-pages@npm:6.1.0"
+ checksum: d8bf644822df211accac9cff24fcc0a5155fd715d05bc1698175623f5cde1aff81c302e7e38f7105e0fa0fe7ab24d7009d8dbb875897af669f48e06c3c20484c
+ languageName: node
+ linkType: hard
+
"@types/graceful-fs@npm:^4.1.3":
version: 4.1.6
resolution: "@types/graceful-fs@npm:4.1.6"
@@ -8240,6 +8263,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/node@npm:^22.10.1":
+ version: 22.10.1
+ resolution: "@types/node@npm:22.10.1"
+ dependencies:
+ undici-types: "npm:~6.20.0"
+ checksum: 0fbb6d29fa35d807f0223a4db709c598ac08d66820240a2cd6a8a69b8f0bc921d65b339d850a666b43b4e779f967e6ed6cf6f0fca3575e08241e6b900364c234
+ languageName: node
+ linkType: hard
+
"@types/parse-json@npm:^4.0.0":
version: 4.0.0
resolution: "@types/parse-json@npm:4.0.0"
@@ -10011,6 +10043,13 @@ __metadata:
languageName: node
linkType: hard
+"async@npm:^3.2.4":
+ version: 3.2.6
+ resolution: "async@npm:3.2.6"
+ checksum: 36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70
+ languageName: node
+ linkType: hard
+
"asynckit@npm:^0.4.0":
version: 0.4.0
resolution: "asynckit@npm:0.4.0"
@@ -11255,6 +11294,13 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:^11.0.0":
+ version: 11.1.0
+ resolution: "commander@npm:11.1.0"
+ checksum: 13cc6ac875e48780250f723fb81c1c1178d35c5decb1abb1b628b3177af08a8554e76b2c0f29de72d69eef7c864d12613272a71fabef8047922bc622ab75a179
+ languageName: node
+ linkType: hard
+
"commander@npm:^2.20.0":
version: 2.20.3
resolution: "commander@npm:2.20.3"
@@ -12284,6 +12330,13 @@ __metadata:
languageName: node
linkType: hard
+"email-addresses@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "email-addresses@npm:5.0.0"
+ checksum: fc8a6f84e378bbe601ce39a3d8d86bc7e4584030ae9eb1938e12943f7fb5207e5fd7ae449cced3bea70968a519ade560d55ca170208c3f1413d7d25d8613a577
+ languageName: node
+ linkType: hard
+
"emittery@npm:^0.13.1":
version: 0.13.1
resolution: "emittery@npm:0.13.1"
@@ -12704,7 +12757,7 @@ __metadata:
languageName: node
linkType: hard
-"escape-string-regexp@npm:^1.0.5":
+"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5":
version: 1.0.5
resolution: "escape-string-regexp@npm:1.0.5"
checksum: a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371
@@ -13753,6 +13806,24 @@ __metadata:
languageName: node
linkType: hard
+"filename-reserved-regex@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "filename-reserved-regex@npm:2.0.0"
+ checksum: 453740b7f9fd126e508da555b37e38c1f7ff19f5e9f3d297b2de1beb09854957baddd74c83235e87b16e9ce27a2368798896669edad5a81b5b7bd8cb57c942fc
+ languageName: node
+ linkType: hard
+
+"filenamify@npm:^4.3.0":
+ version: 4.3.0
+ resolution: "filenamify@npm:4.3.0"
+ dependencies:
+ filename-reserved-regex: "npm:^2.0.0"
+ strip-outer: "npm:^1.0.1"
+ trim-repeated: "npm:^1.0.0"
+ checksum: dcfd2f116d66f78c9dd58bb0f0d9b6529d89c801a9f37a4f86e7adc0acecb6881c7fb7c3231dc9e6754b767edcfdca89cba3a492a58afd2b48479b30d14ccf8f
+ languageName: node
+ linkType: hard
+
"filesize@npm:^10.0.12":
version: 10.1.6
resolution: "filesize@npm:10.1.6"
@@ -14059,6 +14130,17 @@ __metadata:
languageName: node
linkType: hard
+"fs-extra@npm:^11.1.1":
+ version: 11.2.0
+ resolution: "fs-extra@npm:11.2.0"
+ dependencies:
+ graceful-fs: "npm:^4.2.0"
+ jsonfile: "npm:^6.0.1"
+ universalify: "npm:^2.0.0"
+ checksum: d77a9a9efe60532d2e790e938c81a02c1b24904ef7a3efb3990b835514465ba720e99a6ea56fd5e2db53b4695319b644d76d5a0e9988a2beef80aa7b1da63398
+ languageName: node
+ linkType: hard
+
"fs-extra@npm:^7.0.1":
version: 7.0.1
resolution: "fs-extra@npm:7.0.1"
@@ -14125,7 +14207,7 @@ __metadata:
languageName: node
linkType: hard
-"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2":
+"fsevents@npm:2.3.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2":
version: 2.3.2
resolution: "fsevents@npm:2.3.2"
dependencies:
@@ -14135,7 +14217,7 @@ __metadata:
languageName: node
linkType: hard
-"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin":
+"fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin":
version: 2.3.2
resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1"
dependencies:
@@ -14293,6 +14375,24 @@ __metadata:
languageName: node
linkType: hard
+"gh-pages@npm:^6.2.0":
+ version: 6.2.0
+ resolution: "gh-pages@npm:6.2.0"
+ dependencies:
+ async: "npm:^3.2.4"
+ commander: "npm:^11.0.0"
+ email-addresses: "npm:^5.0.0"
+ filenamify: "npm:^4.3.0"
+ find-cache-dir: "npm:^3.3.1"
+ fs-extra: "npm:^11.1.1"
+ globby: "npm:^11.1.0"
+ bin:
+ gh-pages: bin/gh-pages.js
+ gh-pages-clean: bin/gh-pages-clean.js
+ checksum: 30b996b3a9c3dc00d333b6fb15232b3ddc8628f9f458de871ad237b4e3414e68f5408d7525d82ae4a551e24bd7461f009908e8db7c7031dc7dc51e62e7c18ac0
+ languageName: node
+ linkType: hard
+
"github-slugger@npm:^2.0.0":
version: 2.0.0
resolution: "github-slugger@npm:2.0.0"
@@ -19068,6 +19168,30 @@ __metadata:
languageName: node
linkType: hard
+"playwright-core@npm:1.49.1":
+ version: 1.49.1
+ resolution: "playwright-core@npm:1.49.1"
+ bin:
+ playwright-core: cli.js
+ checksum: 990b619c75715cd98b2c10c1180a126e3a454b247063b8352bc67792fe01183ec07f31d30c8714c3768cefed12886d1d64ac06da701f2baafc2cad9b439e3919
+ languageName: node
+ linkType: hard
+
+"playwright@npm:1.49.1":
+ version: 1.49.1
+ resolution: "playwright@npm:1.49.1"
+ dependencies:
+ fsevents: "npm:2.3.2"
+ playwright-core: "npm:1.49.1"
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ bin:
+ playwright: cli.js
+ checksum: 2368762c898920d4a0a5788b153dead45f9c36c3f5cf4d2af5228d0b8ea65823e3bbe998877950a2b9bb23a211e4633996f854c6188769dc81a25543ac818ab5
+ languageName: node
+ linkType: hard
+
"plist@npm:^3.0.5":
version: 3.1.0
resolution: "plist@npm:3.1.0"
@@ -19856,6 +19980,16 @@ __metadata:
languageName: node
linkType: hard
+"react-native-toast-message@npm:2.2.1":
+ version: 2.2.1
+ resolution: "react-native-toast-message@npm:2.2.1"
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ checksum: 03418b03ae345f5fe1c1747a98ae9c420a9ea37402d849920a14bfc6eb01541ad934266ae2656433604448d2fba1266ab6f6be649a49c9b22445e86444c1f6de
+ languageName: node
+ linkType: hard
+
"react-native-url-polyfill@npm:2.0.0":
version: 2.0.0
resolution: "react-native-url-polyfill@npm:2.0.0"
@@ -21504,6 +21638,15 @@ __metadata:
languageName: node
linkType: hard
+"strip-outer@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "strip-outer@npm:1.0.1"
+ dependencies:
+ escape-string-regexp: "npm:^1.0.2"
+ checksum: c0f38e6f37563d878a221b1c76f0822f180ec5fc39be5ada30ee637a7d5b59d19418093bad2b4db1e69c40d7a7a7ac50828afce07276cf3d51ac8965cb140dfb
+ languageName: node
+ linkType: hard
+
"strnum@npm:^1.0.5":
version: 1.0.5
resolution: "strnum@npm:1.0.5"
@@ -21964,6 +22107,15 @@ __metadata:
languageName: node
linkType: hard
+"trim-repeated@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "trim-repeated@npm:1.0.0"
+ dependencies:
+ escape-string-regexp: "npm:^1.0.2"
+ checksum: 89acada0142ed0cdb113615a3e82fdb09e7fdb0e3504ded62762dd935bc27debfcc38edefa497dc7145d8dc8602d40dd9eec891e0ea6c28fa0cc384200b692db
+ languageName: node
+ linkType: hard
+
"ts-api-utils@npm:^1.3.0":
version: 1.3.0
resolution: "ts-api-utils@npm:1.3.0"
@@ -22425,6 +22577,13 @@ __metadata:
languageName: node
linkType: hard
+"undici-types@npm:~6.20.0":
+ version: 6.20.0
+ resolution: "undici-types@npm:6.20.0"
+ checksum: 68e659a98898d6a836a9a59e6adf14a5d799707f5ea629433e025ac90d239f75e408e2e5ff086afc3cace26f8b26ee52155293564593fbb4a2f666af57fc59bf
+ languageName: node
+ linkType: hard
+
"unenv@npm:^1.8.0":
version: 1.9.0
resolution: "unenv@npm:1.9.0"
From 007909cec165f2d62ad8274f0bd6b5f58407c0b9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 16 Dec 2024 10:26:53 -0300
Subject: [PATCH 109/114] chore(deps): bump nanoid from 3.3.6 to 3.3.8 (#284)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.6 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.6...3.3.8)
---
updated-dependencies:
- dependency-name: nanoid
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
yarn.lock | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 6cb7d561f..ca6ac19ae 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -18107,21 +18107,12 @@ __metadata:
languageName: node
linkType: hard
-"nanoid@npm:^3.3.6":
- version: 3.3.6
- resolution: "nanoid@npm:3.3.6"
- bin:
- nanoid: bin/nanoid.cjs
- checksum: 606b355960d0fcbe3d27924c4c52ef7d47d3b57208808ece73279420d91469b01ec1dce10fae512b6d4a8c5a5432b352b228336a8b2202a6ea68e67fa348e2ee
- languageName: node
- linkType: hard
-
-"nanoid@npm:^3.3.7":
- version: 3.3.7
- resolution: "nanoid@npm:3.3.7"
+"nanoid@npm:^3.3.6, nanoid@npm:^3.3.7":
+ version: 3.3.8
+ resolution: "nanoid@npm:3.3.8"
bin:
nanoid: bin/nanoid.cjs
- checksum: e3fb661aa083454f40500473bb69eedb85dc160e763150b9a2c567c7e9ff560ce028a9f833123b618a6ea742e311138b591910e795614a629029e86e180660f3
+ checksum: 4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120
languageName: node
linkType: hard
From c28fcb94cea5e212d3030c7c17869b9371f188d2 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 17 Dec 2024 11:51:28 -0300
Subject: [PATCH 110/114] chore: wrapped authview in memo (#285)
* chore: wrapped authview in memo
---
.github/workflows/verify.yml | 6 -----
apps/native/.github/workflows/playwright.yml | 27 --------------------
package.json | 2 +-
packages/wallet/src/AppKitAuthWebview.tsx | 7 +++--
4 files changed, 6 insertions(+), 36 deletions(-)
delete mode 100644 apps/native/.github/workflows/playwright.yml
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 95a8d345d..b2629a578 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -24,9 +24,3 @@ jobs:
- name: Package Tests
run: yarn test
-
- - name: E2E Tests
- uses: ./.github/workflows/e2e.yml
- with:
- skip_setup: true # Skip redundant setup steps
- secrets: inherit
diff --git a/apps/native/.github/workflows/playwright.yml b/apps/native/.github/workflows/playwright.yml
deleted file mode 100644
index a94b6417a..000000000
--- a/apps/native/.github/workflows/playwright.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: Playwright Tests
-on:
- push:
- branches: [ main, master ]
- pull_request:
- branches: [ main, master ]
-jobs:
- test:
- timeout-minutes: 60
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: lts/*
- - name: Install dependencies
- run: npm install -g yarn && yarn
- - name: Install Playwright Browsers
- run: yarn playwright install --with-deps
- - name: Run Playwright tests
- run: yarn playwright test
- - uses: actions/upload-artifact@v4
- if: ${{ !cancelled() }}
- with:
- name: playwright-report
- path: playwright-report/
- retention-days: 30
diff --git a/package.json b/package.json
index 0392016c5..7dbaf2c12 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"clean": "turbo clean && rm -rf node_modules && watchman watch-del-all",
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\" --ignore-path .gitignore",
"changeset:prepublish": "yarn run clean; yarn install; yarn version:update; yarn run lint && yarn run prettier; yarn run build; yarn run test;",
- "changeset:publish": "yarn run changeset:prepublish; yarn run changeset publish",
+ "changeset:publish": "yarn run changeset:prepublish; yarn run changeset publish --no-git-tag",
"changeset:version": "changeset version; yarn run version:update; yarn install --refresh-lockfile",
"version:update": "./scripts/bump-version.sh"
},
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index cd477f99c..34544f271 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -1,5 +1,5 @@
import { useSnapshot } from 'valtio';
-import { useEffect, useRef, useState } from 'react';
+import { memo, useEffect, useRef, useState } from 'react';
import { Animated, Appearance, Linking, Platform, SafeAreaView, StyleSheet } from 'react-native';
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
@@ -24,7 +24,7 @@ import type { AppKitFrameTypes } from './AppKitFrameTypes';
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
-export function AuthWebview() {
+function _AuthWebview() {
const webviewRef = useRef(null);
const Theme = useTheme();
const authConnector = ConnectorController.getAuthConnector();
@@ -176,6 +176,7 @@ export function AuthWebview() {
containerStyle={styles.webview}
injectedJavaScript={AppKitFrameConstants.FRAME_MESSAGES_HANDLER}
ref={webviewRef}
+ webviewDebuggingEnabled
onOpenWindow={syntheticEvent => {
const { nativeEvent } = syntheticEvent;
const { targetUrl } = nativeEvent;
@@ -217,6 +218,8 @@ export function AuthWebview() {
) : null;
}
+export const AuthWebview = memo(_AuthWebview);
+
const styles = StyleSheet.create({
backdrop: {
position: 'absolute',
From f8a95489558d38cf61b192542396bcb55e7c533d Mon Sep 17 00:00:00 2001
From: ignaciosantise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 17 Dec 2024 12:34:58 -0300
Subject: [PATCH 111/114] chore: removed debug flag from webview
---
packages/wallet/src/AppKitAuthWebview.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/wallet/src/AppKitAuthWebview.tsx b/packages/wallet/src/AppKitAuthWebview.tsx
index 34544f271..a7d20567a 100644
--- a/packages/wallet/src/AppKitAuthWebview.tsx
+++ b/packages/wallet/src/AppKitAuthWebview.tsx
@@ -176,7 +176,6 @@ function _AuthWebview() {
containerStyle={styles.webview}
injectedJavaScript={AppKitFrameConstants.FRAME_MESSAGES_HANDLER}
ref={webviewRef}
- webviewDebuggingEnabled
onOpenWindow={syntheticEvent => {
const { nativeEvent } = syntheticEvent;
const { targetUrl } = nativeEvent;
From 6f73551bd4aba49d7d755ee8b48c6fc3375078ba Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Tue, 17 Dec 2024 18:26:59 -0300
Subject: [PATCH 112/114] chore: added e2e in pull request action (#286)
---
.github/workflows/changesets.yml | 4 ++++
.github/workflows/e2e.yml | 17 +----------------
.github/workflows/pull-request.yml | 4 ++++
3 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/changesets.yml b/.github/workflows/changesets.yml
index 91fe32bf9..a104bc4e6 100644
--- a/.github/workflows/changesets.yml
+++ b/.github/workflows/changesets.yml
@@ -24,6 +24,10 @@ jobs:
- name:
uses: ./.github/actions/setup
+ - name: E2E Tests
+ uses: ./.github/workflows/e2e.yml
+ secrets: inherit
+
- name: Create Release Pull Request or Publish to NPM
id: changesets
uses: changesets/action@v1
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 2d2bf6450..3ab77cd0d 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -4,11 +4,6 @@ on:
workflow_dispatch:
workflow_call:
inputs:
- branch:
- description: 'The branch to use'
- default: 'main'
- required: false
- type: string
base-url:
description: 'The AppKit App url'
default: 'http://localhost:8081/'
@@ -19,10 +14,6 @@ on:
default: 'https://react-wallet.walletconnect.com/'
required: false
type: string
- skip_setup:
- description: 'Skip setup steps if already done'
- type: boolean
- default: false
secrets:
CLOUD_PROJECT_ID:
required: true
@@ -32,19 +23,13 @@ jobs:
name: 'Playwright Tests'
runs-on: ubuntu-latest
steps:
- - name: checkout
- if: ${{ !inputs.skip_setup }}
+ - name: Checkout
uses: actions/checkout@v4
- with:
- repository: reown-com/appkit-react-native
- ref: ${{ inputs.branch }}
- name: Setup
- if: ${{ !inputs.skip_setup }}
uses: ./.github/actions/setup
- name: Build SDK
- if: ${{ !inputs.skip_setup }}
run: |
echo "Building SDK..."
yarn build
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 64e1a66f0..536d7e32c 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -12,3 +12,7 @@ jobs:
name: Verify
uses: ./.github/workflows/verify.yml
secrets: inherit
+
+ e2e:
+ uses: ./.github/workflows/e2e.yml
+ secrets: inherit
From 4dde1c830011bdb6198d39df07527f78c41d08cf Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 18 Dec 2024 10:59:48 -0300
Subject: [PATCH 113/114] chore: disabled farcaster login (#287)
---
apps/native/App.tsx | 2 +-
packages/core/src/utils/ConstantsUtil.ts | 2 +-
packages/core/src/utils/TypeUtil.ts | 6 ++++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/apps/native/App.tsx b/apps/native/App.tsx
index ea1abcdd9..264779f01 100644
--- a/apps/native/App.tsx
+++ b/apps/native/App.tsx
@@ -75,7 +75,7 @@ createAppKit({
debug: true,
features: {
email: true,
- socials: ['x', 'farcaster', 'discord', 'apple'],
+ socials: ['x', 'discord', 'apple'],
emailShowWallets: true
}
});
diff --git a/packages/core/src/utils/ConstantsUtil.ts b/packages/core/src/utils/ConstantsUtil.ts
index 8e537210f..e580d1077 100644
--- a/packages/core/src/utils/ConstantsUtil.ts
+++ b/packages/core/src/utils/ConstantsUtil.ts
@@ -3,7 +3,7 @@ import type { Features } from './TypeUtil';
const defaultFeatures: Features = {
email: true,
emailShowWallets: true,
- socials: ['x', 'discord', 'apple', 'farcaster']
+ socials: ['x', 'discord', 'apple']
};
export const ConstantsUtil = {
diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts
index d0bce97b0..0cd0e363c 100644
--- a/packages/core/src/utils/TypeUtil.ts
+++ b/packages/core/src/utils/TypeUtil.ts
@@ -63,6 +63,8 @@ export type SdkVersion =
| `react-native-ethers5-${string}`
| `react-native-ethers-${string}`;
+type EnabledSocials = Exclude;
+
export type Features = {
/**
* @description Enable or disable the email feature. Enabled by default.
@@ -76,9 +78,9 @@ export type Features = {
emailShowWallets?: boolean;
/**
* @description Enable or disable the socials feature. Enabled by default.
- * @type {FeaturesSocials[]}
+ * @type {EnabledSocials[]}
*/
- socials?: SocialProvider[] | false;
+ socials?: EnabledSocials[] | false;
};
// -- ApiController Types -------------------------------------------------------
From 047cb8e2d4a435e1728cf1918c3754c217a60be2 Mon Sep 17 00:00:00 2001
From: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com>
Date: Wed, 18 Dec 2024 11:27:30 -0300
Subject: [PATCH 114/114] chore: updated ethereum provider version (#289)
---
.changeset/weak-poems-play.md | 18 ++++++
packages/ethers/package.json | 2 +-
packages/ethers5/package.json | 2 +-
yarn.lock | 102 +++++++++++++++++++---------------
4 files changed, 77 insertions(+), 47 deletions(-)
create mode 100644 .changeset/weak-poems-play.md
diff --git a/.changeset/weak-poems-play.md b/.changeset/weak-poems-play.md
new file mode 100644
index 000000000..896f956c4
--- /dev/null
+++ b/.changeset/weak-poems-play.md
@@ -0,0 +1,18 @@
+---
+'@reown/appkit-coinbase-ethers-react-native': patch
+'@reown/appkit-coinbase-wagmi-react-native': patch
+'@reown/appkit-scaffold-utils-react-native': patch
+'@reown/appkit-auth-ethers-react-native': patch
+'@reown/appkit-auth-wagmi-react-native': patch
+'@reown/appkit-scaffold-react-native': patch
+'@reown/appkit-ethers5-react-native': patch
+'@reown/appkit-common-react-native': patch
+'@reown/appkit-ethers-react-native': patch
+'@reown/appkit-wallet-react-native': patch
+'@reown/appkit-wagmi-react-native': patch
+'@reown/appkit-core-react-native': patch
+'@reown/appkit-siwe-react-native': patch
+'@reown/appkit-ui-react-native': patch
+---
+
+chore: updated ethereum provider to 2.17.3
diff --git a/packages/ethers/package.json b/packages/ethers/package.json
index 9047e6046..0e6127b79 100644
--- a/packages/ethers/package.json
+++ b/packages/ethers/package.json
@@ -42,7 +42,7 @@
"@reown/appkit-scaffold-react-native": "1.0.2",
"@reown/appkit-scaffold-utils-react-native": "1.0.2",
"@reown/appkit-siwe-react-native": "1.0.2",
- "@walletconnect/ethereum-provider": "2.17.2"
+ "@walletconnect/ethereum-provider": "2.17.3"
},
"peerDependencies": {
"@react-native-async-storage/async-storage": ">=1.17.0",
diff --git a/packages/ethers5/package.json b/packages/ethers5/package.json
index 790554726..2fe1786da 100644
--- a/packages/ethers5/package.json
+++ b/packages/ethers5/package.json
@@ -42,7 +42,7 @@
"@reown/appkit-scaffold-react-native": "1.0.2",
"@reown/appkit-scaffold-utils-react-native": "1.0.2",
"@reown/appkit-siwe-react-native": "1.0.2",
- "@walletconnect/ethereum-provider": "2.17.2"
+ "@walletconnect/ethereum-provider": "2.17.3"
},
"peerDependencies": {
"@react-native-async-storage/async-storage": ">=1.17.0",
diff --git a/yarn.lock b/yarn.lock
index ca6ac19ae..d17c20ea0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6749,7 +6749,7 @@ __metadata:
"@reown/appkit-scaffold-react-native": "npm:1.0.2"
"@reown/appkit-scaffold-utils-react-native": "npm:1.0.2"
"@reown/appkit-siwe-react-native": "npm:1.0.2"
- "@walletconnect/ethereum-provider": "npm:2.17.2"
+ "@walletconnect/ethereum-provider": "npm:2.17.3"
ethers: "npm:6.10.0"
peerDependencies:
"@react-native-async-storage/async-storage": ">=1.17.0"
@@ -6770,7 +6770,7 @@ __metadata:
"@reown/appkit-scaffold-react-native": "npm:1.0.2"
"@reown/appkit-scaffold-utils-react-native": "npm:1.0.2"
"@reown/appkit-siwe-react-native": "npm:1.0.2"
- "@walletconnect/ethereum-provider": "npm:2.17.2"
+ "@walletconnect/ethereum-provider": "npm:2.17.3"
ethers: "npm:5.7.2"
peerDependencies:
"@react-native-async-storage/async-storage": ">=1.17.0"
@@ -8825,28 +8825,28 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/core@npm:2.17.2":
- version: 2.17.2
- resolution: "@walletconnect/core@npm:2.17.2"
+"@walletconnect/core@npm:2.17.3":
+ version: 2.17.3
+ resolution: "@walletconnect/core@npm:2.17.3"
dependencies:
"@walletconnect/heartbeat": "npm:1.2.2"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
"@walletconnect/jsonrpc-types": "npm:1.0.4"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
- "@walletconnect/jsonrpc-ws-connection": "npm:1.0.14"
+ "@walletconnect/jsonrpc-ws-connection": "npm:1.0.16"
"@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/logger": "npm:2.1.2"
"@walletconnect/relay-api": "npm:1.0.11"
"@walletconnect/relay-auth": "npm:1.0.4"
"@walletconnect/safe-json": "npm:1.0.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.17.2"
- "@walletconnect/utils": "npm:2.17.2"
+ "@walletconnect/types": "npm:2.17.3"
+ "@walletconnect/utils": "npm:2.17.3"
"@walletconnect/window-getters": "npm:1.0.1"
events: "npm:3.3.0"
lodash.isequal: "npm:4.5.0"
uint8arrays: "npm:3.1.0"
- checksum: 6124b81892a4e5e9350cfff22a7ce3a23a66c9589221411bd8bfd411fc392b6b343fae1634b32000d4275ba11b1a0f732cf6b7ba5da35b388854c7e7b4f2764d
+ checksum: e6a841a0d5b27922b83fbb7a1dbcb519b825d70489f9bd6a909cf0b3c543ab3a6c209a0775a95c5dc452a875757f04c9ca27d02c6f002c39974d2ce2061e5887
languageName: node
linkType: hard
@@ -8877,9 +8877,9 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/ethereum-provider@npm:2.17.2":
- version: 2.17.2
- resolution: "@walletconnect/ethereum-provider@npm:2.17.2"
+"@walletconnect/ethereum-provider@npm:2.17.3":
+ version: 2.17.3
+ resolution: "@walletconnect/ethereum-provider@npm:2.17.3"
dependencies:
"@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
"@walletconnect/jsonrpc-provider": "npm:1.0.14"
@@ -8887,12 +8887,12 @@ __metadata:
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
"@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/modal": "npm:2.7.0"
- "@walletconnect/sign-client": "npm:2.17.2"
- "@walletconnect/types": "npm:2.17.2"
- "@walletconnect/universal-provider": "npm:2.17.2"
- "@walletconnect/utils": "npm:2.17.2"
+ "@walletconnect/sign-client": "npm:2.17.3"
+ "@walletconnect/types": "npm:2.17.3"
+ "@walletconnect/universal-provider": "npm:2.17.3"
+ "@walletconnect/utils": "npm:2.17.3"
events: "npm:3.3.0"
- checksum: 191eb6106119a57c1e4c82212cf6650f9e9e32b26a39c5aba0745125067e9153f30ddc43254bafd95ed5f1debd5a5d08094dd5a037ff4a61e645c652ae3d022c
+ checksum: 6ca5aaf5f72dfe0c8edd54f4bd30a55ee22e28cf766a6fe1052a22ad252f0aab4d41c9e105b97e1a4ce29f25fbb8aaed3081a447ecb1759664306b4725948774
languageName: node
linkType: hard
@@ -8983,6 +8983,18 @@ __metadata:
languageName: node
linkType: hard
+"@walletconnect/jsonrpc-ws-connection@npm:1.0.16":
+ version: 1.0.16
+ resolution: "@walletconnect/jsonrpc-ws-connection@npm:1.0.16"
+ dependencies:
+ "@walletconnect/jsonrpc-utils": "npm:^1.0.6"
+ "@walletconnect/safe-json": "npm:^1.0.2"
+ events: "npm:^3.3.0"
+ ws: "npm:^7.5.1"
+ checksum: 30a09d24ffb6b4b291e2d1263504c4ea6c6797c992f5e6eb8033e58bd24749c80fd4e5ba6ffaadb28f8ced0c6b131213195b616f8983bb9f56aa7c91e83e6218
+ languageName: node
+ linkType: hard
+
"@walletconnect/keyvaluestorage@npm:1.1.1":
version: 1.1.1
resolution: "@walletconnect/keyvaluestorage@npm:1.1.1"
@@ -9129,20 +9141,20 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/sign-client@npm:2.17.2":
- version: 2.17.2
- resolution: "@walletconnect/sign-client@npm:2.17.2"
+"@walletconnect/sign-client@npm:2.17.3":
+ version: 2.17.3
+ resolution: "@walletconnect/sign-client@npm:2.17.3"
dependencies:
- "@walletconnect/core": "npm:2.17.2"
+ "@walletconnect/core": "npm:2.17.3"
"@walletconnect/events": "npm:1.0.1"
"@walletconnect/heartbeat": "npm:1.2.2"
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
"@walletconnect/logger": "npm:2.1.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.17.2"
- "@walletconnect/utils": "npm:2.17.2"
+ "@walletconnect/types": "npm:2.17.3"
+ "@walletconnect/utils": "npm:2.17.3"
events: "npm:3.3.0"
- checksum: 0acbda4ea34be209b1436134804e72641ca377e2bb6823b7d94177b30e50b8e6de28dfdad6ff64dac61a1305e7b6f281df2357488382c88e440a79b817d377a8
+ checksum: 454afa3c933ec11f651c4cd275af88eef7da65b5d4bcf8987f768f340557492cf436d662ca42baa54ad8136e4b16f5269e0bc3e212580df09e0ee49873718b96
languageName: node
linkType: hard
@@ -9169,9 +9181,9 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/types@npm:2.17.2":
- version: 2.17.2
- resolution: "@walletconnect/types@npm:2.17.2"
+"@walletconnect/types@npm:2.17.3":
+ version: 2.17.3
+ resolution: "@walletconnect/types@npm:2.17.3"
dependencies:
"@walletconnect/events": "npm:1.0.1"
"@walletconnect/heartbeat": "npm:1.2.2"
@@ -9179,7 +9191,7 @@ __metadata:
"@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/logger": "npm:2.1.2"
events: "npm:3.3.0"
- checksum: 95bd3e4f4f2ef181ea69691800a0a06be2c4fa900ae972539851c5817a0f01b4ba9f381161d044df4db004f431bc416548ec6eca0ac523fc1fb06014386accac
+ checksum: 6e50f1f3d64f32d0fa697bb61340191b153aa0a77b8a483cacaeb62aefa190524e10f78188260b591eaae877d6bfa5ea9ffab5ed905c286151300577f2e0101f
languageName: node
linkType: hard
@@ -9200,9 +9212,9 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/universal-provider@npm:2.17.2":
- version: 2.17.2
- resolution: "@walletconnect/universal-provider@npm:2.17.2"
+"@walletconnect/universal-provider@npm:2.17.3":
+ version: 2.17.3
+ resolution: "@walletconnect/universal-provider@npm:2.17.3"
dependencies:
"@walletconnect/events": "npm:1.0.1"
"@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
@@ -9211,12 +9223,12 @@ __metadata:
"@walletconnect/jsonrpc-utils": "npm:1.0.8"
"@walletconnect/keyvaluestorage": "npm:1.1.1"
"@walletconnect/logger": "npm:2.1.2"
- "@walletconnect/sign-client": "npm:2.17.2"
- "@walletconnect/types": "npm:2.17.2"
- "@walletconnect/utils": "npm:2.17.2"
+ "@walletconnect/sign-client": "npm:2.17.3"
+ "@walletconnect/types": "npm:2.17.3"
+ "@walletconnect/utils": "npm:2.17.3"
events: "npm:3.3.0"
lodash: "npm:4.17.21"
- checksum: afc617916ce2a8e8b669f2d5813795fe0d2cc4400dc0b3275e0b814e5c960b6bc2a1de27fa22021a5fc124aa58ec5ec6a02403fd49ddc4945e1ea941fba3c4da
+ checksum: a577099e5b40fc254df56f9fa3335ff064af24804ec7db9e213ef74261076b2e92194251f56f44de3a7d980deb7cef14f76ca961399e6f6671d1a7dccbdea8d9
languageName: node
linkType: hard
@@ -9244,9 +9256,9 @@ __metadata:
languageName: node
linkType: hard
-"@walletconnect/utils@npm:2.17.2":
- version: 2.17.2
- resolution: "@walletconnect/utils@npm:2.17.2"
+"@walletconnect/utils@npm:2.17.3":
+ version: 2.17.3
+ resolution: "@walletconnect/utils@npm:2.17.3"
dependencies:
"@ethersproject/hash": "npm:5.7.0"
"@ethersproject/transactions": "npm:5.7.0"
@@ -9261,14 +9273,14 @@ __metadata:
"@walletconnect/relay-auth": "npm:1.0.4"
"@walletconnect/safe-json": "npm:1.0.2"
"@walletconnect/time": "npm:1.0.2"
- "@walletconnect/types": "npm:2.17.2"
+ "@walletconnect/types": "npm:2.17.3"
"@walletconnect/window-getters": "npm:1.0.1"
"@walletconnect/window-metadata": "npm:1.0.1"
detect-browser: "npm:5.3.0"
- elliptic: "npm:6.6.0"
+ elliptic: "npm:6.6.1"
query-string: "npm:7.1.3"
uint8arrays: "npm:3.1.0"
- checksum: b44c0025be12301a28715a204c037328eae4fa432f0ee1730da08b3b6583e07aeaf59efd9dcc52209f6a61b50b31c84e555028b97067dfdf9f5efe1211378fc8
+ checksum: ab08f625786eb55e0ae41075a3ccee9804750b1f20745f2d7a81569a6741d022463b250958124925e6b5f51d3a5b3ec783a23233391d8d937c4bcd76e7a8cc8c
languageName: node
linkType: hard
@@ -12300,9 +12312,9 @@ __metadata:
languageName: node
linkType: hard
-"elliptic@npm:6.6.0":
- version: 6.6.0
- resolution: "elliptic@npm:6.6.0"
+"elliptic@npm:6.6.1":
+ version: 6.6.1
+ resolution: "elliptic@npm:6.6.1"
dependencies:
bn.js: "npm:^4.11.9"
brorand: "npm:^1.1.0"
@@ -12311,7 +12323,7 @@ __metadata:
inherits: "npm:^2.0.4"
minimalistic-assert: "npm:^1.0.1"
minimalistic-crypto-utils: "npm:^1.0.1"
- checksum: 42eb3492e218017bf8923a5d14a86f414952f2f771361805b3ae9f380923b5da53e203d0d92be95cb0a248858a78db7db5934a346e268abb757e6fe561d401c9
+ checksum: 8b24ef782eec8b472053793ea1e91ae6bee41afffdfcb78a81c0a53b191e715cbe1292aa07165958a9bbe675bd0955142560b1a007ffce7d6c765bcaf951a867
languageName: node
linkType: hard