diff --git a/package-lock.json b/package-lock.json index 816061be..99734bb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,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.23", + "@babylonlabs-io/bbn-wallet-connect": "^0.1.6", "@babylonlabs-io/btc-staking-ts": "0.4.0-canary.3", "@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3", "@bitcoinerlab/secp256k1": "^1.1.1", @@ -23,7 +23,7 @@ "@sentry/nextjs": "^8.30.0", "@tanstack/react-query": "^5.28.14", "@tanstack/react-query-next-experimental": "^5.28.14", - "@tomo-inc/wallet-connect-sdk": "0.2.16", + "@tomo-inc/wallet-connect-sdk": "^0.3.3", "@uidotdev/usehooks": "^2.4.1", "axios": "^1.7.4", "bitcoinjs-lib": "6.1.5", @@ -2085,15 +2085,14 @@ } }, "node_modules/@babylonlabs-io/bbn-wallet-connect": { - "version": "0.0.23", - "resolved": "https://registry.npmjs.org/@babylonlabs-io/bbn-wallet-connect/-/bbn-wallet-connect-0.0.23.tgz", - "integrity": "sha512-x6pFnKmo/2tSofQrtJnYYa05//+d8dLhp2zrxFNtjogVkZMgSeP5X7lq12gNXUE5Wlvzd5C9WfNDC61x3TyQEQ==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babylonlabs-io/bbn-wallet-connect/-/bbn-wallet-connect-0.1.6.tgz", + "integrity": "sha512-yUO+9WP3mfMX7vlvc9cN4Mm05aU+9Qnqa3MT2SRTlZTQPM0yc2LipbF0oxRaNuvmrI5potdeijrZRjAgIsXrIA==", "dependencies": { "@cosmjs/stargate": "^0.32.4", "@keplr-wallet/types": "^0.12.156", "buffer": "^6.0.3", - "nanoevents": "^9.1.0", - "react-icons": "^5.3.0" + "nanoevents": "^9.1.0" }, "peerDependencies": { "@babylonlabs-io/bbn-core-ui": "^0.2.0", @@ -6630,9 +6629,9 @@ } }, "node_modules/@tomo-inc/tomo-wallet-provider": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@tomo-inc/tomo-wallet-provider/-/tomo-wallet-provider-1.0.21.tgz", - "integrity": "sha512-HyBHHKVa2L4/deWwHw7gASvmR9sTZJnF2hiG0iA+x9pAgPNAjbc60PkCiilYtP32ja3JT1G1VfhLXIPTdkrVLA==", + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/@tomo-inc/tomo-wallet-provider/-/tomo-wallet-provider-1.0.25.tgz", + "integrity": "sha512-P84NzQ6xiRuiQgVJqzfTWjpnlF65NbqYY/L5OaJZbpPSXaFAeNYClIUn40Okxkg/xKwryoOWEr4KzZxiOOVpxg==", "dependencies": { "events": "^3.3.0", "long": "^5.2.3" @@ -6651,11 +6650,11 @@ } }, "node_modules/@tomo-inc/wallet-connect-sdk": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/@tomo-inc/wallet-connect-sdk/-/wallet-connect-sdk-0.2.16.tgz", - "integrity": "sha512-ywYJZ8XC6daiqQgVLtPGeMXKSBd0q2Bm4saD9EhjT+yXVG4vDHvBbp0CWPx+MoEzWj/0GBgW33JkbPRS5fvBaA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@tomo-inc/wallet-connect-sdk/-/wallet-connect-sdk-0.3.3.tgz", + "integrity": "sha512-dtfmwL3Rko73WqwbY8cyP793m4Lq/zssPEy0OOSuVl2y6ABvoQRw2Zh+9DhET6U9wt7NP/OYuYYm7F3rwST1fg==", "dependencies": { - "@tomo-inc/tomo-wallet-provider": "^1.0.21", + "@tomo-inc/tomo-wallet-provider": "^1.0.25", "animate.css": "^4.1.1", "buffer": "^6.0.3", "classnames": "^2.5.1", @@ -6663,8 +6662,6 @@ "immutability-helper": "^3.1.1", "jotai": "^2.9.0", "long": "^5.2.3", - "react": "^18", - "react-dom": "^18", "tailwind-merge": "2.2.2" }, "peerDependencies": { @@ -14679,9 +14676,9 @@ } }, "node_modules/jotai": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.10.1.tgz", - "integrity": "sha512-4FycO+BOTl2auLyF2Chvi6KTDqdsdDDtpaL/WHQMs8f3KS1E3loiUShQzAzFA/sMU5cJ0hz/RT1xum9YbG/zaA==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.10.3.tgz", + "integrity": "sha512-Nnf4IwrLhNfuz2JOQLI0V/AgwcpxvVy8Ec8PidIIDeRi4KCFpwTFIpHAAcU+yCgnw/oASYElq9UY0YdUUegsSA==", "license": "MIT", "engines": { "node": ">=12.20.0" diff --git a/package.json b/package.json index 292aa783..97363676 100644 --- a/package.json +++ b/package.json @@ -27,7 +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.23", + "@babylonlabs-io/bbn-wallet-connect": "^0.1.6", "@babylonlabs-io/btc-staking-ts": "0.4.0-canary.3", "@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3", "@bitcoinerlab/secp256k1": "^1.1.1", @@ -40,7 +40,7 @@ "@sentry/nextjs": "^8.30.0", "@tanstack/react-query": "^5.28.14", "@tanstack/react-query-next-experimental": "^5.28.14", - "@tomo-inc/wallet-connect-sdk": "0.2.16", + "@tomo-inc/wallet-connect-sdk": "^0.3.3", "@uidotdev/usehooks": "^2.4.1", "axios": "^1.7.4", "bitcoinjs-lib": "6.1.5", diff --git a/src/app/context/tomo/BBNConnector.tsx b/src/app/context/tomo/BBNConnector.tsx new file mode 100644 index 00000000..528b8b55 --- /dev/null +++ b/src/app/context/tomo/BBNConnector.tsx @@ -0,0 +1,81 @@ +import { + createExternalWallet, + IBBNProvider, + useChainConnector, + useWidgetState, +} from "@babylonlabs-io/bbn-wallet-connect"; +import { + CosmosProvider, + useTomoProviders, + useTomoWalletConnect, + useTomoWalletState, + useWalletList, +} from "@tomo-inc/wallet-connect-sdk"; +import { memo, useCallback, useEffect, useMemo } from "react"; + +const createProvider = (provider: CosmosProvider): IBBNProvider => { + return { + connectWallet: async () => void provider.connectWallet(), + getAddress: () => provider.getAddress(), + getPublicKeyHex: async () => "", + getSigningStargateClient: (options) => + provider.getSigningStargateClient(options), + getBalance: (searchDenom) => provider.getBalance(searchDenom), + }; +}; + +export const TomoBBNConnector = memo(() => { + const tomoWalletState = useTomoWalletState(); + const walletList = useWalletList(); + const { cosmosProvider: connectedProvider } = useTomoProviders(); + const tomoWalletConnect = useTomoWalletConnect(); + + const { visible } = useWidgetState(); + const connector = useChainConnector("BBN"); + + const connectedWallet = useMemo(() => { + const { connected, walletId } = tomoWalletState.cosmos ?? {}; + + return connected && walletId + ? (walletList.find((wallet: any) => wallet.id === walletId) ?? null) + : null; + }, [tomoWalletState.cosmos, walletList]); + + const connect = useCallback( + async (bbnWallet: any, bbnProvider: CosmosProvider) => { + if (!connector) return; + + const wallet = createExternalWallet({ + id: "tomo-bbn-connector", + name: bbnWallet.name, + icon: bbnWallet.img, + provider: createProvider(bbnProvider), + }); + + await connector.connect(wallet); + }, + [connector], + ); + + useEffect(() => { + if (visible && connectedWallet && connectedProvider) { + connect(connectedWallet, connectedProvider); + } + }, [visible, connectedWallet, connectedProvider, connect]); + + useEffect(() => { + if (!connector) return; + + const unsubscribe = connector.on("disconnect", (wallet) => { + if (wallet.id === "tomo-bbn-connector") { + tomoWalletConnect.disconnect(); + } + }); + + return unsubscribe; + }, [connector, tomoWalletConnect]); + + return null; +}); + +TomoBBNConnector.displayName = "TomoBBNConnector"; diff --git a/src/app/context/tomo/BTCConnector.tsx b/src/app/context/tomo/BTCConnector.tsx new file mode 100644 index 00000000..9a7b2c44 --- /dev/null +++ b/src/app/context/tomo/BTCConnector.tsx @@ -0,0 +1,104 @@ +import { + createExternalWallet, + IBTCProvider, + useChainConnector, + useWidgetState, +} from "@babylonlabs-io/bbn-wallet-connect"; +import { + BTCProvider, + useTomoProviders, + useTomoWalletConnect, + useTomoWalletState, + useWalletList, +} from "@tomo-inc/wallet-connect-sdk"; +import { memo, useCallback, useEffect, useMemo } from "react"; + +const createProvider = (provider: BTCProvider): IBTCProvider => { + return { + connectWallet: async () => void provider.connectWallet(), + getAddress: () => provider.getAddress(), + getPublicKeyHex: () => provider.getPublicKeyHex(), + signPsbt: (psbtHex: string) => provider.signPsbt(psbtHex), + signPsbts: (psbtsHexes: string[]) => provider.signPsbts(psbtsHexes), + getNetwork: () => provider.getNetwork(), + signMessageBIP322: (message: string) => provider.signMessageBIP322(message), + signMessage: (message: string, type: "ecdsa" | "bip322-simple") => + provider.signMessage(message, type), + on: (eventName: string, callBack: () => void) => + provider.on(eventName, callBack), + off: (eventName: string, callBack: () => void) => + provider.off(eventName, callBack), + getBalance: () => provider.getBalance(), + getNetworkFees: () => provider.getNetworkFees(), + pushTx: (txHex: string) => provider.pushTx(txHex), + getUtxos: (address: string, amount?: number) => + provider.getUtxos(address, amount), + getBTCTipHeight: () => provider.getBTCTipHeight(), + getInscriptions: () => + provider + .getInscriptions() + .then((result) => + result.list.map((ordinal) => ({ + txid: ordinal.inscriptionId, + vout: ordinal.outputValue, + })), + ) + .catch(() => []), + }; +}; + +export const TomoBTCConnector = memo(() => { + const tomoWalletState = useTomoWalletState(); + const walletList = useWalletList(); + const { bitcoinProvider: connectedProvider } = useTomoProviders(); + const tomoWalletConnect = useTomoWalletConnect(); + + const { visible } = useWidgetState(); + const connector = useChainConnector("BTC"); + + const connectedWallet = useMemo(() => { + const { connected, walletId } = tomoWalletState.bitcoin ?? {}; + + return connected && walletId + ? (walletList.find((wallet: any) => wallet.id === walletId) ?? null) + : null; + }, [tomoWalletState.bitcoin, walletList]); + + const connect = useCallback( + async (btcWallet: any, btcProvider: BTCProvider) => { + if (!connector) return; + + const wallet = createExternalWallet({ + id: "tomo-btc-connector", + name: btcWallet.name, + icon: btcWallet.img, + provider: createProvider(btcProvider), + }); + + await connector.connect(wallet); + }, + [connector], + ); + + useEffect(() => { + if (visible && connectedWallet && connectedProvider) { + connect(connectedWallet, connectedProvider); + } + }, [visible, connectedWallet, connectedProvider, connect]); + + useEffect(() => { + if (!connector) return; + + const unsubscribe = connector.on("disconnect", (wallet) => { + if (wallet.id === "tomo-btc-connector") { + tomoWalletConnect.disconnect(); + } + }); + + return unsubscribe; + }, [connector, tomoWalletConnect]); + + return null; +}); + +TomoBTCConnector.displayName = "TomoBTCConnector"; diff --git a/src/app/context/tomo/ConnectButton.tsx b/src/app/context/tomo/ConnectButton.tsx new file mode 100644 index 00000000..8660a726 --- /dev/null +++ b/src/app/context/tomo/ConnectButton.tsx @@ -0,0 +1,38 @@ +import { Text } from "@babylonlabs-io/bbn-core-ui"; +import { + useWidgetState, + WalletButton, +} from "@babylonlabs-io/bbn-wallet-connect"; +import { useTomoModalControl } from "@tomo-inc/wallet-connect-sdk"; +import { useCallback } from "react"; + +import logo from "./tomo.png"; + +const CHAINS = { + bitcoin: "BTC", + cosmos: "BBN", +}; + +export const ConnectButton = ({ + chainName, +}: { + chainName: "bitcoin" | "cosmos"; +}) => { + const tomoModal = useTomoModalControl(); + const { displayWallets } = useWidgetState(); + + const open = useCallback(async () => { + const result = await tomoModal.open(chainName); + + if (!result) { + displayWallets?.(CHAINS[chainName]); + } + }, [tomoModal, chainName, displayWallets]); + + return ( +