@@ -107,12 +107,28 @@ export default function InteractionClient() {
107107 const calculateUserAmountAfterFees = useCallback ( async ( amount : string ) => {
108108 if ( ! amount || ! tokenAddress || ! chainId || isNaN ( Number ( amount ) ) || Number ( amount ) <= 0 ) {
109109 setUserAmountAfterFees ( 0 ) ;
110+ setIsCalculatingFees ( false ) ;
110111 return ;
111112 }
112113
114+ // Validate that decimals is set and is a valid number
115+ if ( decimals === undefined || decimals === null || isNaN ( decimals ) ) {
116+ console . warn ( "Decimals not set yet, skipping fee calculation" ) ;
117+ setIsCalculatingFees ( false ) ;
118+ return ;
119+ }
120+
121+ setIsCalculatingFees ( true ) ;
122+
113123 try {
114124 const publicClient = getPublicClient ( config , { chainId } ) ;
115- if ( ! publicClient ) return ;
125+ if ( ! publicClient ) {
126+ console . warn ( "No public client available, using fallback calculation" ) ;
127+ const fallbackAmount = Number ( amount ) * 0.995 ;
128+ setUserAmountAfterFees ( isNaN ( fallbackAmount ) ? 0 : fallbackAmount ) ;
129+ setIsCalculatingFees ( false ) ;
130+ return ;
131+ }
116132
117133 const userAmount = await makeContractCallWithRetry ( publicClient , {
118134 address : tokenAddress ,
@@ -121,11 +137,23 @@ export default function InteractionClient() {
121137 args : [ parseUnits ( amount , decimals ) ] ,
122138 } ) ;
123139
124- setUserAmountAfterFees ( Number ( formatUnits ( userAmount as bigint , decimals ) ) ) ;
140+ const calculatedAmount = Number ( formatUnits ( userAmount as bigint , decimals ) ) ;
141+
142+ // Validate the calculated amount
143+ if ( isNaN ( calculatedAmount ) || calculatedAmount < 0 ) {
144+ console . warn ( "Invalid calculated amount, using fallback" ) ;
145+ const fallbackAmount = Number ( amount ) * 0.995 ;
146+ setUserAmountAfterFees ( isNaN ( fallbackAmount ) ? 0 : fallbackAmount ) ;
147+ } else {
148+ setUserAmountAfterFees ( calculatedAmount ) ;
149+ }
125150 } catch ( error ) {
126151 console . error ( "Error calculating user amount after fees:" , error ) ;
127152 // Fallback calculation
128- setUserAmountAfterFees ( Number ( amount ) * 0.995 ) ;
153+ const fallbackAmount = Number ( amount ) * 0.995 ;
154+ setUserAmountAfterFees ( isNaN ( fallbackAmount ) ? 0 : fallbackAmount ) ;
155+ } finally {
156+ setIsCalculatingFees ( false ) ;
129157 }
130158 } , [ tokenAddress , chainId , decimals , makeContractCallWithRetry ] ) ;
131159
@@ -147,6 +175,7 @@ export default function InteractionClient() {
147175 const [ isUserAdmin , setIsUserAdmin ] = useState < boolean > ( false ) ;
148176 const [ isUserMinter , setIsUserMinter ] = useState < boolean > ( false ) ;
149177 const [ userAmountAfterFees , setUserAmountAfterFees ] = useState < number > ( 0 ) ;
178+ const [ isCalculatingFees , setIsCalculatingFees ] = useState < boolean > ( false ) ;
150179 const { writeContract : grantMinterRole , data : grantMinterRoleData } = useWriteContract ( ) ;
151180 const { writeContract : revokeMinterRole , data : revokeMinterRoleData } = useWriteContract ( ) ;
152181
@@ -1005,14 +1034,14 @@ export default function InteractionClient() {
10051034 type = "number"
10061035 placeholder = "Enter amount"
10071036 value = { mintAmount }
1008- onChange = { ( e ) => setMintAmount ( e . target . value ) }
1037+ onChange = { ( e ) => setMintAmount ( Math . min ( Number ( e . target . value ) , tokenDetails . maxMintableAmount ) . toString ( ) ) }
10091038 className = "h-10 text-sm bg-white/60 dark:bg-[#2a1a00] border-2 border-gray-200 dark:border-yellow-400/20 text-gray-600 dark:text-yellow-200"
10101039 />
10111040 < Button
10121041 type = "button"
10131042 onClick = { ( ) => {
10141043 // Set max mintable amount (fees will be deducted from this amount)
1015- const safeMaxAmount = Math . max ( 0 , tokenDetails . maxMintableAmount - 0.000001 ) ;
1044+ const safeMaxAmount = Math . max ( 0 , tokenDetails . maxMintableAmount ) ;
10161045 setMintAmount ( safeMaxAmount . toFixed ( 6 ) ) ;
10171046 } }
10181047 disabled = { tokenDetails . maxMintableAmount === 0 }
@@ -1027,17 +1056,29 @@ export default function InteractionClient() {
10271056 You will receive:
10281057 < span
10291058 className = "font-bold cursor-help"
1030- title = { `${ userAmountAfterFees } ${ tokenDetails . tokenSymbol } ` }
1059+ title = { `${ userAmountAfterFees || 0 } ${ tokenDetails . tokenSymbol } ` }
10311060 >
1032- { formatNumber ( userAmountAfterFees ) } { tokenDetails . tokenSymbol }
1061+ { isCalculatingFees ? (
1062+ "Calculating..."
1063+ ) : ! isNaN ( userAmountAfterFees ) && userAmountAfterFees !== null ? (
1064+ formatNumber ( userAmountAfterFees )
1065+ ) : (
1066+ "0"
1067+ ) } { tokenDetails . tokenSymbol }
10331068 </ span >
10341069 < br />
10351070 Clowder fee:
10361071 < span
10371072 className = "font-bold cursor-help"
1038- title = { `${ Number ( mintAmount ) - userAmountAfterFees } ${ tokenDetails . tokenSymbol } ` }
1073+ title = { `${ ! isNaN ( userAmountAfterFees ) && userAmountAfterFees !== null ? Number ( mintAmount ) - userAmountAfterFees : 0 } ${ tokenDetails . tokenSymbol } ` }
10391074 >
1040- { formatNumber ( Number ( mintAmount ) - userAmountAfterFees ) } { tokenDetails . tokenSymbol }
1075+ { isCalculatingFees ? (
1076+ "Calculating..."
1077+ ) : ! isNaN ( userAmountAfterFees ) && userAmountAfterFees !== null ? (
1078+ formatNumber ( Number ( mintAmount ) - userAmountAfterFees )
1079+ ) : (
1080+ "0"
1081+ ) } { tokenDetails . tokenSymbol }
10411082 </ span >
10421083 </ p >
10431084 </ div >
0 commit comments