Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

feat: use privy wallets #2555

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
},
];

const SELECT_LIST = [

Check warning on line 67 in packages/app/components/creator-token/buy-creator-token.web.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/components/creator-token/buy-creator-token.web.tsx#L67

[unused-imports/no-unused-vars] 'SELECT_LIST' is assigned a value but never used. Allowed unused vars must match /^_/u.
{
title: "Buy",
value: "buy",
Expand All @@ -80,14 +80,13 @@
const [username] = useParam("username");
const [selectedActionParam] = useParam("selectedAction");
const [tokenAmount, setTokenAmount] = useState(1);
const { wallets } = useWallets();
const isPrivyWalletConnected = wallets?.[0]?.walletClientType === "privy";
const isPrivyWalletConnected = wallet?.walletClientType === "privy";

const { data: profileData } = useUserProfile({ address: username });
const sellToken = useCreatorTokenSell();
const redirectToCreatorTokensShare = useRedirectToCreatorTokensShare();

const [selectedAction, setSelectedAction] = useState<Query["selectedAction"]>(

Check warning on line 89 in packages/app/components/creator-token/buy-creator-token.web.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/components/creator-token/buy-creator-token.web.tsx#L89

[unused-imports/no-unused-vars] 'setSelectedAction' is assigned a value but never used. Allowed unused vars must match /^_/u.
selectedActionParam ?? "buy"
);

Expand Down
9 changes: 7 additions & 2 deletions packages/app/components/header/header.md.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ const ChannelsUnreadMessages = () => {

export const HeaderMd = withColorScheme(() => {
const { user, isAuthenticated } = useUser();
const { handleSubmitWallet, loading: loginLoading } = useLogin();
const { loading: loginLoading } = useLogin();
const { links, social } = useFooter();
const isDark = useIsDarkMode();
const router = useRouter();
Expand Down Expand Up @@ -560,7 +560,12 @@ export const HeaderMd = withColorScheme(() => {
<Button
size="regular"
tw="mt-6"
onPress={handleSubmitWallet}
onPress={async () => {
if (privy.authenticated) {
await privy.logout();
}
privy.login();
}}
disabled={loginLoading}
>
<>
Expand Down
24 changes: 20 additions & 4 deletions packages/app/components/login/index.web.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useContext } from "react";
import { StyleSheet } from "react-native";

import { PortalProvider } from "@gorhom/portal";
Expand All @@ -17,6 +17,7 @@ import { View } from "@showtime-xyz/universal.view";

import { usePreviousValue } from "app/hooks/use-previous-value";
import { useUser } from "app/hooks/use-user";
import { PrivySetLoginMethodContext } from "app/lib/privy/privy-provider.web";

import { useLogin } from "./use-login";

Expand All @@ -27,7 +28,6 @@ export function Login() {
walletName,
showSignMessage,
verifySignature,
handleSubmitWallet,
loading,
} = useLogin();
const privy = usePrivy();
Expand All @@ -36,6 +36,7 @@ export function Login() {
const prevUser = usePreviousValue(user);
//#endregion
const modalScreenContext = useModalScreenContext();
const privyLoginMethodContext = useContext(PrivySetLoginMethodContext);

useEffect(() => {
if (showSignMessage) {
Expand Down Expand Up @@ -90,7 +91,14 @@ export function Login() {
if (privy.authenticated) {
await privy.logout();
}
privy.login();
privyLoginMethodContext.setLoginMethods([
"sms",
"google",
"apple",
]);
setTimeout(() => {
privy.login();
});
}}
>
Phone & Social
Expand All @@ -100,7 +108,15 @@ export function Login() {
variant="primary"
tw={`my-2 ${loading ? "opacity-[0.5]" : ""}`}
disabled={loading}
onPress={handleSubmitWallet}
onPress={async () => {
if (privy.authenticated) {
await privy.logout();
}
privyLoginMethodContext.setLoginMethods(["wallet"]);
setTimeout(() => {
privy.login();
});
}}
>
<View tw="absolute left-4 top-3">
<Ethereum
Expand Down
6 changes: 6 additions & 0 deletions packages/app/components/settings/settings-wallet-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { View } from "@showtime-xyz/universal.view";
import { useSetPrimaryWallet } from "app/hooks/api/use-set-primary-wallet";
import { useCurrentUserAddress } from "app/hooks/use-current-user-address";
import { useUser } from "app/hooks/use-user";
import { useWallet } from "app/hooks/use-wallet";
import { WalletAddressesV2 } from "app/types";
import { formatAddressShort } from "app/utilities";

Expand Down Expand Up @@ -222,6 +223,11 @@ export const SettingsWalletItem = (props: Props) => {
</View>
<View tw="flex flex-row items-center justify-center">
<Hidden until="md">
{isConnectedAddress ? (
<PressableHover tw="mr-4 h-6 flex-row items-center justify-center self-start rounded-3xl border border-blue-500 bg-blue-500/20 px-2 md:h-8">
<Text tw="text-xs text-blue-600"> Active</Text>
</PressableHover>
) : null}
<MakePrimaryBtn
isPrimary={isPrimary}
onPress={() => setPrimaryWallet(wallet.address)}
Expand Down
8 changes: 5 additions & 3 deletions packages/app/hooks/use-wallet/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ export type ConnectResult = Promise<
*/
connector?: GetAccountResult["connector"];
isReconnected?: boolean;
walletClientType?: string;
}
| undefined
>;
export type UseWalletReturnType = {
address?: `0x${string}`;
address?: string;
disconnect: () => ConnectResult;
connected?: boolean;
connect: () => ConnectResult;
name?: string;
signMessageAsync: (args: SignMessageArgs) => Promise<string | undefined>;
signMessageAsync: (args: SignMessageArgs) => Promise<string> | undefined;
isMagicWallet?: boolean;
walletClient?: WalletClient | null;
getWalletClient: () => WalletClient | undefined | null;
getWalletClient: () => any;
walletClientType?: string;
};
35 changes: 20 additions & 15 deletions packages/app/hooks/use-wallet/use-wallet.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import { ConnectResult, UseWalletReturnType } from "./types";
const useWallet = (): UseWalletReturnType => {
const walletConnectedPromiseResolveCallback = useRef<any>(null);
const privy = usePrivy();
const wallets = useWallets();
const latestConnectedWallet = useLatestValueRef(wallets.wallets[0]);
const { wallets: connectedWallets } = useWallets();
const wallet = connectedWallets.find(
(wallet) => wallet.walletClientType === "privy"
);
const latestConnectedWallet = useLatestValueRef(wallet);
useConnectWallet({
onSuccess: (wallet) => {
console.log("wallet connect success", wallet);
Expand All @@ -23,11 +26,11 @@ const useWallet = (): UseWalletReturnType => {
},
});

const connected = !!wallets.wallets[0];
const connected = !!wallet;

const disconnect = useStableCallback(() => {
localStorage.removeItem("walletconnect");
wallets.wallets.forEach((wallet) => wallet.disconnect());
connectedWallets.forEach((wallet) => wallet.disconnect());
});

const result = useMemo(() => {
Expand All @@ -40,23 +43,25 @@ const useWallet = (): UseWalletReturnType => {
},
getWalletClient: async () => {
await latestConnectedWallet.current?.switchChain(baseChain.id);
const ethereumProvider =
await wallets.wallets[0]?.getEthereumProvider();
const walletClient = await createWalletClient({
account: latestConnectedWallet.current?.address as any,
chain: baseChain,
transport: custom(ethereumProvider),
});
return walletClient;
const ethereumProvider = await wallet?.getEthereumProvider();
if (ethereumProvider) {
const walletClient = await createWalletClient({
account: latestConnectedWallet.current?.address as any,
chain: baseChain,
transport: custom(ethereumProvider),
});
return walletClient;
}
},
connected,
address: wallets.wallets[0]?.address,
address: wallet?.address,
disconnect,
walletClientType: wallet?.walletClientType,
signMessageAsync: ({ message }: { message: string }) => {
return latestConnectedWallet.current.sign(message);
return latestConnectedWallet.current?.sign(message);
},
};
}, [connected, disconnect, privy, latestConnectedWallet, wallets.wallets]);
}, [connected, wallet, disconnect, privy, latestConnectedWallet]);

return result;
};
Expand Down
19 changes: 12 additions & 7 deletions packages/app/lib/privy/privy-hooks.web.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { usePrivy, useWallets } from "@privy-io/react-auth";

import { useWallet } from "app/hooks/use-wallet";

export const useLoginWithSMS = () => {
return {
loginWithCode: () => {},
Expand All @@ -13,17 +15,20 @@ export const useExportPrivyWallet = () => {
};

export const usePrivyFundWallet = () => {
const { wallets } = useWallets();
const wallets = useWallets();
const wallet = useWallet();
const fundWallet = (currencyCode: "eth" | "usdc") => {
return wallets[0].fund({
config: {
currencyCode: currencyCode === "usdc" ? "USDC_BASE" : "ETH_BASE",
},
});
return wallets.wallets
.find((w) => w.walletClientType === "privy")
?.fund({
config: {
currencyCode: currencyCode === "usdc" ? "USDC_BASE" : "ETH_BASE",
},
});
};

return {
fundWallet,
isAvailable: wallets?.[0]?.walletClientType === "privy",
isAvailable: wallet?.walletClientType === "privy",
};
};
91 changes: 81 additions & 10 deletions packages/app/lib/privy/privy-provider.web.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
forwardRef,
useRef,
useEffect,
useState,
useContext,
createContext,
} from "react";
import { forwardRef, useRef, useEffect, useState, createContext } from "react";

import {
PrivyProvider as PrivyProviderImpl,
Expand All @@ -14,20 +7,30 @@
PrivyInterface,
useLogin,
} from "@privy-io/react-auth";
import * as Clipboard from "expo-clipboard";

import { Button } from "@showtime-xyz/universal.button";
import { useIsDarkMode } from "@showtime-xyz/universal.hooks";
import { Copy, Ethereum } from "@showtime-xyz/universal.icon";
import { ModalSheet } from "@showtime-xyz/universal.modal-sheet";
import { Text } from "@showtime-xyz/universal.text";
import { View } from "@showtime-xyz/universal.view";

import { useAuth } from "app/hooks/auth/use-auth";
import { baseChain } from "app/hooks/creator-token/utils";
import { useStableCallback } from "app/hooks/use-stable-callback";
import { useWallet } from "app/hooks/use-wallet";

import { toast } from "design-system/toast";

import { usePrivyFundWallet } from "./privy-hooks";

export const PrivySetLoginMethodContext = createContext<any>(null);

export const PrivyProvider = ({ children }: any) => {
const colorScheme = useIsDarkMode() ? "dark" : "light";
const [loginMethods, setLoginMethods] = useState<any>([
// "wallet",
"wallet",
"sms",
"google",
"apple",
Expand Down Expand Up @@ -62,16 +65,19 @@
current: null,
} as { current: PrivyInterface | null };

export const PrivyAuth = forwardRef(function PrivyAuth(props: any, ref) {

Check warning on line 68 in packages/app/lib/privy/privy-provider.web.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/lib/privy/privy-provider.web.tsx#L68

[unused-imports/no-unused-vars] 'ref' is defined but never used. Allowed unused args must match /^_/u.
const privy = usePrivy();
const { authenticationStatus, setAuthenticationStatus, login, logout } =
useAuth();
const wallet = useWallet();
const { fundWallet } = usePrivyFundWallet();
let prevAuthStatus = useRef<any>();
const [showWalletCreated, setShowWalletCreated] = useState(false);

const createWalletAndLogin = useStableCallback(async (user: PrivyUser) => {
try {
await privy.createWallet();
setShowWalletCreated(true);
} catch (e) {
console.log("wallet is already created by privy!");
}
Expand Down Expand Up @@ -100,6 +106,7 @@
});

const disconnect = wallet.disconnect;
const isDark = useIsDarkMode();

// TODO: remove this when we have a better way to handle this. Providers hierarchy is not ideal.
useEffect(() => {
Expand All @@ -120,7 +127,71 @@

privyRef.current = privy;

return props.children;
return (
<>
{props.children}
{showWalletCreated ? (
<ModalSheet
snapPoints={[240]}
title="You just created a Showtime wallet!"
visible={showWalletCreated}
close={() => setShowWalletCreated(false)}
onClose={() => setShowWalletCreated(false)}
>
<View tw="p-4">
<Text tw="text-base">
Your wallet is linked to your sign in method. Transfer or buy ETH
(on the Base network only) to get started. You can manage your
wallets in settings.
</Text>
<View tw="mt-4 w-full flex-row justify-between">
<Button
size="regular"
tw="flex-1"
onPress={() => {
fundWallet("eth");
}}
>
<Ethereum
color={isDark ? "black" : "white"}
height={20}
width={20}
/>
{" "}
Buy ETH
</Button>
<Button
variant="text"
size="regular"
tw="flex-1"
onPress={async () => {
if (wallet.address) {
await Clipboard.setStringAsync(wallet.address);
toast.success("Copied!");
}
}}
>
Copy wallet{" "}
<Copy
color={isDark ? "white" : "black"}
height={20}
width={20}
/>
</Button>
</View>
<Button
tw="mt-3 flex-1"
variant="outlined"
size="regular"
onPress={() => setShowWalletCreated(false)}
>
Continue
</Button>
</View>
</ModalSheet>
) : null}
</>
);
});

export const usePrivyLogout = () => {
Expand Down
Loading