Skip to content

Commit 0df01f1

Browse files
committed
Enhance network switching and error handling in LaserEyes app
- Add `NetworkType` and `useEffect` for network management - Implement network switching logic in `App` component - Improve error handling with `toast` notifications - Update UtxoProvider to derive network from `useLaserEyes` - Refactor provider classes to handle unsupported networks - Adjust network constants and helper functions - Update package dependencies to use workspace versions
1 parent dcf2464 commit 0df01f1

File tree

13 files changed

+158
-67
lines changed

13 files changed

+158
-67
lines changed

apps/demo.lasereyes.build/app/page.tsx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import {
33
FRACTAL_MAINNET,
44
FRACTAL_TESTNET,
55
MAINNET,
6+
NetworkType,
67
SIGNET,
78
TESTNET,
89
TESTNET4,
910
} from '@omnisat/lasereyes'
1011
import dynamic from 'next/dynamic'
1112

1213
import App from '@/components/App'
13-
import { useState } from 'react'
14+
import { useEffect, useState } from 'react'
1415
import { UtxoProvider } from '@/hooks/useUtxos'
1516

1617
const DynamicLasereyesProvider = dynamic(
@@ -19,18 +20,41 @@ const DynamicLasereyesProvider = dynamic(
1920
)
2021

2122
export default function Home() {
22-
const [network] = useState<
23+
const [network, setNetwork] = useState<
2324
| typeof MAINNET
2425
| typeof TESTNET
2526
| typeof TESTNET4
2627
| typeof SIGNET
2728
| typeof FRACTAL_MAINNET
2829
| typeof FRACTAL_TESTNET
2930
>(MAINNET)
31+
32+
const [mounted, setMounted] = useState(false)
33+
34+
const switchNet = (net: NetworkType) => {
35+
if (network === MAINNET) {
36+
setNetwork(TESTNET4)
37+
} else {
38+
setNetwork(MAINNET)
39+
}
40+
}
41+
42+
useEffect(() => {
43+
setMounted(true)
44+
}, [])
45+
46+
if (!mounted) {
47+
return null
48+
}
49+
3050
return (
31-
<DynamicLasereyesProvider config={{ network }}>
51+
<DynamicLasereyesProvider
52+
config={{
53+
network: network,
54+
}}
55+
>
3256
<UtxoProvider network={network}>
33-
<App />
57+
<App setNetwork={switchNet} />
3458
</UtxoProvider>
3559
</DynamicLasereyesProvider>
3660
)

apps/demo.lasereyes.build/components/App.tsx

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,13 @@ import WalletCard from '@/components/WalletCard'
33
import { useEffect, useState } from 'react'
44
import { clsx } from 'clsx'
55
import {
6-
LEATHER,
7-
MAGIC_EDEN,
8-
OKX,
9-
OYL,
10-
PHANTOM,
11-
UNISAT,
12-
WIZZ,
13-
ORANGE,
14-
XVERSE,
6+
MAINNET,
7+
NetworkType,
8+
ProviderType,
9+
SUPPORTED_WALLETS,
10+
TESTNET4,
1511
useLaserEyes,
1612
WalletIcon,
17-
OP_NET,
18-
SUPPORTED_WALLETS,
19-
ProviderType,
2013
} from '@omnisat/lasereyes'
2114
import { satoshisToBTC } from '@/lib/btc'
2215
import { cn, truncateString } from '@/lib/utils'
@@ -30,8 +23,9 @@ import { FaExternalLinkAlt } from 'react-icons/fa'
3023
import { RxReload } from 'react-icons/rx'
3124
import { ClickToCopyNpmInstallPill } from '@/components/ClickToCopyNpmInstallPill'
3225
import { ImNewTab } from 'react-icons/im'
26+
import { toast } from 'sonner'
3327

34-
const App = () => {
28+
const App = ({ setNetwork }: { setNetwork: (n: NetworkType) => void }) => {
3529
const {
3630
address,
3731
paymentAddress,
@@ -56,6 +50,20 @@ const App = () => {
5650
| undefined
5751
>()
5852

53+
const switchN = () => {
54+
try {
55+
if (network === MAINNET) {
56+
switchNetwork(TESTNET4)
57+
setNetwork(TESTNET4)
58+
} else {
59+
switchNetwork(MAINNET)
60+
setNetwork(MAINNET)
61+
}
62+
} catch (e) {
63+
toast.error(e.message)
64+
}
65+
}
66+
5967
useEffect(() => {
6068
getPackageVersion().then((version) => {
6169
setPkgVersion(version)
@@ -91,6 +99,8 @@ const App = () => {
9199
src={
92100
address ? '/lasereyes_connected.svg' : '/lasereyes_disconnected.svg'
93101
}
102+
className={'w-auto h-auto'}
103+
priority
94104
alt={address ? 'Laser Eyes Connected' : 'Laser Eyes Disconnected'}
95105
width={300}
96106
height={47}
@@ -132,7 +142,14 @@ const App = () => {
132142
<div className={'border border-[#3c393f] w-full text-xl grow pb-8'}>
133143
<div className={'flex flex-row items-center gap-4 '}>
134144
<div className={'grow'} />
135-
<div className={'flex flex-col p-4 items-center'}>{network}</div>
145+
<div
146+
className={
147+
'flex flex-col border border-[#3c393f] hover:underline cursor-pointer hover:text-orange-400 p-4 items-center'
148+
}
149+
onClick={() => switchN()}
150+
>
151+
{network}
152+
</div>
136153
</div>
137154
<div
138155
className={'flex flex-col gap-2 text-center items-center break-all'}

apps/demo.lasereyes.build/hooks/useUtxos.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,20 @@ type UtxoContextType = {
1919
const UtxoContext = createContext<UtxoContextType | undefined>(undefined)
2020

2121
export const UtxoProvider: React.FC<{
22-
network: NetworkType
2322
children: React.ReactNode
24-
}> = ({ children, network }) => {
25-
const { paymentAddress } = useLaserEyes()
23+
}> = ({ children }) => {
24+
const { paymentAddress, network } = useLaserEyes()
2625
const mempoolUrl = `${getMempoolSpaceUrl(network)}/api/address/${paymentAddress}/utxo`
2726
const [utxos, setUtxos] = useState<IMempoolUtxo[]>([])
2827

2928
const fetcher = useCallback(async (url: string) => {
30-
const response = await fetch(url)
31-
if (!response.ok) {
32-
throw new Error('Failed to fetch UTXOs')
33-
}
34-
return response.json()
29+
try {
30+
const response = await fetch(url)
31+
if (!response.ok) {
32+
throw new Error('Failed to fetch UTXOs')
33+
}
34+
return response.json()
35+
} catch (e) {}
3536
}, [])
3637

3738
const { data: utxosData, error } = useSWR<IMempoolUtxo[]>(

packages/lasereyes-core/src/client/index.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ export class LaserEyesClient {
114114
await provider?.connect(defaultWallet)
115115
this.$store.setKey('connected', true)
116116
} catch (error) {
117-
console.error(error)
118117
this.$store.setKey('isConnecting', false)
119118
this.disconnect()
120119
throw error
@@ -128,9 +127,9 @@ export class LaserEyesClient {
128127
throw new Error('No wallet provider connected')
129128
}
130129

131-
if (!this.$providerMap[this.$store.get().provider!]) {
132-
throw new Error("The connected wallet doesn't support this method")
133-
}
130+
// if (!this.$providerMap[this.$store.get().provider!]) {
131+
// throw new Error("The connected wallet doesn't support request accounts")
132+
// }
134133

135134
try {
136135
return await this.$providerMap[
@@ -332,7 +331,7 @@ export class LaserEyesClient {
332331
} catch (error) {
333332
if (error instanceof Error) {
334333
if (error.message.toLowerCase().includes('not implemented')) {
335-
throw new Error("The connected wallet doesn't support this method")
334+
throw new Error("The connected wallet doesn't support getPublicKey")
336335
}
337336
}
338337
throw error
@@ -351,7 +350,7 @@ export class LaserEyesClient {
351350
} catch (error) {
352351
if (error instanceof Error) {
353352
if (error.message.toLowerCase().includes('not implemented')) {
354-
throw new Error("The connected wallet doesn't support this method")
353+
throw new Error("The connected wallet doesn't support getBalance")
355354
}
356355
}
357356
throw error

packages/lasereyes-core/src/client/providers/magic-eden.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
import * as bitcoin from 'bitcoinjs-lib'
22
import {
3-
GetAddressOptions,
3+
BitcoinNetworkType,
44
getAddress,
5-
signMessage,
5+
GetAddressOptions,
6+
MessageSigningProtocols,
67
sendBtcTransaction,
7-
BitcoinNetworkType,
88
SendBtcTransactionOptions,
9-
MessageSigningProtocols,
9+
signMessage,
1010
signTransaction,
1111
} from 'sats-connect'
1212
import { WalletProvider } from '.'
1313
import {
14-
ProviderType,
15-
NetworkType,
16-
MAGIC_EDEN,
1714
getSatsConnectNetwork,
18-
MAINNET,
1915
LaserEyesStoreType,
16+
MAGIC_EDEN,
17+
MAINNET,
18+
NetworkType,
19+
ProviderType,
2020
} from '../..'
2121
import {
2222
findOrdinalsAddress,
2323
findPaymentAddress,
24-
getBTCBalance,
2524
getBitcoinNetwork,
25+
getBTCBalance,
26+
isMainnetNetwork,
27+
isTestnetNetwork,
2628
} from '../../lib/helpers'
27-
import { MapStore, listenKeys } from 'nanostores'
29+
import { listenKeys, MapStore } from 'nanostores'
2830
import { persistentMap } from '@nanostores/persistent'
2931
import { fromOutputScript } from 'bitcoinjs-lib/src/address'
3032
import { keysToPersist, PersistedKey } from '../utils'
@@ -123,18 +125,27 @@ export default class MagicEdenProvider extends WalletProvider {
123125

124126
try {
125127
if (address) {
126-
this.restorePersistedValues()
127-
getBTCBalance(paymentAddress, this.network).then((totalBalance) => {
128-
this.$store.setKey('balance', totalBalance)
129-
})
130-
return
128+
if (address.startsWith('tb1') && isMainnetNetwork(this.network)) {
129+
this.disconnect()
130+
} else {
131+
this.restorePersistedValues()
132+
getBTCBalance(paymentAddress, this.network).then((totalBalance) => {
133+
this.$store.setKey('balance', totalBalance)
134+
})
135+
return
136+
}
131137
}
138+
139+
if (isTestnetNetwork(this.network)) {
140+
throw new Error(`${this.network} is not supported by ${MAGIC_EDEN}`)
141+
}
142+
132143
let magicEdenNetwork = getSatsConnectNetwork(this.network || MAINNET)
133144
const getAddressOptions = {
134145
getProvider: async () => this.library,
135146
payload: {
136147
purposes: ['ordinals', 'payment'],
137-
message: 'Address for receiving Ordinals and payments',
148+
message: 'Connecting with lasereyes',
138149
network: {
139150
type: magicEdenNetwork,
140151
},

packages/lasereyes-core/src/client/providers/oyl.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import * as bitcoin from 'bitcoinjs-lib'
22
import { UNSUPPORTED_PROVIDER_METHOD_ERROR, WalletProvider } from '.'
33
import { ProviderType, NetworkType } from '../../types'
4-
import { createSendBtcPsbt, getBTCBalance } from '../../lib/helpers'
4+
import {
5+
createSendBtcPsbt,
6+
getBTCBalance,
7+
isTestnetNetwork,
8+
} from '../../lib/helpers'
59
import { OYL } from '../../constants/wallets'
610
import { listenKeys, MapStore } from 'nanostores'
711
import { persistentMap } from '@nanostores/persistent'
@@ -98,6 +102,10 @@ export default class OylProvider extends WalletProvider {
98102

99103
async connect(_: ProviderType): Promise<void> {
100104
if (!this.library) throw new Error("Oyl isn't installed")
105+
if (isTestnetNetwork(this.network)) {
106+
throw new Error(`${this.network} is not supported by Oyl`)
107+
}
108+
101109
const { nativeSegwit, taproot } = await this.library.getAddresses()
102110
if (!nativeSegwit || !taproot) throw new Error('No accounts found')
103111
this.$store.setKey('address', taproot.address)

packages/lasereyes-core/src/client/providers/phantom.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
createSendBtcPsbt,
77
getBitcoinNetwork,
88
getBTCBalance,
9+
isTestnetNetwork,
910
} from '../../lib/helpers'
1011
import { listenKeys } from 'nanostores'
1112
import { fromOutputScript } from 'bitcoinjs-lib/src/address'
@@ -73,6 +74,10 @@ export default class PhantomProvider extends WalletProvider {
7374

7475
async connect(_: ProviderType): Promise<void> {
7576
if (!this.library) throw new Error("Phantom isn't installed")
77+
if (isTestnetNetwork(this.network)) {
78+
throw new Error(`${this.network} is not supported by ${PHANTOM}`)
79+
}
80+
7681
const phantomAccounts = await this.library.requestAccounts()
7782
if (!phantomAccounts) throw new Error('No accounts found')
7883
this.$store.setKey('accounts', phantomAccounts)

packages/lasereyes-core/src/client/providers/unisat.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export default class UnisatProvider extends WalletProvider {
8282
this.parent.disconnect()
8383
}
8484
}
85-
private handleNetworkChanged(network: NetworkType) {
85+
private handleNetworkChanged(network: string) {
8686
const foundNetwork = getNetworkForUnisat(network)
8787
if (this.network !== foundNetwork) {
8888
this.switchNetwork(foundNetwork)
@@ -94,6 +94,12 @@ export default class UnisatProvider extends WalletProvider {
9494
if (!this.library) throw new Error("Unisat isn't installed")
9595
const unisatAccounts = await this.library.requestAccounts()
9696
if (!unisatAccounts) throw new Error('No accounts found')
97+
await this.getNetwork().then((network) => {
98+
if (this.network !== network) {
99+
console.log('Network changed')
100+
this.switchNetwork(this.network)
101+
}
102+
})
97103
const unisatPubKey = await this.library.getPublicKey()
98104
if (!unisatPubKey) throw new Error('No public key found')
99105
this.$store.setKey('accounts', unisatAccounts)
@@ -102,12 +108,8 @@ export default class UnisatProvider extends WalletProvider {
102108
this.$store.setKey('publicKey', unisatPubKey)
103109
this.$store.setKey('paymentPublicKey', unisatPubKey)
104110
this.$store.setKey('provider', UNISAT)
105-
await this.getNetwork().then((network) => {
106-
if (this.config?.network !== network) {
107-
this.switchNetwork(network)
108-
}
109-
})
110-
// TODO: Confirm if this is necessary and why
111+
112+
// TODO: Confirm if this i necessary and why
111113
getBTCBalance(unisatAccounts[0], this.network).then((totalBalance) => {
112114
this.$store.setKey('balance', totalBalance)
113115
})
@@ -192,6 +194,5 @@ export default class UnisatProvider extends WalletProvider {
192194
const wantedNetwork = getUnisatNetwork(network)
193195
await this.library?.switchChain(wantedNetwork)
194196
this.$network.set(network)
195-
await this.getBalance()
196197
}
197198
}

0 commit comments

Comments
 (0)