diff --git a/config.mainnet.json b/config.mainnet.json
index 4aa113e3..a545d9ed 100644
--- a/config.mainnet.json
+++ b/config.mainnet.json
@@ -28,6 +28,16 @@
"name": "Smart Bitcoin Labs",
"addresses": ["0x46166fA874AAEDEA8d98b15F9A72C84e22Abe2A1"],
"logo": "/images/logos/sbl-logotype.svg"
+ },
+ {
+ "name": "Waterdrip Capital",
+ "addresses": ["0x2816f3528AD324E6089714DA8E89455f58739e68"],
+ "logo": "/images/logos/waterdrip-capital-logo.svg"
+ },
+ {
+ "name": "Pattern Research",
+ "addresses": ["0x707A141c5c19c25E2e6D50b214e39A4293B63234"],
+ "logo": "/images/logos/pattern-research-logo.svg"
}
],
"protocols": [
diff --git a/public/images/logos/fordefi-logo.svg b/public/images/logos/fordefi-logo.svg
new file mode 100644
index 00000000..0b9e22af
--- /dev/null
+++ b/public/images/logos/fordefi-logo.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/logos/pattern-research-logo.svg b/public/images/logos/pattern-research-logo.svg
new file mode 100644
index 00000000..ce361332
--- /dev/null
+++ b/public/images/logos/pattern-research-logo.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/logos/waterdrip-capital-logo.svg b/public/images/logos/waterdrip-capital-logo.svg
new file mode 100644
index 00000000..73ee4f5a
--- /dev/null
+++ b/public/images/logos/waterdrip-capital-logo.svg
@@ -0,0 +1,99 @@
+
+
diff --git a/src/app/components/modals/ledger-modal/components/ledger-modal-error-box.tsx b/src/app/components/modals/ledger-modal/components/ledger-modal-error-box.tsx
index 61bb04c6..9ee0c172 100644
--- a/src/app/components/modals/ledger-modal/components/ledger-modal-error-box.tsx
+++ b/src/app/components/modals/ledger-modal/components/ledger-modal-error-box.tsx
@@ -5,13 +5,19 @@ interface LedgerModalErrorBoxProps {
}
function formatErrorMessage(error: string): string {
- if (error.includes('0x6985')) {
- return 'Action Rejected by User';
- } else if (error.includes('0x5515')) {
- return 'Locked Device';
- } else {
- return error;
+ const errorMessages: Record = {
+ '0x6985': 'Action Rejected by User',
+ '0x5515': 'Locked Device',
+ '0x6a80':
+ "Invalid data received. Please ensure your Ledger hardware's firmware and Bitcoin app are up to date",
+ };
+
+ for (const [code, message] of Object.entries(errorMessages)) {
+ if (error.includes(code)) {
+ return message;
+ }
}
+ return error;
}
export function LedgerModalErrorBox({
diff --git a/src/app/components/modals/select-bitcoin-wallet-modal/components/update-bitcoin-wallet-message.tsx b/src/app/components/modals/select-bitcoin-wallet-modal/components/update-bitcoin-wallet-message.tsx
new file mode 100644
index 00000000..debe56df
--- /dev/null
+++ b/src/app/components/modals/select-bitcoin-wallet-modal/components/update-bitcoin-wallet-message.tsx
@@ -0,0 +1,33 @@
+import { Link, Text, VStack } from '@chakra-ui/react';
+
+export function UpdateBitcoinWalletMessage(): React.JSX.Element {
+ return (
+
+
+ Before proceeding, please make sure your Bitcoin Wallet is up to date.
+
+
+ If you are using Ledger, ensure both the device firmware and Bitcoin App are updated to
+ avoid errors.
+
+
+ Use{' '}
+
+ Ledger Live
+ {' '}
+ to update both firmware and the app easily.
+
+
+ );
+}
diff --git a/src/app/components/modals/select-bitcoin-wallet-modal/select-bitcoin-wallet-modal.tsx b/src/app/components/modals/select-bitcoin-wallet-modal/select-bitcoin-wallet-modal.tsx
index 7af33fc0..6e7899db 100644
--- a/src/app/components/modals/select-bitcoin-wallet-modal/select-bitcoin-wallet-modal.tsx
+++ b/src/app/components/modals/select-bitcoin-wallet-modal/select-bitcoin-wallet-modal.tsx
@@ -9,6 +9,7 @@ import { BitcoinWalletType, bitcoinWallets } from '@models/wallet';
import { modalActions } from '@store/slices/modal/modal.actions';
import { SelectBitcoinWalletMenu } from './components/select-bitcoin-wallet-modal-menu';
+import { UpdateBitcoinWalletMessage } from './components/update-bitcoin-wallet-message';
export function SelectBitcoinWalletModal({
isOpen,
@@ -47,6 +48,19 @@ export function SelectBitcoinWalletModal({
});
}
break;
+ case BitcoinWalletType.Fordefi:
+ try {
+ await connectUnisatWallet(true);
+ } catch (error: any) {
+ toast({
+ title: 'Failed to connect to Unisat Wallet',
+ description: error.message,
+ status: 'error',
+ duration: 9000,
+ isClosable: true,
+ });
+ }
+ break;
case BitcoinWalletType.Ledger:
dispatch(modalActions.toggleLedgerModalVisibility());
break;
@@ -66,6 +80,7 @@ export function SelectBitcoinWalletModal({
handleClick={() => handleLogin(wallet.id)}
/>
))}
+
);
diff --git a/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/components/transaction-screen.transaction-form.wallet-information.tsx b/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/components/transaction-screen.transaction-form.wallet-information.tsx
index 848fdcca..6af6bb24 100644
--- a/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/components/transaction-screen.transaction-form.wallet-information.tsx
+++ b/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/components/transaction-screen.transaction-form.wallet-information.tsx
@@ -1,12 +1,5 @@
-import { HStack, Text, keyframes } from '@chakra-ui/react';
-
-const borderColorKeyframes = keyframes`
- 0% { border-color: rgba(255, 168, 0, 0.11); }
- 25% { border-color: rgba(255, 168, 0, 0.3); }
- 50% { border-color: rgba(255, 168, 0, 0.5); }
- 75% { border-color: rgba(255, 168, 0, 0.7); }
- 100% { border-color: rgba(255, 168, 0, 0.1); }
-`;
+import { HStack, Text } from '@chakra-ui/react';
+import { orangeBoxShadowAnimation } from '@styles/css-styles';
interface TransactionScreenWalletInformationProps {
isBitcoinWalletLoading: [boolean, string];
@@ -22,9 +15,11 @@ export function TransactionScreenWalletInformation({
w={'100%'}
bgColor={'background.content.01'}
justifyContent={'space-between'}
- border={'1px solid'}
+ border={'2px solid transparent'}
borderRadius={'md'}
- animation={`${borderColorKeyframes} 2s linear infinite`}
+ css={{
+ animation: `${orangeBoxShadowAnimation} 1.5s infinite ease-in-out`,
+ }}
>
diff --git a/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/transaction-screen.transaction-form.tsx b/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/transaction-screen.transaction-form.tsx
index b93af6e5..917c90c5 100644
--- a/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/transaction-screen.transaction-form.tsx
+++ b/src/app/components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/transaction-screen.transaction-form.tsx
@@ -8,6 +8,7 @@ import { BitcoinTransactionConfirmationsContext } from '@providers/bitcoin-query
import { BitcoinWalletContextState } from '@providers/bitcoin-wallet-context-provider';
import { useForm } from '@tanstack/react-form';
import Decimal from 'decimal.js';
+import { isEmpty } from 'ramda';
import { TransactionFormNavigateButtonGroup } from './components/transaction-screen.transaction-form.navigate-button-group';
import { TransactionFormProgressStack } from './components/transaction-screen.transaction-form.progress-stack/components/transaction-screen.transaction-form.progress-stack';
@@ -140,7 +141,8 @@ export function VaultTransactionForm({
},
validators: {
onChange: ({ value }) => {
- setCurrentFieldValue(new Decimal(value.assetAmount).toNumber());
+ const assetAmount = value.assetAmount;
+ setCurrentFieldValue(isEmpty(assetAmount) ? 0 : new Decimal(value.assetAmount).toNumber());
return {
fields: {
assetAmount: validateFormAmount(
diff --git a/src/app/components/vault/components/vault.detaills/components/vault.details.button-group/vault.details.button-group.tsx b/src/app/components/vault/components/vault.detaills/components/vault.details.button-group/vault.details.button-group.tsx
index 45d00dce..7d63307b 100644
--- a/src/app/components/vault/components/vault.detaills/components/vault.details.button-group/vault.details.button-group.tsx
+++ b/src/app/components/vault/components/vault.detaills/components/vault.details.button-group/vault.details.button-group.tsx
@@ -1,4 +1,4 @@
-import { Divider, HStack, VStack } from '@chakra-ui/react';
+import { HStack, VStack } from '@chakra-ui/react';
import { VaultState } from 'dlc-btc-lib/models';
import { VaultExpandedInformationButton } from './components/vault.details.button-group.button';
@@ -36,8 +36,7 @@ export function VaultExpandedInformationButtonGroup({
return (
-
-
+
-
-
+
+
+
+
+
Promise;
+ connectUnisatWallet: (isFordefi?: boolean) => Promise;
handleFundingTransaction: (
dlcHandler: SoftwareWalletDLCHandler,
vault: RawVault,
@@ -131,10 +131,16 @@ export function useUnisat(): UseUnisatReturnType {
*
* @returns A promise that resolves to the user's taproot address.
*/
- async function getBitcoinAddresses(): Promise {
+ async function getBitcoinAddresses(isFordefi: boolean = false): Promise {
try {
if (!window.unisat) {
- throw new UnisatError('Unisat Wallet is not installed');
+ throw new UnisatError(
+ isFordefi ? 'Fordefi Wallet is Not Installed' : 'Unisat Wallet is Not Installed'
+ );
+ } else if (isFordefi && !window?.unisat?.is_fordefi) {
+ throw new UnisatError('Please disable Unisat Wallet and enable Fordefi Wallet');
+ } else if (!isFordefi && window?.unisat?.is_fordefi) {
+ throw new UnisatError('Please disable Fordefi Wallet and enable Unisat Wallet');
}
const userAddresses: string[] = await window.unisat.requestAccounts();
@@ -159,11 +165,11 @@ export function useUnisat(): UseUnisatReturnType {
*
* @returns A promise that resolves to the User's Taproot Address.
*/
- async function connectUnisatWallet(): Promise {
+ async function connectUnisatWallet(isFordefi: boolean = false): Promise {
try {
setIsLoading([true, 'Connecting To Unisat Wallet']);
- const taprootAccount = await getBitcoinAddresses();
+ const taprootAccount = await getBitcoinAddresses(isFordefi);
const unisatDLCHandler = new SoftwareWalletDLCHandler(
taprootAccount.publicKey,
diff --git a/src/shared/models/wallet.ts b/src/shared/models/wallet.ts
index 31189491..2b7fbb1f 100644
--- a/src/shared/models/wallet.ts
+++ b/src/shared/models/wallet.ts
@@ -2,6 +2,7 @@ export enum BitcoinWalletType {
Leather = 'Leather',
Ledger = 'Ledger',
Unisat = 'Unisat',
+ Fordefi = 'Fordefi',
}
export interface BitcoinWallet {
@@ -28,4 +29,10 @@ const unisat: BitcoinWallet = {
logo: '/images/logos/unisat-logo.svg',
};
-export const bitcoinWallets: BitcoinWallet[] = [leather, ledger, unisat];
+const fordefi: BitcoinWallet = {
+ id: BitcoinWalletType.Fordefi,
+ name: 'Fordefi',
+ logo: '/images/logos/fordefi-logo.svg',
+};
+
+export const bitcoinWallets: BitcoinWallet[] = [leather, ledger, unisat, fordefi];
diff --git a/src/shared/utils.ts b/src/shared/utils.ts
index be70a651..bdf6bdc2 100644
--- a/src/shared/utils.ts
+++ b/src/shared/utils.ts
@@ -37,11 +37,14 @@ export function findEthereumNetworkByName(ethereumNetworkName: string): Chain {
export function formatEvent(event: DetailedEvent): FormattedEvent {
const isMint = event.eventType === 'mint';
+ const date = new Date(event.timestamp * 1000);
return {
dlcBTCAmount: isMint ? event.value : -event.value,
merchant: isMint ? event.to : event.from,
txHash: event.txHash,
- date: new Date(event.timestamp * 1000).toDateString(),
+ date: date
+ .toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
+ .replace(',', ''),
isMint,
chain: event.chain,
isCCIP: event.isCCIP,
diff --git a/src/styles/css-styles.ts b/src/styles/css-styles.ts
index 54675a27..8a71de02 100644
--- a/src/styles/css-styles.ts
+++ b/src/styles/css-styles.ts
@@ -20,3 +20,11 @@ export const boxShadowAnimation = keyframes`
75% { box-shadow: 0 0 10px rgba(255,255,255,0.5); }
100% { box-shadow: 0 0 5px rgba(7,232,216,0); }
`;
+
+export const orangeBoxShadowAnimation = keyframes`
+0% { box-shadow: 0 0 5px rgba(255, 168, 0, 0); }
+25% { box-shadow: 0 0 10px rgba(255, 168, 0,0.5); }
+50% { box-shadow: 0 0 15px rgba(255, 168, 0,0.75); }
+75% { box-shadow: 0 0 10px rgba(255, 168, 0,0.5); }
+100% { box-shadow: 0 0 5px rgba(7,232,216,0); }
+`;
diff --git a/src/styles/modal-theme.ts b/src/styles/modal-theme.ts
index 04be30e7..97e04200 100644
--- a/src/styles/modal-theme.ts
+++ b/src/styles/modal-theme.ts
@@ -5,7 +5,7 @@ const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpe
const baseStyle = definePartsStyle({
dialogContainer: {
- top: '19.5%',
+ top: '10.5%',
},
dialog: {
padding: '15px',