cosmos-multisig-ui/components/dataViews/AccountView/ButtonConnectWallet.tsx
2024-06-19 17:01:16 +02:00

119 lines
3.8 KiB
TypeScript

import { getKeplrKey, useKeplrReconnect } from "@/lib/keplr";
import { cn, toastError } from "@/lib/utils";
import { LoadingStates, WalletInfo, WalletType } from "@/types/signing";
import { makeCosmoshubPath } from "@cosmjs/amino";
import { toBase64 } from "@cosmjs/encoding";
import { LedgerSigner } from "@cosmjs/ledger-amino";
import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
import { Loader2, Unplug } from "lucide-react";
import Image from "next/image";
import { Dispatch, SetStateAction, useCallback, useState } from "react";
import { useChains } from "../../../context/ChainsContext";
import { getConnectError } from "../../../lib/errorHelpers";
import { Button } from "../../ui/button";
interface ButtonConnectWalletProps {
readonly walletType: WalletType;
readonly walletInfoState: [
WalletInfo | null | undefined,
Dispatch<SetStateAction<WalletInfo | null | undefined>>,
];
}
export default function ButtonConnectWallet({
walletType,
walletInfoState: [walletInfo, setWalletInfo],
}: ButtonConnectWalletProps) {
const { chain } = useChains();
const [loading, setLoading] = useState<LoadingStates>({});
const connectKeplr = useCallback(async () => {
try {
setLoading((oldLoading) => ({ ...oldLoading, keplr: true }));
const { bech32Address: address, pubKey: pubKeyArray } = await getKeplrKey(chain.chainId);
const pubKey = toBase64(pubKeyArray);
setWalletInfo({ type: "Keplr", address, pubKey });
} catch (e) {
const connectError = getConnectError(e);
console.error(connectError, e);
toastError({
description: connectError,
fullError: e instanceof Error ? e : undefined,
});
} finally {
setLoading((newLoading) => ({ ...newLoading, keplr: false }));
}
}, [chain.chainId, setWalletInfo]);
useKeplrReconnect(!!walletInfo?.address, connectKeplr);
const connectLedger = async () => {
try {
setLoading((newLoading) => ({ ...newLoading, ledger: true }));
const ledgerTransport = await TransportWebUSB.create(120000, 120000);
const offlineSigner = new LedgerSigner(ledgerTransport, {
hdPaths: [makeCosmoshubPath(0)],
prefix: chain.addressPrefix,
});
const [{ address, pubkey: pubKeyArray }] = await offlineSigner.getAccounts();
const pubKey = toBase64(pubKeyArray);
setWalletInfo({ type: "Ledger", address, pubKey });
} catch (e) {
const connectError = getConnectError(e);
console.error(connectError, e);
toastError({
description: connectError,
fullError: e instanceof Error ? e : undefined,
});
} finally {
setLoading((newLoading) => ({ ...newLoading, ledger: false }));
}
};
const onClick = (() => {
if (walletType === "Keplr") {
return connectKeplr;
}
if (walletType === "Ledger") {
return connectLedger;
}
return () => {};
})();
const isLoading =
(walletType === "Keplr" && loading.keplr) || (walletType === "Ledger" && loading.ledger);
return walletInfo?.type === walletType ? (
<Button
variant="outline"
onClick={() => {
setWalletInfo(null);
}}
>
<Unplug className="mr-2 h-auto w-5 text-destructive" />
Disconnect {walletInfo.type}
</Button>
) : (
<Button onClick={onClick} disabled={loading.keplr || loading.ledger} variant="outline">
{isLoading ? (
<Loader2 className="mr-2 h-5 w-5 animate-spin" />
) : (
<Image
alt=""
src={`/assets/icons/${walletType.toLowerCase()}.svg`}
width={walletType === "Ledger" ? 23 : 20}
height={walletType === "Ledger" ? 23 : 20}
className={cn("mr-2", walletType === "Ledger" && "bg-white p-0.5")}
/>
)}
Connect {walletType}
</Button>
);
}