@@ -4,17 +4,17 @@ import { useCallback, useMemo, useState } from "react";
44import { useRouter } from "next/navigation" ;
55import { keccak256 , stringToHex , zeroAddress } from "viem" ;
66import { useAccount , usePublicClient , useReadContract , useWriteContract } from "wagmi" ;
7- import { useScaffoldReadContract } from "~~/hooks/scaffold-eth/useScaffoldReadContract" ;
87import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth/useScaffoldWriteContract" ;
98
109export interface PayButtonProps {
1110 listingId : string | number ;
1211 priceWei ?: string ; // pass as string to avoid bigint serialization issues
1312 paymentToken ?: string ; // zero address for ETH; otherwise ERC20
1413 disabled ?: boolean ;
14+ listingTypeAddress ?: string ; // spender/listing type contract address passed from parent
1515}
1616
17- export const PayButton = ( { listingId, priceWei, paymentToken, disabled } : PayButtonProps ) => {
17+ export const PayButton = ( { listingId, priceWei, paymentToken, disabled, listingTypeAddress } : PayButtonProps ) => {
1818 const { writeContractAsync, isMining } = useScaffoldWriteContract ( { contractName : "Marketplace" } ) ;
1919 const { address } = useAccount ( ) ;
2020 const router = useRouter ( ) ;
@@ -34,17 +34,11 @@ export const PayButton = ({ listingId, priceWei, paymentToken, disabled }: PayBu
3434 return "Buy" ;
3535 } , [ isEth , priceWei ] ) ;
3636
37- // Read listing pointer to get listingType (spender) address
3837 const idBig = useMemo ( ( ) => BigInt ( typeof listingId === "number" ? listingId : listingId . toString ( ) ) , [ listingId ] ) ;
39- const { data : listingRes } = useScaffoldReadContract ( {
40- contractName : "Marketplace" ,
41- functionName : "getListing" ,
42- args : [ idBig ] ,
43- // don't need to watch aggressively here
44- watch : false ,
45- } as any ) ;
46- const pointer = useMemo ( ( ) => ( listingRes ? ( listingRes as any ) [ 0 ] : undefined ) , [ listingRes ] ) ;
47- const listingTypeAddress = ( pointer ?. listingType as string | undefined ) ?. toLowerCase ?.( ) ;
38+ const listingTypeSpenderLower = useMemo (
39+ ( ) => ( listingTypeAddress ? listingTypeAddress . toLowerCase ( ) : undefined ) ,
40+ [ listingTypeAddress ] ,
41+ ) ;
4842
4943 // Minimal ERC20 ABI
5044 const erc20Abi = useMemo (
@@ -81,15 +75,15 @@ export const PayButton = ({ listingId, priceWei, paymentToken, disabled }: PayBu
8175
8276 const ownerAddress = ( address || "0x0000000000000000000000000000000000000000" ) as `0x${string } `;
8377 const tokenAddress = ( paymentToken || "0x0000000000000000000000000000000000000000" ) as `0x${string } `;
84- const spenderAddress = ( listingTypeAddress || "0x0000000000000000000000000000000000000000" ) as `0x${string } `;
78+ const spenderAddress = ( listingTypeSpenderLower || "0x0000000000000000000000000000000000000000" ) as `0x${string } `;
8579
8680 const { data : allowanceData } = useReadContract ( {
8781 address : tokenAddress ,
8882 abi : erc20Abi ,
8983 functionName : "allowance" ,
9084 args : [ ownerAddress , spenderAddress ] ,
9185 query : {
92- enabled : isErc20 && ! ! address && ! ! listingTypeAddress && ! ! paymentToken ,
86+ enabled : isErc20 && ! ! address && ! ! listingTypeSpenderLower && ! ! paymentToken ,
9387 } ,
9488 } as any ) ;
9589
@@ -108,6 +102,10 @@ export const PayButton = ({ listingId, priceWei, paymentToken, disabled }: PayBu
108102
109103 const onBuy = useCallback ( async ( ) => {
110104 try {
105+ // Prevent approving zero address if listing type (spender) isn't available yet
106+ if ( isErc20 && ! listingTypeSpenderLower ) {
107+ return ;
108+ }
111109 if ( isErc20 ) {
112110 const needed = priceWei ? BigInt ( priceWei ) : 0n ;
113111 const current = ( allowanceData as bigint | undefined ) ?? 0n ;
@@ -129,11 +127,26 @@ export const PayButton = ({ listingId, priceWei, paymentToken, disabled }: PayBu
129127 } catch {
130128 // swallow; user may have rejected or tx failed
131129 }
132- } , [ isErc20 , allowanceData , priceWei , doBuy , writeTokenAsync , tokenAddress , erc20Abi , spenderAddress , publicClient ] ) ;
130+ } , [
131+ isErc20 ,
132+ listingTypeSpenderLower ,
133+ allowanceData ,
134+ priceWei ,
135+ doBuy ,
136+ writeTokenAsync ,
137+ tokenAddress ,
138+ erc20Abi ,
139+ spenderAddress ,
140+ publicClient ,
141+ ] ) ;
133142
134143 return (
135144 < >
136- < button className = "btn btn-primary" onClick = { onBuy } disabled = { disabled || isMining } >
145+ < button
146+ className = "btn btn-primary"
147+ onClick = { onBuy }
148+ disabled = { disabled || isMining || ( isErc20 && ! listingTypeSpenderLower ) }
149+ >
137150 { label }
138151 </ button >
139152 { /* Approving is now automatic; no modal shown. */ }
0 commit comments