Skip to content

Commit

Permalink
Add Metamask wallet support and improve state handling in wallet comp…
Browse files Browse the repository at this point in the history
…onents
  • Loading branch information
Ben-Rey authored and peterjah committed Dec 19, 2024
1 parent 516cb26 commit 977ace3
Show file tree
Hide file tree
Showing 13 changed files with 653 additions and 78 deletions.
398 changes: 385 additions & 13 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"style": "src/global.css",
"scripts": {
"build": "tsc",
"build:watch": "tsc --watch",
"storybook": "storybook dev -p 6006",
"storybook:build": "storybook build",
"lint": "eslint .",
Expand Down
26 changes: 13 additions & 13 deletions src/lib/ConnectMassaWallets/components/BearbyWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ import { useAccountStore } from '../store';
import { BEARBY_INSTALL } from '../../massa-react/const';

export default function BearbyWallet() {
const { connectedAccount } = useAccountStore();
const { connectedAccount, isFetching } = useAccountStore();

if (connectedAccount) {
if (!connectedAccount && !isFetching) {
return (
<div className="flex flex-col gap-4 mas-body">
<ConnectedAccount />
<MASBalance />
</div>
<WalletError
description={Intl.t(
'connect-wallet.card-destination.bearby-not-installed',
)}
link={BEARBY_INSTALL}
linkLabel={Intl.t('connect-wallet.card-destination.get-bearby')}
/>
);
}

return (
<WalletError
description={Intl.t(
'connect-wallet.card-destination.bearby-not-installed',
)}
link={BEARBY_INSTALL}
linkLabel={Intl.t('connect-wallet.card-destination.get-bearby')}
/>
<div className="flex flex-col gap-4 mas-body">
<ConnectedAccount />
<MASBalance />
</div>
);
}
37 changes: 30 additions & 7 deletions src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MetaMaskSvg } from './MetaMaskSvg';
import { BearbySvg } from './BearbySvg';
import BearbyWallet from './BearbyWallet';
import SelectMassaWallet from './SelectMassaWallet';
Expand All @@ -8,25 +9,37 @@ import Intl from '../i18n';
import { useAccountStore } from '../store';
import { MassaWallet, Tooltip } from '../../../components';
import { WalletName } from '@massalabs/wallet-provider';
import MetamaskWallet from './MetamaskWallet';
import { Network } from './Network';
import { useEffect, useState } from 'react';

export const ConnectMassaWallet = () => {
const { currentWallet, wallets, setCurrentWallet, isFetching } =
useAccountStore();
const [selectedWallet, setSelectedWallet] = useState<WalletName | null>(null);

useEffect(() => {
if (currentWallet) {
setSelectedWallet(currentWallet.name());
}
}, [currentWallet]);

function renderWallet() {
switch (currentWallet?.name()) {
switch (selectedWallet) {
case WalletName.MassaStation:
return <StationWallet />;
case WalletName.Bearby:
return <BearbyWallet />;
case WalletName.Metamask:
return <MetamaskWallet />;
default:
// Should not happen
return <>Error: no wallet selected</>;
}
}

function renderSelectedWallet() {
switch (currentWallet?.name()) {
switch (selectedWallet) {
case WalletName.MassaStation:
return (
<>
Expand All @@ -41,18 +54,26 @@ export const ConnectMassaWallet = () => {
{Intl.t(`connect-wallet.${WalletName.Bearby}`)}
</>
);
case WalletName.Metamask:
return (
<>
<MetaMaskSvg />
{Intl.t(`connect-wallet.${WalletName.Metamask}`)}
</>
);
}
}

if (!currentWallet) {
if (!selectedWallet && !isFetching) {
return (
<div className="text-f-primary">
<SelectMassaWallet
onClick={async (providerName) => {
const provider = wallets.find((p) => p.name() === providerName);
if (provider) {
await setCurrentWallet(provider);
const wallet = wallets.find((p) => p.name() === providerName);
if (wallet) {
await setCurrentWallet(wallet);
}
setSelectedWallet(providerName);
}}
/>
</div>
Expand All @@ -68,6 +89,7 @@ export const ConnectMassaWallet = () => {
<div className="flex gap-2 items-center">
{renderSelectedWallet()}
<ChainStatus />
<Network />
{currentWallet?.name() === WalletName.Bearby && (
<Tooltip
customClass="mas-caption w-fit whitespace-nowrap"
Expand All @@ -78,11 +100,12 @@ export const ConnectMassaWallet = () => {
<SwitchWalletButton
onClick={() => {
setCurrentWallet();
setSelectedWallet(null);
}}
/>
</div>

{!isFetching && renderWallet()}
{renderWallet()}
</div>
);
};
11 changes: 6 additions & 5 deletions src/lib/ConnectMassaWallets/components/MASBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ import { useEffect, useState } from 'react';
import Intl from '../i18n';
import { useAccountStore } from '../store';
import { FetchingLine } from '../../../components';
import { fetchMASBalance } from '../../massa-react/utils';
import { massaToken } from '../../massa-react/const';
import { formatAmount } from '../../util/parseAmount';

export function MASBalance() {
const [balance, setBalance] = useState<bigint>();

const { connectedAccount } = useAccountStore();
const { connectedAccount, currentWallet, network } = useAccountStore();

useEffect(() => {
if (!connectedAccount) return;
fetchMASBalance(connectedAccount).then((balance) => {
const fetchBalance = async () => {
const balance = await connectedAccount.balance(false);
setBalance(balance);
});
}, [connectedAccount, setBalance]);
};
fetchBalance();
}, [connectedAccount, setBalance, currentWallet, network]);

const formattedBalance = formatAmount(balance?.toString() || '0', 9).full;

Expand Down
57 changes: 57 additions & 0 deletions src/lib/ConnectMassaWallets/components/MetaMaskSvg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* eslint-disable max-len */
export function MetaMaskSvg() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 256 240"
>
<path fill="#E17726" d="M250.066 0L140.219 81.279l20.427-47.9z" />
<path
fill="#E27625"
d="m6.191.096l89.181 33.289l19.396 48.528zM205.86 172.858l48.551.924l-16.968 57.642l-59.243-16.311zm-155.721 0l27.557 42.255l-59.143 16.312l-16.865-57.643z"
/>
<path
fill="#E27625"
d="m112.131 69.552l1.984 64.083l-59.371-2.701l16.888-25.478l.214-.245zm31.123-.715l40.9 36.376l.212.244l16.888 25.478l-59.358 2.7zM79.435 173.044l32.418 25.259l-37.658 18.181zm97.136-.004l5.131 43.445l-37.553-18.184z"
/>
<path
fill="#D5BFB2"
d="m144.978 195.922l38.107 18.452l-35.447 16.846l.368-11.134zm-33.967.008l-2.909 23.974l.239 11.303l-35.53-16.833z"
/>
<path
fill="#233447"
d="m100.007 141.999l9.958 20.928l-33.903-9.932zm55.985.002l24.058 10.994l-34.014 9.929z"
/>
<path
fill="#CC6228"
d="m82.026 172.83l-5.48 45.04l-29.373-44.055zm91.95.001l34.854.984l-29.483 44.057zm28.136-44.444l-25.365 25.851l-19.557-8.937l-9.363 19.684l-6.138-33.849zm-148.237 0l60.435 2.749l-6.139 33.849l-9.365-19.681l-19.453 8.935z"
/>
<path
fill="#E27525"
d="m52.166 123.082l28.698 29.121l.994 28.749zm151.697-.052l-29.746 57.973l1.12-28.8zm-90.956 1.826l1.155 7.27l2.854 18.111l-1.835 55.625l-8.675-44.685l-.003-.462zm30.171-.101l6.521 35.96l-.003.462l-8.697 44.797l-.344-11.205l-1.357-44.862z"
/>
<path
fill="#F5841F"
d="m177.788 151.046l-.971 24.978l-30.274 23.587l-6.12-4.324l6.86-35.335zm-99.471 0l30.399 8.906l6.86 35.335l-6.12 4.324l-30.275-23.589z"
/>
<path
fill="#C0AC9D"
d="m67.018 208.858l38.732 18.352l-.164-7.837l3.241-2.845h38.334l3.358 2.835l-.248 7.831l38.487-18.29l-18.728 15.476l-22.645 15.553h-38.869l-22.63-15.617z"
/>
<path
fill="#161616"
d="m142.204 193.479l5.476 3.869l3.209 25.604l-4.644-3.921h-36.476l-4.556 4l3.104-25.681l5.478-3.871z"
/>
<path
fill="#763E1A"
d="M242.814 2.25L256 41.807l-8.235 39.997l5.864 4.523l-7.935 6.054l5.964 4.606l-7.897 7.191l4.848 3.511l-12.866 15.026l-52.77-15.365l-.457-.245l-38.027-32.078zm-229.628 0l98.326 72.777l-38.028 32.078l-.457.245l-52.77 15.365l-12.866-15.026l4.844-3.508l-7.892-7.194l5.952-4.601l-8.054-6.071l6.085-4.526L0 41.809z"
/>
<path
fill="#F5841F"
d="m180.392 103.99l55.913 16.279l18.165 55.986h-47.924l-33.02.416l24.014-46.808zm-104.784 0l-17.151 25.873l24.017 46.808l-33.005-.416H1.631l18.063-55.985zm87.776-70.878l-15.639 42.239l-3.319 57.06l-1.27 17.885l-.101 45.688h-30.111l-.098-45.602l-1.274-17.986l-3.32-57.045l-15.637-42.239z"
/>
</svg>
);
}
63 changes: 63 additions & 0 deletions src/lib/ConnectMassaWallets/components/MetamaskWallet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import React from 'react';

import { ConnectedAccount } from './ConnectedAccount';
import { MASBalance } from './MASBalance';
import { WalletError } from './WalletError';
import Intl from '../i18n';
import { useAccountStore } from '../store';
import { METAMASK_INSTALL } from '../../massa-react/const';
import { Button } from '../../../components';
import { CHAIN_ID, Network } from '@massalabs/massa-web3';

export default function MetamaskWallet() {
const { connectedAccount, currentWallet, network, isFetching } =
useAccountStore();

function handleSwitchNetwork(network: Network): void {
if (!currentWallet) return;
if (network.chainId === CHAIN_ID.Mainnet) {
currentWallet.setRpcUrl('https://buildnet.massa.net/api/v2');
} else {
currentWallet.setRpcUrl('https://mainnet.massa.net/api/v2');
}
}

if (!connectedAccount && !isFetching) {
return (
<WalletError
description={Intl.t(
'connect-wallet.card-destination.meta-mask-not-connected',
)}
link={METAMASK_INSTALL}
linkLabel={Intl.t('connect-wallet.card-destination.get-metamask')}
/>
);
}

return (
<div className="flex flex-col gap-4 mas-body">
<ConnectedAccount />
<MASBalance />
{network && currentWallet && (
<div className="flex gap-4">
<SwitchNetwork
networkName={network.name === 'mainnet' ? 'buildnet' : 'mainnet'}
onClick={() => handleSwitchNetwork(network)}
/>
</div>
)}
</div>
);
}

function SwitchNetwork({
networkName,
onClick,
}: {
networkName: string;
onClick: () => void;
}) {
return <Button onClick={onClick}>Switch To {networkName}</Button>;
}
18 changes: 18 additions & 0 deletions src/lib/ConnectMassaWallets/components/Network.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import React from 'react';

import { Tag, tagTypes } from '../../../components';
import { useAccountStore } from '../store';

export function Network() {
const { network } = useAccountStore();

if (!network) return;

return <NetworkTag networkName={network.name} />;
}

export function NetworkTag({ networkName }: { networkName: string }) {
return <Tag type={tagTypes.info}>{networkName}</Tag>;
}
5 changes: 5 additions & 0 deletions src/lib/ConnectMassaWallets/components/SelectMassaWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Disconnected } from './Status/Disconnected';
import Intl from '../i18n';
import { Dropdown, MassaWallet } from '../../../components';
import { WalletName } from '@massalabs/wallet-provider';
import { MetaMaskSvg } from './MetaMaskSvg';

const walletList = [
{
Expand All @@ -17,6 +18,10 @@ const walletList = [
name: WalletName.Bearby,
icon: <BearbySvg />,
},
{
name: WalletName.Metamask,
icon: <MetaMaskSvg />,
},
];

interface SelectMassaWalletProps {
Expand Down
10 changes: 5 additions & 5 deletions src/lib/ConnectMassaWallets/components/StationWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Intl from '../i18n';
import { useAccountStore } from '../store';

export default function StationWallet() {
const { accounts } = useAccountStore();
const { accounts, isFetching } = useAccountStore();

const [stationIsOn, setStationIsOn] = useState<boolean | undefined>(
undefined,
Expand All @@ -40,7 +40,7 @@ export default function StationWallet() {
});
});

if (stationIsOn === false) {
if (stationIsOn === false && !isFetching) {
return (
<WalletError
description={Intl.t(
Expand All @@ -52,7 +52,7 @@ export default function StationWallet() {
);
}

if (massaWalletIsOn === false) {
if (massaWalletIsOn === false && !isFetching) {
return (
<WalletError
description={Intl.t(
Expand All @@ -64,7 +64,7 @@ export default function StationWallet() {
);
}

if (accounts !== undefined && !accounts.length) {
if (accounts !== undefined && !accounts.length && !isFetching) {
return (
<WalletError
description={Intl.t(
Expand All @@ -78,7 +78,7 @@ export default function StationWallet() {
);
}

if (accounts === undefined) {
if (accounts === undefined && !isFetching) {
return <div className="h-14 bg-secondary rounded-lg animate-pulse"></div>;
}

Expand Down
3 changes: 3 additions & 0 deletions src/lib/ConnectMassaWallets/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"your-wallet": "Your wallet",
"bearby-not-installed": "Bearby extension is either turned off or not installed. Make sure the extension is on and refresh the page.",
"get-bearby": "Get Bearby here",
"meta-mask-not-connected": "Metamask is not connected. Make sure the extension is on and connected to the right network.",
"get-metamask": "Get Metamask here",
"massa-station-not-detected": "Massa Station desktop app is not detected. Make sure the app is opened, or click below to install it.",
"get-massa-station": "Get Massa Station",
"massa-wallet-not-detected": "Massa Wallet is not detected. Make sure the plugin is installed, or click below to install it.",
Expand All @@ -26,6 +28,7 @@
},
"MASSASTATION": "MassaWallet",
"BEARBY": "Bearby",
"METAMASK": "Metamask",
"connected-cards": {
"wallet-balance": "Balance: "
},
Expand Down
Loading

0 comments on commit 977ace3

Please sign in to comment.