11import { useState , useEffect , useCallback } from "react" ;
2- import { useWallet } from "@meshsdk/react" ;
32import { Dialog , DialogContent , DialogHeader , DialogTitle , DialogDescription } from "@/components/ui/dialog" ;
43import { Button } from "@/components/ui/button" ;
54import { useToast } from "@/hooks/use-toast" ;
65import useUTXOS from "@/hooks/useUTXOS" ;
7- import { useSiteStore } from "@/lib/zustand/site " ;
8- import { deserializeAddress , pubKeyAddress , scriptAddress , serializeAddressObj } from "@meshsdk/core " ;
6+ import useMeshWallet from "@/hooks/useMeshWallet " ;
7+ import { normalizeAddressToBech32 } from "@/utils/addressCompatibility " ;
98
109interface WalletAuthModalProps {
1110 address : string ; // display label; actual signing address is derived from wallet.getUsedAddresses()
@@ -16,9 +15,16 @@ interface WalletAuthModalProps {
1615}
1716
1817export function WalletAuthModal ( { address, open, onClose, onAuthorized, autoAuthorize = false } : WalletAuthModalProps ) {
19- const { wallet, connected } = useWallet ( ) ;
20- const network = useSiteStore ( ( state ) => state . network ) ;
21- const netId = ( network === 1 ? 1 : 0 ) as 0 | 1 ;
18+ // Use the Mesh 1.9 BrowserWallet (via useMeshWallet), NOT react-2.0's
19+ // useWallet().wallet. The latter is a low-level CIP-30 wallet whose
20+ // signData(address, payload) argument order is SWAPPED relative to 1.9's
21+ // signData(payload, address). Calling it with our (nonce, address) order
22+ // made wallets (e.g. VESPR) sign with the nonce as the address and throw
23+ // CIP-30 InternalError (-2). The 1.9 wallet matches the (payload, address)
24+ // order used everywhere else in the app, and the UTXOS MeshWallet below is
25+ // also payload-first — so a single signData(nonce, address) call is correct
26+ // for both.
27+ const { wallet : meshWallet , connected } = useMeshWallet ( ) ;
2228 const { wallet : utxosWallet , isEnabled : isUtxosEnabled } = useUTXOS ( ) ;
2329 const { toast } = useToast ( ) ;
2430 const [ submitting , setSubmitting ] = useState ( false ) ;
@@ -27,22 +33,7 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized, autoAuth
2733 const signingWallet =
2834 isUtxosEnabled && utxosWallet ?. cardano
2935 ? utxosWallet . cardano
30- : ( wallet && connected ? wallet : null ) ;
31-
32- const normalizePaymentAddress = useCallback ( ( maybeHexOrBech : string ) : string => {
33- if ( maybeHexOrBech . startsWith ( "addr1" ) || maybeHexOrBech . startsWith ( "addr_test1" ) ) {
34- return maybeHexOrBech ;
35- }
36- const d = deserializeAddress ( maybeHexOrBech ) ;
37- const stakeCredential = d . stakeCredentialHash || d . stakeScriptCredentialHash || "" ;
38- const rebuilt =
39- d . pubKeyHash
40- ? pubKeyAddress ( d . pubKeyHash , stakeCredential , ! ! d . stakeScriptCredentialHash )
41- : d . scriptHash
42- ? scriptAddress ( d . scriptHash , stakeCredential , ! ! d . stakeScriptCredentialHash )
43- : null ;
44- return rebuilt ? serializeAddressObj ( rebuilt , netId ) : maybeHexOrBech ;
45- } , [ netId ] ) ;
36+ : ( meshWallet && connected ? meshWallet : null ) ;
4637
4738 const handleAuthorize = useCallback ( async ( ) => {
4839 if ( ! signingWallet ) {
@@ -95,7 +86,10 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized, autoAuth
9586 if ( ! signingAddress ) {
9687 throw new Error ( "No addresses found for wallet" ) ;
9788 }
98- signingAddress = normalizePaymentAddress ( signingAddress ) ;
89+ signingAddress = normalizeAddressToBech32 ( signingAddress ) ;
90+ if ( ! signingAddress . startsWith ( "addr1" ) && ! signingAddress . startsWith ( "addr_test1" ) ) {
91+ throw new Error ( "Could not read a valid payment address from this wallet." ) ;
92+ }
9993
10094 // 1) Get nonce from existing endpoint
10195 const nonceRes = await fetch ( `/api/v1/getNonce?address=${ encodeURIComponent ( signingAddress ) } ` ) ;
@@ -113,26 +107,31 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized, autoAuth
113107
114108 let signed : { signature : string ; key : string } | undefined ;
115109 try {
116- // Mirror the working Swagger token flow: signData(nonce , address)
110+ // Mesh 1.9 / UTXOS order is signData(payload , address).
117111 signed = ( await ( signingWallet as any ) . signData (
118112 nonce ,
119113 signingAddress ,
120114 ) ) as { signature : string ; key : string } ;
121115 } catch ( error : any ) {
122- if ( error instanceof Error ) {
123- const msg = error . message . toLowerCase ( ) ;
124- if (
125- msg . includes ( "user" ) ||
126- msg . includes ( "cancel" ) ||
127- msg . includes ( "decline" ) ||
128- msg . includes ( "reject" )
129- ) {
130- throw new Error (
131- "Signing cancelled. Please try again and approve the signing request." ,
132- ) ;
133- }
134- }
135- throw new Error ( "Failed to sign nonce. Please try again." ) ;
116+ const raw =
117+ error instanceof Error
118+ ? error . message
119+ : typeof error === "string"
120+ ? error
121+ : ( ( ) => {
122+ try {
123+ return JSON . stringify ( error ) ;
124+ } catch {
125+ return String ( error ) ;
126+ }
127+ } ) ( ) ;
128+ // Surface the wallet's real error verbatim — some (e.g. the UTXOS
129+ // smart wallet) fail inside signData with a provider-specific
130+ // message we otherwise lose. The previous cancel/reject heuristic
131+ // false-matched non-cancellation errors that merely contained the
132+ // word "user", hiding the true cause, so always show the raw text.
133+ console . error ( "[WalletAuthModal] signData failed:" , error ) ;
134+ throw new Error ( `Failed to sign nonce: ${ raw || "unknown wallet error" } ` ) ;
136135 }
137136
138137 if ( ! signed ?. signature || ! signed ?. key ) {
@@ -171,7 +170,7 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized, autoAuth
171170 } finally {
172171 setSubmitting ( false ) ;
173172 }
174- } , [ signingWallet , toast , onAuthorized , onClose , normalizePaymentAddress ] ) ;
173+ } , [ signingWallet , toast , onAuthorized , onClose ] ) ;
175174
176175 // Auto-authorize when modal opens if autoAuthorize is true (only once)
177176 useEffect ( ( ) => {
0 commit comments