Skip to content

Commit 5df453f

Browse files
authored
feat: Add BTC signet support (#297)
1 parent 11e5c24 commit 5df453f

File tree

9 files changed

+503
-29
lines changed

9 files changed

+503
-29
lines changed

examples/hello/frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13-
"@zetachain/toolkit": "16.1.4",
13+
"@zetachain/toolkit": "16.2.0",
1414
"@zetachain/wallet": "1.0.13",
1515
"clsx": "^2.1.1",
1616
"ethers": "^6.13.2",

examples/hello/frontend/src/App.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@ import { UniversalSignInContextProvider } from '@zetachain/wallet/react';
33
import { AppContent } from './AppContent';
44
import { Header } from './components/Header';
55
import { USE_DYNAMIC_WALLET } from './constants/wallets';
6+
import { UnisatWalletProvider } from './context/UnisatWalletProvider';
67
import { useTheme } from './hooks/useTheme';
78

89
function App() {
910
const { theme } = useTheme();
1011

11-
return USE_DYNAMIC_WALLET ? (
12-
<UniversalSignInContextProvider environment="sandbox" theme={theme}>
13-
<Header />
14-
<AppContent />
15-
</UniversalSignInContextProvider>
16-
) : (
17-
<>
18-
<Header />
19-
<AppContent />
20-
</>
12+
return (
13+
<UnisatWalletProvider>
14+
{USE_DYNAMIC_WALLET ? (
15+
<UniversalSignInContextProvider environment="sandbox" theme={theme}>
16+
<Header />
17+
<AppContent />
18+
</UniversalSignInContextProvider>
19+
) : (
20+
<>
21+
<Header />
22+
<AppContent />
23+
</>
24+
)}
25+
</UnisatWalletProvider>
2126
);
2227
}
2328

examples/hello/frontend/src/ConnectedContent.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface ConnectedContentProps {
1818
supportedChain: SupportedChain | undefined;
1919
primaryWallet?: PrimaryWallet | null;
2020
account?: string | null;
21+
onChainSelect?: (chain: SupportedChain) => void;
2122
}
2223

2324
const DynamicConnectedContent = ({
@@ -85,11 +86,15 @@ const Eip6963ConnectedContent = ({
8586
selectedProvider,
8687
supportedChain,
8788
account,
89+
onChainSelect,
8890
}: ConnectedContentProps) => {
8991
const { switchChain } = useSwitchChain();
9092

9193
const handleNetworkSelect = (chain: SupportedChain) => {
92-
switchChain(chain.chainId);
94+
onChainSelect?.(chain);
95+
if (chain.chainType === 'EVM') {
96+
switchChain(chain.chainId);
97+
}
9398
};
9499

95100
return (
@@ -126,6 +131,7 @@ export function ConnectedContent({
126131
supportedChain,
127132
primaryWallet,
128133
account,
134+
onChainSelect,
129135
}: ConnectedContentProps) {
130136
return USE_DYNAMIC_WALLET ? (
131137
<DynamicConnectedContent
@@ -138,6 +144,7 @@ export function ConnectedContent({
138144
selectedProvider={selectedProvider}
139145
supportedChain={supportedChain}
140146
account={account}
147+
onChainSelect={onChainSelect}
141148
/>
142149
);
143150
}

examples/hello/frontend/src/Eip6963AppContent.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1+
import { useEffect, useState } from 'react';
2+
13
import { ConnectedContent } from './ConnectedContent';
2-
import { SUPPORTED_CHAINS } from './constants/chains';
4+
import { SUPPORTED_CHAINS, type SupportedChain } from './constants/chains';
35
import { DisconnectedContent } from './DisconnectedContent';
46
import { useEip6963Wallet } from './hooks/useEip6963Wallet';
57

68
export function Eip6963AppContent() {
79
const { selectedProvider, decimalChainId, account } = useEip6963Wallet();
810

9-
const supportedChain = SUPPORTED_CHAINS.find(
11+
// Find the EVM chain from wallet
12+
const evmChain = SUPPORTED_CHAINS.find(
1013
(chain) => chain.chainId === decimalChainId
1114
);
1215

16+
// Track selected chain separately to support non-EVM chains (SOL, BTC)
17+
const [selectedChain, setSelectedChain] = useState<
18+
SupportedChain | undefined
19+
>(evmChain);
20+
21+
// Sync with EVM wallet changes (when user switches chains in MetaMask, etc.)
22+
useEffect(() => {
23+
if (evmChain && evmChain.chainType === 'EVM') {
24+
setSelectedChain(evmChain);
25+
}
26+
}, [evmChain]);
27+
1328
const isDisconnected = !selectedProvider;
1429

1530
if (isDisconnected) {
@@ -19,7 +34,8 @@ export function Eip6963AppContent() {
1934
return (
2035
<ConnectedContent
2136
selectedProvider={selectedProvider}
22-
supportedChain={supportedChain}
37+
supportedChain={selectedChain}
38+
onChainSelect={setSelectedChain}
2339
account={account}
2440
/>
2541
);

examples/hello/frontend/src/components/NetworkSelector.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useMemo } from 'react';
22

33
import { SUPPORTED_CHAINS, type SupportedChain } from '../constants/chains';
44
import { USE_DYNAMIC_WALLET } from '../constants/wallets';
5+
import { useUnisatWallet } from '../context/UnisatWalletProvider';
56
import { Dropdown, type DropdownOption } from './Dropdown';
67

78
interface NetworkSelectorProps {
@@ -19,12 +20,19 @@ export const NetworkSelector = ({
1920
disabled = false,
2021
className = '',
2122
}: NetworkSelectorProps) => {
23+
const { connect: connectUnisatWallet, switchChain: switchUnisatChain } =
24+
useUnisatWallet();
25+
2226
// Convert chains to dropdown options
2327
const options: DropdownOption<SupportedChain>[] = useMemo(
2428
() =>
25-
SUPPORTED_CHAINS.filter(
26-
(chain) => USE_DYNAMIC_WALLET || chain.chainType === 'EVM'
27-
).map((chain) => ({
29+
SUPPORTED_CHAINS.filter((chain) => {
30+
if (USE_DYNAMIC_WALLET) {
31+
return chain.chainType === 'EVM' || chain.chainType === 'SOL';
32+
} else {
33+
return chain.chainType === 'EVM' || chain.chainType === 'BTC';
34+
}
35+
}).map((chain) => ({
2836
id: chain.chainId,
2937
label: chain.name,
3038
value: chain,
@@ -45,7 +53,17 @@ export const NetworkSelector = ({
4553
[selectedChain, options]
4654
);
4755

48-
const handleSelect = (option: DropdownOption<SupportedChain>) => {
56+
const handleSelect = async (option: DropdownOption<SupportedChain>) => {
57+
if (option.value.chainType === 'BTC') {
58+
try {
59+
await connectUnisatWallet();
60+
await switchUnisatChain('BITCOIN_SIGNET');
61+
} catch (error) {
62+
console.error('Failed to connect/switch Unisat wallet:', error);
63+
return; // Don't update selection if connection failed
64+
}
65+
}
66+
4967
onNetworkSelect?.(option.value);
5068
};
5169

examples/hello/frontend/src/constants/chains.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export interface SupportedChain {
22
explorerUrl: (txHash: string) => string;
33
name: string;
44
chainId: number;
5-
chainType: 'EVM' | 'SOL';
5+
chainType: 'EVM' | 'SOL' | 'BTC';
66
icon: string;
77
colorHex: string;
88
}
@@ -69,8 +69,20 @@ export const SUPPORTED_CHAINS: SupportedChain[] = [
6969
icon: '/logos/solana-logo.svg',
7070
colorHex: '#9945FF',
7171
},
72+
{
73+
explorerUrl: (txHash: string) =>
74+
`https://mempool.space/signet/tx/${txHash}`,
75+
name: 'Bitcoin Signet',
76+
chainId: 18333,
77+
chainType: 'BTC',
78+
icon: '/logos/bitcoin-logo.svg',
79+
colorHex: '#F7931A',
80+
},
7281
];
7382

83+
export const BITCOIN_GATEWAY_ADDRESS_SIGNET =
84+
'tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur';
85+
7486
export const SUPPORTED_CHAIN_IDS = SUPPORTED_CHAINS.map(
7587
(chain) => chain.chainId
7688
);

0 commit comments

Comments
 (0)