diff --git a/src/app/hooks/use-leather.ts b/src/app/hooks/use-leather.ts index c8b13e6c..6dc02b37 100644 --- a/src/app/hooks/use-leather.ts +++ b/src/app/hooks/use-leather.ts @@ -26,21 +26,18 @@ import { BITCOIN_NETWORK_MAP } from '@shared/constants/bitcoin.constants'; interface UseLeatherReturnType { connectLeatherWallet: () => Promise; handleFundingTransaction: ( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ) => Promise; handleDepositTransaction: ( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ) => Promise; handleWithdrawalTransaction: ( - dlcHandler: SoftwareWalletDLCHandler, withdrawAmount: number, attestorGroupPublicKey: string, vault: RawVault, @@ -50,7 +47,7 @@ interface UseLeatherReturnType { } export function useLeather(): UseLeatherReturnType { - const { setDLCHandler, setBitcoinWalletContextState, setBitcoinWalletType } = + const { setDLCHandler, setBitcoinWalletContextState, setBitcoinWalletType, dlcHandler } = useContext(BitcoinWalletContext); const [isLoading, setIsLoading] = useState<[boolean, string]>([false, '']); @@ -151,13 +148,20 @@ export function useLeather(): UseLeatherReturnType { * @returns The Signed Funding Transaction. */ async function handleFundingTransaction( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new LeatherError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof SoftwareWalletDLCHandler)) { + throw new LeatherError('DLC Handler is not Software Wallet'); + } + setIsLoading([true, 'Creating Funding Transaction']); // ==> Create Funding Transaction @@ -190,13 +194,20 @@ export function useLeather(): UseLeatherReturnType { * @returns The Signed Deposit Transaction. */ async function handleDepositTransaction( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new LeatherError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof SoftwareWalletDLCHandler)) { + throw new LeatherError('DLC Handler is not Software Wallet'); + } + setIsLoading([true, 'Creating Deposit Transaction']); // ==> Create Deposit Transaction @@ -231,13 +242,20 @@ export function useLeather(): UseLeatherReturnType { } async function handleWithdrawalTransaction( - dlcHandler: SoftwareWalletDLCHandler, withdrawAmount: number, attestorGroupPublicKey: string, vault: RawVault, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new LeatherError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof SoftwareWalletDLCHandler)) { + throw new LeatherError('DLC Handler is not Software Wallet'); + } + setIsLoading([true, 'Creating Withdrawal Transaction']); const withdrawalTransaction = await dlcHandler.createWithdrawPSBT( diff --git a/src/app/hooks/use-ledger.ts b/src/app/hooks/use-ledger.ts index 2d2145e4..c13c9751 100644 --- a/src/app/hooks/use-ledger.ts +++ b/src/app/hooks/use-ledger.ts @@ -40,21 +40,18 @@ interface UseLedgerReturnType { paymentType: SupportedPaymentType ) => Promise; handleFundingTransaction: ( - dlcHandler: LedgerDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ) => Promise; handleDepositTransaction: ( - dlcHandler: LedgerDLCHandler, vault: RawVault, withdrawAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ) => Promise; handleWithdrawalTransaction: ( - dlcHandler: LedgerDLCHandler, withdrawAmount: number, attestorGroupPublicKey: string, vault: RawVault, @@ -64,7 +61,8 @@ interface UseLedgerReturnType { } export function useLedger(): UseLedgerReturnType { - const { setBitcoinWalletContextState, setDLCHandler } = useContext(BitcoinWalletContext); + const { setBitcoinWalletContextState, setDLCHandler, dlcHandler } = + useContext(BitcoinWalletContext); const [ledgerApp, setLedgerApp] = useState(undefined); const [isLoading, setIsLoading] = useState<[boolean, string]>([false, '']); @@ -227,13 +225,20 @@ export function useLedger(): UseLedgerReturnType { * @returns The Signed Funding Transaction. */ async function handleFundingTransaction( - dlcHandler: LedgerDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new LedgerError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof LedgerDLCHandler)) { + throw new LedgerError('DLC Handler is not Ledger Wallet'); + } + setIsLoading([true, 'Accept Multisig Wallet Policy on your Ledger Device']); // ==> Create Funding Transaction @@ -258,13 +263,20 @@ export function useLedger(): UseLedgerReturnType { } async function handleDepositTransaction( - dlcHandler: LedgerDLCHandler, vault: RawVault, withdrawAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new LedgerError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof LedgerDLCHandler)) { + throw new LedgerError('DLC Handler is not Ledger Wallet'); + } + setIsLoading([true, 'Accept Multisig Wallet Policy on your Ledger Device']); const depositPSBT = await dlcHandler.createDepositPSBT( @@ -288,13 +300,20 @@ export function useLedger(): UseLedgerReturnType { } async function handleWithdrawalTransaction( - dlcHandler: LedgerDLCHandler, withdrawAmount: number, attestorGroupPublicKey: string, vault: RawVault, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new LedgerError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof LedgerDLCHandler)) { + throw new LedgerError('DLC Handler is not Ledger Wallet'); + } + setIsLoading([true, 'Accept Multisig Wallet Policy on your Ledger Device']); const withdrawalPSBT = await dlcHandler.createWithdrawPSBT( diff --git a/src/app/hooks/use-psbt.ts b/src/app/hooks/use-psbt.ts index 745aa1bd..a440f113 100644 --- a/src/app/hooks/use-psbt.ts +++ b/src/app/hooks/use-psbt.ts @@ -5,7 +5,6 @@ import { BitcoinWalletType } from '@models/wallet'; import { bytesToHex } from '@noble/hashes/utils'; import { BitcoinWalletContext } from '@providers/bitcoin-wallet-context-provider'; import { EthereumNetworkConfigurationContext } from '@providers/ethereum-network-configuration.provider'; -import { LedgerDLCHandler, SoftwareWalletDLCHandler } from 'dlc-btc-lib'; import { submitFundingPSBT, submitWithdrawDepositPSBT, @@ -56,6 +55,30 @@ export function usePSBT(): UsePSBTReturnType { const [bitcoinDepositAmount, setBitcoinDepositAmount] = useState(0); + const handleFundingTransactionMap = { + [BitcoinWalletType.Ledger]: handleFundingTransactionWithLedger, + [BitcoinWalletType.Leather]: handleFundingTransactionWithLeather, + [BitcoinWalletType.Unisat]: handleFundingTransactionWithUnisat, + }; + + const handleDepositTransactionMap = { + [BitcoinWalletType.Ledger]: handleDepositTransactionWithLedger, + [BitcoinWalletType.Leather]: handleDepositTransactionWithLeather, + [BitcoinWalletType.Unisat]: handleDepositTransactionWithUnisat, + }; + + const handleWithdrawalTransactionMap = { + [BitcoinWalletType.Ledger]: handleWithdrawalTransactionWithLedger, + [BitcoinWalletType.Leather]: handleWithdrawalTransactionWithLeather, + [BitcoinWalletType.Unisat]: handleWithdrawalTransactionWithUnisat, + }; + + const loadingStateMap = { + [BitcoinWalletType.Ledger]: isLedgerLoading, + [BitcoinWalletType.Leather]: isLeatherLoading, + [BitcoinWalletType.Unisat]: isUnisatLoading, + }; + async function handleSignFundingTransaction( vaultUUID: string, depositAmount: number @@ -63,6 +86,7 @@ export function usePSBT(): UsePSBTReturnType { try { if (!dlcHandler) throw new Error('DLC Handler is not setup'); if (!ethereumUserAddress) throw new Error('User Address is not setup'); + if (!bitcoinWalletType) throw new Error('Bitcoin Wallet is not setup'); const feeRateMultiplier = import.meta.env.VITE_FEE_RATE_MULTIPLIER; @@ -70,95 +94,35 @@ export function usePSBT(): UsePSBTReturnType { const attestorGroupPublicKey = await getAttestorGroupPublicKey(dlcManagerContract); const vault = await getRawVault(dlcManagerContract, vaultUUID); + const isFundingTransaction = vault.valueLocked.toNumber() === 0; + + const fundingTransaction: Transaction = isFundingTransaction + ? await handleFundingTransactionMap[bitcoinWalletType]( + vault, + depositAmount, + attestorGroupPublicKey, + feeRateMultiplier + ) + : await handleDepositTransactionMap[bitcoinWalletType]( + vault, + depositAmount, + attestorGroupPublicKey, + feeRateMultiplier + ); - let fundingTransaction: Transaction; - switch (bitcoinWalletType) { - case 'Ledger': - switch (vault.valueLocked.toNumber()) { - case 0: - fundingTransaction = await handleFundingTransactionWithLedger( - dlcHandler as LedgerDLCHandler, - vault, - depositAmount, - attestorGroupPublicKey, - feeRateMultiplier - ); - break; - default: - fundingTransaction = await handleDepositTransactionWithLedger( - dlcHandler as LedgerDLCHandler, - vault, - depositAmount, - attestorGroupPublicKey, - feeRateMultiplier - ); - } - break; - case 'Unisat': - switch (vault.valueLocked.toNumber()) { - case 0: - fundingTransaction = await handleFundingTransactionWithUnisat( - dlcHandler as SoftwareWalletDLCHandler, - vault, - depositAmount, - attestorGroupPublicKey, - feeRateMultiplier - ); - break; - default: - fundingTransaction = await handleDepositTransactionWithUnisat( - dlcHandler as SoftwareWalletDLCHandler, - vault, - depositAmount, - attestorGroupPublicKey, - feeRateMultiplier - ); - break; - } - break; - case 'Leather': - switch (vault.valueLocked.toNumber()) { - case 0: - fundingTransaction = await handleFundingTransactionWithLeather( - dlcHandler as SoftwareWalletDLCHandler, - vault, - depositAmount, - attestorGroupPublicKey, - feeRateMultiplier - ); - break; - default: - fundingTransaction = await handleDepositTransactionWithLeather( - dlcHandler as SoftwareWalletDLCHandler, - vault, - depositAmount, - attestorGroupPublicKey, - feeRateMultiplier - ); - break; - } - break; - default: - throw new BitcoinError('Invalid Bitcoin Wallet Type'); - } - - switch (vault.status) { - case VaultState.READY: - await submitFundingPSBT([appConfiguration.coordinatorURL], { + vault.status === VaultState.READY + ? await submitFundingPSBT([appConfiguration.coordinatorURL], { vaultUUID, fundingPSBT: bytesToHex(fundingTransaction.toPSBT()), userEthereumAddress: ethereumUserAddress, userBitcoinTaprootPublicKey: dlcHandler.getTaprootDerivedPublicKey(), attestorChainID: ethereumNetworkConfiguration.ethereumAttestorChainID as AttestorChainID, - }); - break; - default: - await submitWithdrawDepositPSBT([appConfiguration.coordinatorURL], { + }) + : await submitWithdrawDepositPSBT([appConfiguration.coordinatorURL], { vaultUUID, withdrawDepositPSBT: bytesToHex(fundingTransaction.toPSBT()), }); - } setBitcoinDepositAmount(depositAmount); resetBitcoinWalletContext(); @@ -174,6 +138,7 @@ export function usePSBT(): UsePSBTReturnType { try { if (!dlcHandler) throw new Error('DLC Handler is not setup'); if (!ethereumUserAddress) throw new Error('User Address is not setup'); + if (!bitcoinWalletType) throw new Error('Bitcoin Wallet is not setup'); const feeRateMultiplier = import.meta.env.VITE_FEE_RATE_MULTIPLIER; @@ -182,40 +147,12 @@ export function usePSBT(): UsePSBTReturnType { const attestorGroupPublicKey = await getAttestorGroupPublicKey(dlcManagerContract); const vault = await getRawVault(dlcManagerContract, vaultUUID); - if (!bitcoinWalletType) throw new Error('Bitcoin Wallet is not setup'); - - let withdrawalTransactionHex: string; - switch (bitcoinWalletType) { - case 'Ledger': - withdrawalTransactionHex = await handleWithdrawalTransactionWithLedger( - dlcHandler as LedgerDLCHandler, - withdrawAmount, - attestorGroupPublicKey, - vault, - feeRateMultiplier - ); - break; - case 'Unisat': - withdrawalTransactionHex = await handleWithdrawalTransactionWithUnisat( - dlcHandler as SoftwareWalletDLCHandler, - withdrawAmount, - attestorGroupPublicKey, - vault, - feeRateMultiplier - ); - break; - case 'Leather': - withdrawalTransactionHex = await handleWithdrawalTransactionWithLeather( - dlcHandler as SoftwareWalletDLCHandler, - withdrawAmount, - attestorGroupPublicKey, - vault, - feeRateMultiplier - ); - break; - default: - throw new BitcoinError('Invalid Bitcoin Wallet Type'); - } + const withdrawalTransactionHex = await handleWithdrawalTransactionMap[bitcoinWalletType]( + withdrawAmount, + attestorGroupPublicKey, + vault, + feeRateMultiplier + ); await submitWithdrawDepositPSBT([appConfiguration.coordinatorURL], { vaultUUID, @@ -228,16 +165,10 @@ export function usePSBT(): UsePSBTReturnType { } } - const loadingStates = { - [BitcoinWalletType.Ledger]: isLedgerLoading, - [BitcoinWalletType.Leather]: isLeatherLoading, - [BitcoinWalletType.Unisat]: isUnisatLoading, - }; - return { handleSignFundingTransaction, handleSignWithdrawTransaction, bitcoinDepositAmount, - isLoading: bitcoinWalletType ? loadingStates[bitcoinWalletType] : [false, ''], + isLoading: bitcoinWalletType ? loadingStateMap[bitcoinWalletType] : [false, ''], }; } diff --git a/src/app/hooks/use-unisat.ts b/src/app/hooks/use-unisat.ts index a676d8e9..b59deabf 100644 --- a/src/app/hooks/use-unisat.ts +++ b/src/app/hooks/use-unisat.ts @@ -22,21 +22,18 @@ import { BITCOIN_NETWORK_MAP } from '@shared/constants/bitcoin.constants'; interface UseUnisatReturnType { connectUnisatWallet: () => Promise; handleFundingTransaction: ( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ) => Promise; handleDepositTransaction: ( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ) => Promise; handleWithdrawalTransaction: ( - dlcHandler: SoftwareWalletDLCHandler, withdrawAmount: number, attestorGroupPublicKey: string, vault: RawVault, @@ -46,7 +43,7 @@ interface UseUnisatReturnType { } export function useUnisat(): UseUnisatReturnType { - const { setDLCHandler, setBitcoinWalletContextState, setBitcoinWalletType } = + const { setDLCHandler, setBitcoinWalletContextState, setBitcoinWalletType, dlcHandler } = useContext(BitcoinWalletContext); const [isLoading, setIsLoading] = useState<[boolean, string]>([false, '']); @@ -191,12 +188,19 @@ export function useUnisat(): UseUnisatReturnType { * @returns The Signed Funding Transaction. */ async function handleFundingTransaction( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ): Promise { + if (!dlcHandler) { + throw new UnisatError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof SoftwareWalletDLCHandler)) { + throw new UnisatError('DLC Handler is not Software Wallet'); + } + try { setIsLoading([true, 'Creating Funding Transaction']); @@ -238,13 +242,20 @@ export function useUnisat(): UseUnisatReturnType { * @returns The Signed Deposit Transaction. */ async function handleDepositTransaction( - dlcHandler: SoftwareWalletDLCHandler, vault: RawVault, bitcoinAmount: number, attestorGroupPublicKey: string, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new UnisatError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof SoftwareWalletDLCHandler)) { + throw new UnisatError('DLC Handler is not Software Wallet'); + } + setIsLoading([true, 'Creating Deposit Transaction']); // ==> Create Deposit Transaction @@ -292,13 +303,20 @@ export function useUnisat(): UseUnisatReturnType { * @returns The Signed Withdrawal Transaction. */ async function handleWithdrawalTransaction( - dlcHandler: SoftwareWalletDLCHandler, withdrawAmount: number, attestorGroupPublicKey: string, vault: RawVault, feeRateMultiplier: number ): Promise { try { + if (!dlcHandler) { + throw new UnisatError('DLC Handler not initialized'); + } + + if (!(dlcHandler instanceof SoftwareWalletDLCHandler)) { + throw new UnisatError('DLC Handler is not Software Wallet'); + } + setIsLoading([true, 'Creating Withdrawal Transaction']); const withdrawalTransaction = await dlcHandler.createWithdrawPSBT(