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

feat: bbn wallet connect #413

Merged
merged 3 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
68 changes: 59 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"dependencies": {
"@babylonlabs-io/babylon-proto-ts": "0.0.3-canary.3",
"@babylonlabs-io/bbn-core-ui": "^0.2.0",
"@babylonlabs-io/bbn-wallet-connect": "^0.0.21",
totraev marked this conversation as resolved.
Show resolved Hide resolved
"@babylonlabs-io/btc-staking-ts": "0.4.0-canary.3",
"@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3",
"@bitcoinerlab/secp256k1": "^1.1.1",
Expand Down
6 changes: 4 additions & 2 deletions src/app/components/Connect/ConnectSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ interface ConnectSmallProps {
loading?: boolean;
onConnect: () => void;
address: string;
connected: boolean;
btcWalletBalanceSat?: number;
onDisconnect: () => void;
}

export const ConnectSmall: React.FC<ConnectSmallProps> = ({
loading = false,
connected,
onConnect,
address,
btcWalletBalanceSat,
Expand Down Expand Up @@ -64,7 +66,7 @@ export const ConnectSmall: React.FC<ConnectSmallProps> = ({
);
};

return address ? (
return connected ? (
<div className="relative mr-[-10px] text-sm hidden md:flex" ref={ref}>
<button
className="flex cursor-pointer outline-none items-stretch"
Expand Down Expand Up @@ -143,7 +145,7 @@ export const ConnectSmall: React.FC<ConnectSmallProps> = ({
onClick={onConnect}
// Disable the button if the user is already connected
// or: API is not available, geo-blocked, or has an error
disabled={Boolean(address) || !isApiNormal}
disabled={connected || !isApiNormal}
>
<PiWalletBold size={20} className="flex md:hidden" />
<span className="hidden md:flex">Connect Wallets</span>
Expand Down
4 changes: 3 additions & 1 deletion src/app/components/Connect/ConnectedSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ import { LoadingSmall } from "../Loading/Loading";

interface ConnectedSmallProps {
loading?: boolean;
connected: boolean;
address: string;
onDisconnect: () => void;
btcWalletBalanceSat?: number;
}

export const ConnectedSmall: React.FC<ConnectedSmallProps> = ({
loading = false,
connected,
address,
btcWalletBalanceSat,
onDisconnect,
Expand All @@ -38,7 +40,7 @@ export const ConnectedSmall: React.FC<ConnectedSmallProps> = ({
const { coinName } = getNetworkConfig();

return (
address && (
connected && (
<div className="relative flex text-sm" ref={ref}>
<button
className="flex cursor-pointer outline-none items-stretch w-full justify-between"
Expand Down
6 changes: 4 additions & 2 deletions src/app/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useWalletConnect } from "@babylonlabs-io/bbn-wallet-connect";
import { twJoin } from "tailwind-merge";

import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import { useWalletConnection } from "@/app/context/wallet/WalletConnectionProvider";
import { useAppState } from "@/app/state";
import { shouldDisplayTestingMsg } from "@/config";

Expand All @@ -12,7 +12,7 @@ import { TestingInfo } from "../TestingInfo/TestingInfo";
import { ThemeToggle } from "../ThemeToggle/ThemeToggle";

export const Header = () => {
const { disconnect, open } = useWalletConnection();
const { connected, disconnect, open } = useWalletConnect();
const { address } = useBTCWallet();
const { totalBalance, isLoading: loading } = useAppState();

Expand All @@ -30,6 +30,7 @@ export const Header = () => {
</div>
<div className="flex items-center gap-4">
<ConnectSmall
connected={connected}
loading={loading}
onConnect={open}
address={address}
Expand All @@ -45,6 +46,7 @@ export const Header = () => {
)}
>
<ConnectedSmall
connected={connected}
loading={loading}
address={address}
btcWalletBalanceSat={totalBalance}
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Modals/FilterOrdinalsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useWalletConnect } from "@babylonlabs-io/bbn-wallet-connect";
import { useEffect, useState } from "react";
import { IoMdClose } from "react-icons/io";
import { useLocalStorage } from "usehooks-ts";

import { FILTER_ORDINALS_MODAL_KEY } from "@/app/common/constants";
import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import { useWalletConnection } from "@/app/context/wallet/WalletConnectionProvider";
import { useAppState } from "@/app/state";

import { GeneralModal } from "./GeneralModal";
Expand All @@ -23,7 +23,7 @@ export const FilterOrdinalsModal: React.FC<FilterOrdinalsModalProps> = ({}) => {
}));
};

const { isConnected } = useWalletConnection();
const { connected: isConnected } = useWalletConnect();
const { ordinalsExcluded, includeOrdinals, excludeOrdinals } = useAppState();

const [hasSeenFilterOrdinalsModal, setHasSeenFilterOrdinalsModal] =
Expand Down
85 changes: 33 additions & 52 deletions src/app/context/wallet/BTCWalletProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { BTCProvider } from "@tomo-inc/tomo-wallet-provider";
"use client";
import {
BTCProvider,
useChainConnector,
useWalletConnect,
UTXO,
} from "@babylonlabs-io/bbn-wallet-connect";
import type { networks } from "bitcoinjs-lib";
import {
createContext,
Expand All @@ -21,12 +27,9 @@ import {
Fees,
InscriptionIdentifier,
Network,
UTXO,
} from "@/utils/wallet/btc_wallet_provider";
import { WalletError, WalletErrorType } from "@/utils/wallet/errors";

import { useWalletConnection } from "./WalletConnectionProvider";

interface BTCWalletContextProps {
network?: networks.Network;
publicKeyNoCoord: string;
Expand Down Expand Up @@ -79,7 +82,8 @@ export const BTCWalletProvider = ({ children }: PropsWithChildren) => {
const [address, setAddress] = useState("");

const { showError, captureError } = useError();
const { open, isConnected, providers } = useWalletConnection();
const btcConnector = useChainConnector("BTC");
const { open = () => {}, connected } = useWalletConnect();

const btcDisconnect = useCallback(() => {
setBTCWalletProvider(undefined);
Expand All @@ -89,12 +93,13 @@ export const BTCWalletProvider = ({ children }: PropsWithChildren) => {
}, []);

const connectBTC = useCallback(
async (walletProvider: BTCProvider) => {
async (walletProvider: BTCProvider | null) => {
if (!walletProvider) return;

const supportedNetworkMessage =
"Only Native SegWit and Taproot addresses are supported. Please switch the address type in your wallet and try again.";

try {
await walletProvider.connectWallet();
const address = await walletProvider.getAddress();
const supported = isSupportedAddressType(address);
if (!supported) {
Expand Down Expand Up @@ -140,19 +145,22 @@ export const BTCWalletProvider = ({ children }: PropsWithChildren) => {
[showError, captureError],
);

useEffect(() => {
const unsubscribe = btcConnector?.on("connect", (wallet) => {
connectBTC(wallet.provider);
});

return unsubscribe;
}, [btcConnector, connectBTC]);

// Listen for BTC account changes
useEffect(() => {
if (btcWalletProvider) {
let once = false;
btcWalletProvider.on("accountChanged", () => {
if (!once) {
connectBTC(btcWalletProvider);
}
});
return () => {
once = true;
};
}
if (!btcWalletProvider) return;

const cb = () => void connectBTC(btcWalletProvider);
btcWalletProvider.on("accountChanged", cb);

return () => void btcWalletProvider.off("accountChanged", cb);
}, [btcWalletProvider, connectBTC]);

const btcWalletMethods = useMemo(
Expand All @@ -165,8 +173,10 @@ export const BTCWalletProvider = ({ children }: PropsWithChildren) => {
btcWalletProvider?.signPsbts(psbtsHexes) ?? [],
getNetwork: async () =>
btcWalletProvider?.getNetwork() ?? ({} as Network),
signMessage: async (message: string, type?: "ecdsa" | "bip322-simple") =>
btcWalletProvider?.signMessage(message, type) ?? "",
signMessage: async (
message: string,
type: "ecdsa" | "bip322-simple" = "bip322-simple",
) => btcWalletProvider?.signMessage(message, type) ?? "",
getBalance: async () => btcWalletProvider?.getBalance() ?? 0,
getNetworkFees: async () =>
btcWalletProvider?.getNetworkFees() ?? ({} as Fees),
Expand All @@ -175,15 +185,7 @@ export const BTCWalletProvider = ({ children }: PropsWithChildren) => {
btcWalletProvider?.getUtxos(address, amount) ?? [],
getBTCTipHeight: async () => btcWalletProvider?.getBTCTipHeight() ?? 0,
getInscriptions: async (): Promise<InscriptionIdentifier[]> =>
btcWalletProvider
?.getInscriptions()
.then((result) =>
result.list.map((ordinal) => ({
txid: ordinal.inscriptionId,
vout: ordinal.outputValue,
})),
)
.catch((e) => []) ?? [],
btcWalletProvider?.getInscriptions() ?? [],
}),
[btcWalletProvider],
);
Expand All @@ -193,13 +195,13 @@ export const BTCWalletProvider = ({ children }: PropsWithChildren) => {
network,
publicKeyNoCoord,
address,
connected: Boolean(btcWalletProvider),
connected,
open,
disconnect: btcDisconnect,
...btcWalletMethods,
}),
[
btcWalletProvider,
connected,
network,
publicKeyNoCoord,
address,
Expand All @@ -209,27 +211,6 @@ export const BTCWalletProvider = ({ children }: PropsWithChildren) => {
],
);

useEffect(() => {
if (isConnected && providers.state) {
if (!btcWalletProvider && providers.bitcoinProvider) {
connectBTC(providers.bitcoinProvider);
}
}
}, [
connectBTC,
providers.bitcoinProvider,
providers.state,
isConnected,
btcWalletProvider,
]);

// Clean up the state when isConnected becomes false
useEffect(() => {
if (!isConnected) {
btcDisconnect();
}
}, [isConnected, btcDisconnect]);

return (
<BTCWalletContext.Provider value={btcContextValue}>
{children}
Expand Down
Loading
Loading