Skip to content

Commit

Permalink
tomo dual wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
gbarkhatov committed Oct 17, 2024
1 parent d4c69c8 commit f5504c3
Show file tree
Hide file tree
Showing 42 changed files with 2,096 additions and 1,521 deletions.
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
10 changes: 5 additions & 5 deletions docs/WalletIntegration.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const DEFAULT_INSCRIPTION_LIMIT = 100;
* Provides methods for connecting to a wallet, retrieving wallet information, signing transactions, and more.
*/

export abstract class WalletProvider {
export abstract class BTCWalletProvider {
/**
* Connects to the wallet and returns the instance of the wallet provider.
* Currently only supports "native segwit" and "taproot" address types.
Expand Down Expand Up @@ -189,7 +189,7 @@ instance of it under the `window.btcwallet` global object when the Babylon dApp
is loaded.

```ts
class MobileAppWallet extends WalletProvider {
class MobileAppWallet extends BTCWalletProvider {
...
Interface Methods definitions
...
Expand All @@ -211,7 +211,7 @@ are implemented using external calls to the mempool.space API as they are not
provided out of the box from the wallet exposed methods.

```ts
import { WalletProvider, Network, Fees, UTXO } from "../wallet_provider";
import { BTCWalletProvider, Network, Fees, UTXO } from "../btc_wallet_provider";
import {
getAddressBalance,
getTipHeight,
Expand All @@ -225,7 +225,7 @@ type OKXWalletInfo = {
address: string;
};

export class OKXWallet extends WalletProvider {
export class OKXWallet extends BTCWalletProvider {
private okxWalletInfo: OKXWalletInfo | undefined;

constructor() {
Expand Down Expand Up @@ -392,7 +392,7 @@ export class OKXWallet extends WalletProvider {
As a reference, we provide the mempool.space retrieval methods that we used below:

```ts
import { Fees, UTXO } from "./wallet/wallet_provider";
import { Fees, UTXO } from "./wallet/btc_wallet_provider";

/*
URL Construction methods
Expand Down
3,061 changes: 1,692 additions & 1,369 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"node": "22.3.0"
},
"dependencies": {
"@babylonlabs-io/btc-staking-ts": "0.3.0",
"@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3",
"@bitcoinerlab/secp256k1": "^1.1.1",
"@keystonehq/animated-qr": "^0.8.6",
Expand All @@ -33,10 +34,10 @@
"@scure/bip32": "^1.4.0",
"@tanstack/react-query": "^5.28.14",
"@tanstack/react-query-next-experimental": "^5.28.14",
"@tomo-inc/wallet-connect-sdk": "^0.2.4",
"@uidotdev/usehooks": "^2.4.1",
"axios": "^1.7.4",
"bitcoinjs-lib": "6.1.5",
"@babylonlabs-io/btc-staking-ts": "0.3.0",
"date-fns": "^3.6.0",
"decimal.js-light": "^2.5.1",
"framer-motion": "^11.1.9",
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/postFilterOrdinals.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { chunkArray } from "@/utils/chunkArray";
import { UTXO } from "@/utils/wallet/wallet_provider";
import { UTXO } from "@/utils/wallet/btc_wallet_provider";

import { apiWrapper } from "./apiWrapper";

Expand Down
11 changes: 7 additions & 4 deletions src/app/common/utils/psbt.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Psbt, Transaction } from "bitcoinjs-lib";

import { WalletProvider } from "@/utils/wallet/wallet_provider";
import { BTCWalletProvider } from "@/utils/wallet/btc_wallet_provider";

const SIGN_PSBT_NOT_COMPATIBLE_WALLETS = ["OneKey"];

Expand All @@ -9,10 +9,13 @@ export type SignPsbtTransaction = (psbtHex: string) => Promise<Transaction>;
// This method is created to accommodate backward compatibility with the
// old implementation of signPsbt where the wallet.signPsbt method returns
// the signed transaction in hex
export const signPsbtTransaction = (wallet: WalletProvider) => {
export const signPsbtTransaction = (
signPsbt: BTCWalletProvider["signPsbt"],
getWalletProviderName: BTCWalletProvider["getWalletProviderName"],
) => {
return async (psbtHex: string) => {
const signedHex = await wallet.signPsbt(psbtHex);
const providerName = await wallet.getWalletProviderName();
const signedHex = await signPsbt(psbtHex);
const providerName = await getWalletProviderName();
if (SIGN_PSBT_NOT_COMPATIBLE_WALLETS.includes(providerName)) {
try {
// Try to parse the signedHex as PSBT to see if it follows the new implementation
Expand Down
25 changes: 14 additions & 11 deletions src/app/components/Delegations/Delegations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import InfiniteScroll from "react-infinite-scroll-component";
import { useLocalStorage } from "usehooks-ts";

import {
signPsbtTransaction,
SignPsbtTransaction,
signPsbtTransaction,
} from "@/app/common/utils/psbt";
import { LoadingTableList } from "@/app/components/Loading/Loading";
import { DelegationsPointsProvider } from "@/app/context/api/DelegationsPointsProvider";
import { useError } from "@/app/context/Error/ErrorContext";
import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useBTCWallet } from "@/app/context/wallet/WalletProvider";
import { useDelegations } from "@/app/hooks/useDelegations";
import { useHealthCheck } from "@/app/hooks/useHealthCheck";
import { useAppState } from "@/app/state";
Expand All @@ -26,7 +26,7 @@ import { signUnbondingTx } from "@/utils/delegations/signUnbondingTx";
import { signWithdrawalTx } from "@/utils/delegations/signWithdrawalTx";
import { getIntermediateDelegationsLocalStorageKey } from "@/utils/local_storage/getIntermediateDelegationsLocalStorageKey";
import { toLocalStorageIntermediateDelegation } from "@/utils/local_storage/toLocalStorageIntermediateDelegation";
import { WalletProvider } from "@/utils/wallet/wallet_provider";
import { BTCWalletProvider } from "@/utils/wallet/btc_wallet_provider";

import {
MODE,
Expand All @@ -41,14 +41,17 @@ export const Delegations = () => {
const { currentVersion } = useAppState();
const { data: delegationsAPI } = useDelegations();
const {
walletProvider: btcWallet,
address,
publicKeyNoCoord,
connected,
network,
} = useWallet();
pushTx,
getNetworkFees,
signPsbt,
getWalletProviderName,
} = useBTCWallet();

if (!btcWallet || !delegationsAPI || !currentVersion || !network) {
if (!connected || !delegationsAPI || !currentVersion || !network) {
return;
}

Expand All @@ -63,9 +66,9 @@ export const Delegations = () => {
<DelegationsContent
delegationsAPI={delegationsAPI.delegations}
globalParamsVersion={currentVersion}
signPsbtTx={signPsbtTransaction(btcWallet)}
pushTx={btcWallet.pushTx}
getNetworkFees={btcWallet.getNetworkFees}
signPsbtTx={signPsbtTransaction(signPsbt, getWalletProviderName)}
pushTx={pushTx}
getNetworkFees={getNetworkFees}
address={address}
btcWalletNetwork={network}
publicKeyNoCoord={publicKeyNoCoord}
Expand All @@ -83,8 +86,8 @@ interface DelegationsContentProps {
btcWalletNetwork: networks.Network;
address: string;
signPsbtTx: SignPsbtTransaction;
pushTx: WalletProvider["pushTx"];
getNetworkFees: WalletProvider["getNetworkFees"];
pushTx: BTCWalletProvider["pushTx"];
getNetworkFees: BTCWalletProvider["getNetworkFees"];
isWalletConnected: boolean;
}

Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useBTCWallet } from "@/app/context/wallet/WalletProvider";
import { useAppState } from "@/app/state";
import { shouldDisplayTestingMsg } from "@/config";

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

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

return (
Expand Down
6 changes: 3 additions & 3 deletions src/app/components/Modals/ConnectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import { Tooltip } from "react-tooltip";
import { twJoin } from "tailwind-merge";

import { getNetworkConfig } from "@/config/network.config";
import { BTCWalletProvider } from "@/utils/wallet/btc_wallet_provider";
import { BROWSER_INJECTED_WALLET_NAME, walletList } from "@/utils/wallet/list";
import { WalletProvider } from "@/utils/wallet/wallet_provider";

import { GeneralModal } from "./GeneralModal";

interface ConnectModalProps {
open: boolean;
onClose: (value: boolean) => void;
onConnect: (walletProvider: WalletProvider) => void;
onConnect: (walletProvider: BTCWalletProvider) => void;
connectDisabled: boolean;
}

Expand Down Expand Up @@ -69,7 +69,7 @@ export const ConnectModal: React.FC<ConnectModalProps> = ({

const handleConnect = async () => {
if (selectedWallet) {
let walletInstance: WalletProvider;
let walletInstance: BTCWalletProvider;

if (selectedWallet === BROWSER) {
if (!isInjectable) {
Expand Down
12 changes: 6 additions & 6 deletions src/app/components/NetworkBadge/NetworkBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import Image from "next/image";
import { twJoin } from "tailwind-merge";

import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useBTCWallet } from "@/app/context/wallet/WalletProvider";
import { network } from "@/config/network.config";
import { Network } from "@/utils/wallet/wallet_provider";
import { Network } from "@/utils/wallet/btc_wallet_provider";

import testnetIcon from "./testnet-icon.png";

export const NetworkBadge = () => {
const { walletProvider } = useWallet();
const { connected } = useBTCWallet();

return (
<div
className={twJoin(
`absolute left-2`,
Boolean(walletProvider)
Boolean(connected)
? "top-40 md:top-24 lg:top-32"
: "top-24 md:top-24 lg:top-32",
)}
>
{[Network.SIGNET, Network.TESTNET].includes(network) && (
<>
<Image src={testnetIcon} alt="Testnet" className="w-[10rem]" />
{/*
{/*
currently the text is absolutely positioned
since the image has a shadow
since the image has a shadow
*/}
<p className="absolute left-4 top-[4rem] text-sm dark:text-neutral-content">
Testnet
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Staking/Form/StakingFee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { getFeeRateFromMempool } from "@/utils/getFeeRateFromMempool";
import { Fees } from "@/utils/wallet/wallet_provider";
import { Fees } from "@/utils/wallet/btc_wallet_provider";

import { LoadingSmall } from "../../Loading/Loading";

Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Staking/Form/States/WalletNotConnected.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Image from "next/image";

import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useBTCWallet } from "@/app/context/wallet/WalletProvider";

import connectIcon from "./connect-icon.svg";
import walletIcon from "./wallet-icon.svg";

export const WalletNotConnected = () => {
const { open } = useWallet();
const { open } = useBTCWallet();

return (
<div className="flex flex-1 flex-col">
Expand Down
21 changes: 13 additions & 8 deletions src/app/components/Staking/Staking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
OVERFLOW_TVL_WARNING_THRESHOLD,
UTXO_KEY,
} from "@/app/common/constants";
import { signPsbtTransaction } from "@/app/common/utils/psbt";
import { LoadingView } from "@/app/components/Loading/Loading";
import { useError } from "@/app/context/Error/ErrorContext";
import { useStakingStats } from "@/app/context/api/StakingStatsProvider";
import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useBTCWallet } from "@/app/context/wallet/WalletProvider";
import { useHealthCheck } from "@/app/hooks/useHealthCheck";
import { useAppState } from "@/app/state";
import { useDelegationState } from "@/app/state/DelegationState";
Expand Down Expand Up @@ -67,9 +68,12 @@ export const Staking = () => {
connected,
address,
publicKeyNoCoord,
walletProvider: btcWallet,
network: btcWalletNetwork,
} = useWallet();
getNetworkFees,
signPsbt,
getWalletProviderName,
pushTx,
} = useBTCWallet();

const disabled = isError;

Expand Down Expand Up @@ -110,11 +114,11 @@ export const Staking = () => {
} = useQuery({
queryKey: ["mempool fee rates"],
queryFn: async () => {
if (btcWallet?.getNetworkFees) {
return await btcWallet.getNetworkFees();
if (getNetworkFees) {
return await getNetworkFees();
}
},
enabled: Boolean(btcWallet?.getNetworkFees),
enabled: Boolean(connected) && Boolean(getNetworkFees),
refetchInterval: 60000, // 1 minute
retry: (failureCount) => {
return !isErrorOpen && failureCount <= 3;
Expand Down Expand Up @@ -221,7 +225,7 @@ export const Staking = () => {
// Prevent the modal from closing
setAwaitingWalletResponse(true);
// Initial validation
if (!btcWallet) throw new Error("Wallet is not connected");
if (!connected) throw new Error("Wallet is not connected");
if (!address) throw new Error("Address is not set");
if (!btcWalletNetwork) throw new Error("Wallet network is not connected");
if (!finalityProvider)
Expand All @@ -233,7 +237,8 @@ export const Staking = () => {

// Sign the staking transaction
const { stakingTxHex, stakingTerm } = await signStakingTx(
btcWallet,
signPsbtTransaction(signPsbt, getWalletProviderName),
pushTx,
currentVersion,
stakingAmountSat,
stakingTimeBlocks,
Expand Down
6 changes: 3 additions & 3 deletions src/app/components/Summary/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { AiOutlineInfoCircle } from "react-icons/ai";
import { FaBitcoin } from "react-icons/fa";
import { Tooltip } from "react-tooltip";

import { useWallet } from "@/app/context/wallet/WalletProvider";
import { useBTCWallet } from "@/app/context/wallet/WalletProvider";
import { useHealthCheck } from "@/app/hooks/useHealthCheck";
import { useAppState } from "@/app/state";
import { useDelegationState } from "@/app/state/DelegationState";
import { shouldDisplayPoints } from "@/config";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btcConversions";
import { maxDecimals } from "@/utils/maxDecimals";
import { Network } from "@/utils/wallet/wallet_provider";
import { Network } from "@/utils/wallet/btc_wallet_provider";

import { LoadingSmall } from "../Loading/Loading";
import { StakerPoints } from "../Points/StakerPoints";
Expand All @@ -19,7 +19,7 @@ export const Summary = () => {
const { isApiNormal, isGeoBlocked } = useHealthCheck();
const { totalStaked } = useDelegationState();
const { totalBalance, currentVersion, isLoading: loading } = useAppState();
const { address, publicKeyNoCoord } = useWallet();
const { address, publicKeyNoCoord } = useBTCWallet();

const { coinName } = getNetworkConfig();
const onMainnet = getNetworkConfig().network === Network.MAINNET;
Expand Down
Loading

0 comments on commit f5504c3

Please sign in to comment.