Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Gateway] enable metamask desktop and mobile support #1697

Merged
merged 8 commits into from
Dec 15, 2023
Merged
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
12 changes: 4 additions & 8 deletions tools/walletextension/frontend/src/api/ethRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ export const switchToTenNetwork = async () => {
});

return 0;
} catch (error: any) {
return error.code;
} catch (switchError: any) {
showToast(ToastType.DESTRUCTIVE, `switchToTenNetwork: ${switchError.code}`);
return switchError.code;
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
}
};

Jennievon marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -83,14 +84,9 @@ export const getSignature = async (account: string, data: any) => {
};

export const getToken = async (provider: ethers.providers.Web3Provider) => {
if (!provider) {
showToast(
ToastType.DESTRUCTIVE,
"No provider found. Please try again later."
);
if (!provider.send) {
return null;
}

try {
if (await isTenChain()) {
const token = await provider.send(requestMethods.getStorageAt, [
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export default function Footer() {
const { version } = useWalletConnection();

return (
<div className="border-t px-2">
<div className="flex h-16 items-center px-4">
<div className="flex-1 flex items-center space-x-4">
<div className="border-t p-2">
<div className="flex h-16 items-center justify-between px-4 flex-wrap">
<div className="flex items-center space-x-4 pr-2">
<a
href={socialLinks.github}
aria-label="GitHub"
Expand All @@ -36,7 +36,7 @@ export default function Footer() {
<DiscordLogoIcon />
</a>
</div>
<div className="flex-1 flex items-center justify-center">
<div className="flex items-center justify-center space-x-4 pr-2">
<h3 className="text-xs text-muted-foreground">
Version: {version || "Unknown"}
</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const Connected = () => {
</TableRow>
) : (
accounts.map((account: Account, i: number) => (
<TableRow key={i}>
<TableRow key={account.name}>
<TableCell className="font-medium">
<TruncatedAddress address={account.name} />
</TableCell>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Account,
} from "../../types/interfaces/WalletInterfaces";
import { showToast } from "../ui/use-toast";
import { ethereum } from "../../lib/utils";
import { ethereum, isValidTokenFormat } from "../../lib/utils";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import of ethereum from ../../lib/utils should be removed as per the PR objectives to replace direct usage of the ethereum object with the MetaMask SDK.

import {
accountIsAuthenticated,
fetchVersion,
Expand Down Expand Up @@ -44,25 +44,23 @@ export const WalletConnectionProvider = ({
const [provider, setProvider] = useState({} as ethers.providers.Web3Provider);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provider state and its usage should be removed if the intention is to fully integrate the MetaMask SDK, as the provider is part of the ethers library which is being replaced.


const initialize = async () => {
if (!provider) {
return showToast(
ToastType.INFO,
"Provider is required to initialize wallet connection."
);
}

try {
if (!ethereum) {
showToast(
ToastType.DESTRUCTIVE,
"Please install Metamask to connect your wallet."
);
return;
}
const providerInstance = new ethers.providers.Web3Provider(ethereum);
setProvider(providerInstance);
await ethService.checkIfMetamaskIsLoaded(providerInstance);
await ethService.checkIfMetamaskIsLoaded(provider);

const fetchedToken = await getToken(providerInstance);
const fetchedToken = await getToken(provider);
setToken(fetchedToken);

const status = await ethService.isUserConnectedToTenChain(fetchedToken);
setWalletConnected(status);

const accounts = await ethService.getAccounts(providerInstance);
const accounts = await ethService.getAccounts(provider);
setAccounts(accounts || null);
setVersion(await fetchVersion());
} catch (error) {
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -105,7 +103,7 @@ export const WalletConnectionProvider = ({
} else {
showToast(ToastType.DESTRUCTIVE, "Account authentication failed.");
}
} catch (error) {
} catch (error: any) {
showToast(ToastType.DESTRUCTIVE, "Account authentication failed.");
}
};
Expand Down Expand Up @@ -135,35 +133,72 @@ export const WalletConnectionProvider = ({
);
return;
}
const token = await getToken(provider);

if (!isValidTokenFormat(token)) {
showToast(
ToastType.INFO,
"Invalid token format. Please refresh the page."
);
setAccounts([]);
setWalletConnected(false);
return;
}

setToken(token);

try {
const accounts = await ethService.getAccounts(provider);
const token = await getToken(provider);
setToken(token);
let updatedAccounts: Account[] = [];

updatedAccounts = await Promise.all(
accounts!.map(async (account) => {
await ethService.authenticateWithGateway(token, account.name);
const { status } = await accountIsAuthenticated(token, account.name);
return {
...account,
connected: status,
};
})
if (!accounts || accounts.length === 0) {
setAccounts([]);
} else {
updatedAccounts = await Promise.all(
accounts!.map(async (account) => {
await ethService.authenticateWithGateway(token, account.name);
const { status } = await accountIsAuthenticated(
token,
account.name
);
return {
...account,
connected: status,
};
})
);
showToast(ToastType.INFO, "Accounts authenticated with gateway!");
setAccounts(updatedAccounts);
}
} catch (error: any) {
showToast(
ToastType.DESTRUCTIVE,
`Error fetching user accounts: ${error?.message}`
);
setAccounts(updatedAccounts || null);
} catch (error) {
showToast(ToastType.DESTRUCTIVE, "Error fetching user accounts.");
} finally {
setWalletConnected(true);
setLoading(false);
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
}
};

useEffect(() => {
initialize();
// eslint-disable-next-line react-hooks/exhaustive-deps
if (ethereum && ethereum.isMetaMask) {
const providerInstance = new ethers.providers.Web3Provider(ethereum);
setProvider(providerInstance);
initialize();

ethereum.on("accountsChanged", () => {
fetchUserAccounts();
});
}

return () => {
if (ethereum && ethereum.removeListener) {
ethereum.removeListener("accountsChanged", () => {
fetchUserAccounts();
});
}
};
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
}, []);

const walletConnectionContextValue: WalletConnectionContextType = {
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
3 changes: 2 additions & 1 deletion tools/walletextension/frontend/src/services/ethService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const ethService = {
})
);
updatedAccounts = await Promise.all(authenticationPromise);
showToast(ToastType.SUCCESS, "Account authentication status updated!");
showToast(ToastType.INFO, "Account authentication status updated!");
return updatedAccounts;
},

Expand Down Expand Up @@ -135,6 +135,7 @@ const ethService = {
} catch (error) {
console.error(error);
showToast(ToastType.DESTRUCTIVE, "An error occurred. Please try again.");
throw error;
}
},

Expand Down
27 changes: 19 additions & 8 deletions tools/walletextension/frontend/src/services/useGatewayService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { ToastType } from "@/types/interfaces";
import { joinTestnet } from "../api/gateway";
import { useWalletConnection } from "../components/providers/wallet-provider";
import { showToast } from "../components/ui/use-toast";
import {SWITCHED_CODE, tenGatewayAddress, tenGatewayVersion} from "../lib/constants";
import {
SWITCHED_CODE,
tenGatewayAddress,
tenGatewayVersion,
} from "../lib/constants";
import { isTenChain, isValidTokenFormat } from "../lib/utils";
import {
addNetworkToMetaMask,
connectAccounts,
getToken,
switchToTenNetwork,
} from "@/api/ethRequests";

Expand All @@ -28,37 +33,43 @@ const useGatewayService = () => {
};

const connectToTenTestnet = async () => {
showToast(ToastType.INFO, "Connecting to Obscuro Testnet...");
setLoading(true);
try {
if (await isTenChain()) {
if (!token || !isValidTokenFormat(token)) {
showToast(
ToastType.DESTRUCTIVE,
"Existing Ten network detected in MetaMask. Please remove before hitting begin"
"Existing Obscuro Testnet detected in MetaMask. Please remove before hitting begin"
);
return;
}
}

showToast(ToastType.INFO, "Switching to Obscuro Testnet...");
const switched = await switchToTenNetwork();

if (switched === SWITCHED_CODE || (token && !isValidTokenFormat(token))) {
showToast(ToastType.SUCCESS, `Switched to Obscuro Testnet: ${switched}`);
// SWITCHED_CODE=4902; error 4902 means that the chain does not exist
if (
switched === SWITCHED_CODE ||
!isValidTokenFormat(await getToken(provider))
) {
showToast(ToastType.INFO, "Adding Obscuro Testnet...");
const user = await joinTestnet();
const rpcUrls = [
`${tenGatewayAddress}/${tenGatewayVersion}/?token=${user}`,
];
await addNetworkToMetaMask(rpcUrls);
showToast(ToastType.SUCCESS, "Added Obscuro Testnet");
}

if (!(await isMetamaskConnected())) {
showToast(ToastType.INFO, "No accounts found, connecting...");
await connectAccounts();
showToast(ToastType.SUCCESS, "Connected to Ten Network");
showToast(ToastType.SUCCESS, "Connected to Obscuro Testnet");
}

await fetchUserAccounts();
} catch (error: any) {
showToast(ToastType.DESTRUCTIVE, `${error}`);
showToast(ToastType.DESTRUCTIVE, `${error?.message}`);
throw error;
} finally {
setLoading(false);
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
Jennievon marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Loading