Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions token-api/token-api-scaffold-eth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ A comprehensive SDK for interacting with The Graph Token API built on Scaffold-E
- [useNFTItems](#usenftitems)
- [useNFTOwnerships](#usenftownerships)
- [useNFTActivities](#usenftactivities)
- [useNFTHolders](#usenftholders)
- [useNFTSales](#usenftSales)
- [UI Components](#ui-components)
- [Common Patterns](#common-patterns)
Expand Down Expand Up @@ -255,6 +256,7 @@ export const useTokenApi = <DataType, ParamsType = Record<string, any>>(
- **Auto-Refetching**: Supports auto-refreshing with `refetchInterval`
- **Error Handling**: Comprehensive error handling and state management
- **Manual Refetch**: Provides a function to manually trigger refetches
- **Authentication Error Detection**: Clear guidance for API setup and troubleshooting

### Token API Hooks

Expand Down Expand Up @@ -973,6 +975,46 @@ interface NFTActivity {
}
```

#### useNFTHolders

Fetches NFT holder information for a specific contract.

**Location**: `packages/nextjs/app/token-api/_hooks/useNFTHolders.ts`

```typescript
export function useNFTHolders(options: UseNFTHoldersOptions) {
const { contractAddress, network = "mainnet", enabled = true } = options;

const normalizedContractAddress = normalizeContractAddress(contractAddress);
const endpoint = `nft/holders/evm/${normalizedContractAddress}`;

return useTokenApi<NFTHolder[]>(
endpoint,
{ network_id: network },
{ skip: !normalizedContractAddress || !enabled }
);
}
```

**Parameters**:

- `contractAddress`: NFT contract address (required)
- `network`: Network identifier (default: "mainnet")
- `enabled`: Whether to enable the query (default: true)

**Response Type**:

```typescript
interface NFTHolder {
token_standard: string; // ERC721, ERC1155, etc.
address: string; // Holder's wallet address
quantity: number; // Number of tokens held
unique_tokens: number; // Number of unique tokens held
percentage: number; // Percentage of total supply held
network_id: NetworkId;
}
```

#### useNFTSales

Fetches NFT sales/marketplace data.
Expand Down Expand Up @@ -1067,6 +1109,7 @@ The SDK includes UI components for each data type:
- **GetNFTItems**: Shows individual NFTs from a collection with metadata
- **GetNFTOwnerships**: Lists NFTs owned by a wallet address
- **GetNFTActivities**: Displays NFT transaction history with advanced filtering
- **GetNFTHolders**: Shows NFT holder information and distribution statistics
- **GetNFTSales**: Shows NFT marketplace sales data

Example usage:
Expand All @@ -1076,6 +1119,7 @@ import { GetMetadata } from "~~/app/token-api/_components/GetMetadata";
import { GetBalances } from "~~/app/token-api/_components/GetBalances";
import { GetNFTCollections } from "~~/app/token-api/_components/GetNFTCollections";
import { GetNFTOwnerships } from "~~/app/token-api/_components/GetNFTOwnerships";
import { GetNFTHolders } from "~~/app/token-api/_components/GetNFTHolders";

export default function YourPage() {
return (
Expand All @@ -1095,6 +1139,7 @@ export default function YourPage() {
{/* NFT Components */}
<GetNFTCollections isOpen={true} />
<GetNFTOwnerships isOpen={true} />
<GetNFTHolders isOpen={true} />
</div>
);
}
Expand Down Expand Up @@ -1360,8 +1405,26 @@ The SDK covers the following Token API endpoints:
- `/nft/items/evm/{contract}` - NFT items
- `/nft/ownerships/evm/{address}` - NFT ownerships
- `/nft/activities/evm` - NFT activities
- `/nft/holders/evm/{contract}` - NFT holders
- `/nft/sales/evm` - NFT sales

## Recent Updates & Fixes

**Major Improvements in Latest Version:**

- **Authentication Fix**: All APIs now properly handle authentication with comprehensive error messages
- **Data Structure Normalization**: Hooks return arrays directly (`NFTCollection[]`) instead of nested response objects
- **NFT Activities Requirements**: Contract address is now a required parameter with proper validation
- **Time Filtering**: Automatic 30-day time ranges prevent database timeouts on popular contracts
- **Interface Completeness**: Added missing fields like `token_standard` and `total_unique_supply` to NFT interfaces
- **Error Handling**: Enhanced error detection for authentication, validation, and timeout issues

**Breaking Changes:**

- Hook return types changed from `{data: T[]}` to `T[]` directly
- NFT Activities API requires `contract_address` parameter (no longer optional)
- Time filtering now uses default ranges to prevent timeouts

## Troubleshooting

### Authentication Issues
Expand All @@ -1385,6 +1448,7 @@ The SDK covers the following Token API endpoints:
- This was resolved in recent updates where hooks now return data arrays directly
- Ensure you're using the latest version of the hooks
- Check that components use `Array.isArray(data)` instead of `data?.data`
- All hooks now return proper array types (e.g., `NFTCollection[]`, `NFTItem[]`) instead of wrapper objects

### NFT Activities API Issues

Expand All @@ -1394,6 +1458,7 @@ The SDK covers the following Token API endpoints:
- The NFT Activities API requires a contract address parameter
- Ensure you provide a valid NFT contract address (not just a wallet address)
- Use time filters to prevent database timeouts on popular contracts
- Contract address is now a required parameter with proper validation

### Database Timeout Issues

Expand All @@ -1403,6 +1468,7 @@ The SDK covers the following Token API endpoints:
- Add time filters (startTime and endTime) to your queries
- Use the provided time range buttons (Last 24h, Last 7 days, etc.)
- Popular NFT contracts like BAYC require time filtering to avoid timeouts
- Default 30-day time ranges are now automatically applied to prevent timeouts

### Network Connection Issues

Expand Down
26 changes: 19 additions & 7 deletions token-api/token-api-scaffold-eth/TUTORIAL.MD
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,24 @@ export const useTokenMetadata = (

- `useNFTCollections`: Used in `GetNFTCollections.tsx` for fetching NFT collection metadata
- `useNFTItems`: Used in `GetNFTItems.tsx` for retrieving individual NFT items
- `useNFTOwnerships`: Used in `GetNFTOwnerships.tsx` for fetching NFT ownership data
- `useNFTActivities`: Used in `GetNFTActivities.tsx` for NFT transaction history
- `useNFTSales`: Used in `GetNFTSales.tsx` for NFT marketplace sales data
- `useNFTOwnerships`: Used in `GetNFTOwnerships.tsx` for fetching NFT ownership data
- `useNFTActivities`: Used in `GetNFTActivities.tsx` for NFT transaction history
- `useNFTHolders`: Used in `GetNFTHolders.tsx` for fetching NFT holder distribution data
- `useNFTSales`: Used in `GetNFTSales.tsx` for NFT marketplace sales data

### Key Improvements Made

**Data Structure Fix**: All hooks now return arrays directly (e.g., `NFTCollection[]`) instead of response wrapper objects, eliminating the need for components to access `data?.data`.

**Authentication Error Handling**: Enhanced error detection and user guidance for API authentication issues.
**Authentication Error Handling**: Enhanced error detection and user guidance for API authentication issues. The Graph Token API requires proper `NEXT_PUBLIC_GRAPH_TOKEN` configuration.

**Parameter Validation**: Added proper validation for required parameters (e.g., contract addresses for NFT Activities).
**Parameter Validation**: Added proper validation for required parameters (e.g., contract addresses for NFT Activities). The NFT Activities API specifically requires a contract address and cannot work with just wallet addresses.

**Time Filtering**: Implemented advanced time filtering with quick-select buttons to prevent database timeouts on popular contracts.
**Time Filtering**: Implemented advanced time filtering with quick-select buttons to prevent database timeouts on popular contracts. Default 30-day ranges are now automatically applied.

**Interface Completeness**: Added missing fields like `token_standard`, `total_unique_supply` to NFT collection interfaces, ensuring complete data structure coverage.

**Contract Address Normalization**: Implemented proper address cleaning and normalization functions to handle various input formats.

## Component Implementation Pattern

Expand Down Expand Up @@ -227,7 +232,14 @@ Example from GetMetadata.tsx:
- Implements advanced time filtering to prevent database timeouts
- Supports filtering by wallet addresses (from/to/any)

12. **GetNFTSales.tsx**
12. **GetNFTHolders.tsx**

- Uses `useNFTHolders` to fetch NFT holder information for a contract
- Displays holder addresses, quantities, and percentage distribution
- Shows token standards (ERC721, ERC1155) and unique token counts
- Includes proper address normalization and contract validation

13. **GetNFTSales.tsx**
- Uses `useNFTSales` to fetch NFT marketplace sales data
- Maps `token` parameter to `contract` for API compatibility
- Displays sales information including price and marketplace data
Expand Down
44 changes: 39 additions & 5 deletions token-api/token-api-scaffold-eth/WORKSHOP.MD
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ This workshop guides you through recreating a `WorkshopPage`. This component ser
useNFTItems,
useNFTOwnerships,
useNFTActivities,
useNFTHolders,
useNFTSales,
} from "~~/app/token-api/_hooks";
import type { NetworkId } from "~~/app/token-api/_types";
Expand Down Expand Up @@ -121,6 +122,7 @@ type LoggedKeys =
| "nftItems"
| "nftOwnerships"
| "nftActivities"
| "nftHolders"
| "nftSales";
const [logged, setLogged] = useState<Partial<Record<LoggedKeys, boolean>>>({});
```
Expand Down Expand Up @@ -277,6 +279,17 @@ const {
: null
);

// --- NFTHolders Hook ---
const {
data: nftHoldersData,
isLoading: isLoadingNFTHolders,
error: errorNFTHolders,
} = useNFTHolders({
contractAddress: contractAddress,
network: selectedNetwork,
enabled: timestampsReady,
});

// --- NFTSales Hook ---
const {
data: nftSalesData,
Expand Down Expand Up @@ -387,6 +400,17 @@ useEffect(() => {
}
}, [nftActivitiesData, isLoadingNFTActivities, errorNFTActivities, logged]);

useEffect(() => {
if (!logged.nftHolders && nftHoldersData !== undefined) {
console.log("useNFTHolders:", {
data: nftHoldersData,
isLoading: isLoadingNFTHolders,
error: errorNFTHolders,
});
setLogged((l) => ({ ...l, nftHolders: true }));
}
}, [nftHoldersData, isLoadingNFTHolders, errorNFTHolders, logged]);

useEffect(() => {
if (!logged.nftSales && nftSalesData !== undefined) {
console.log("useNFTSales:", {
Expand Down Expand Up @@ -563,10 +587,20 @@ This workshop provides a solid foundation for integrating both token and NFT hoo

**Key Takeaways:**

- Token hooks work with traditional ERC20 data (balances, transfers, prices)
- NFT hooks provide comprehensive NFT functionality (collections, items, ownerships, activities, sales)
- Some NFT hooks (like NFT Activities) require specific parameters (contract addresses)
- Time filtering is crucial for preventing database timeouts on popular contracts
- All hooks now return arrays directly, eliminating data structure confusion
- **Token hooks** work with traditional ERC20 data (balances, transfers, prices)
- **NFT hooks** provide comprehensive NFT functionality (collections, items, ownerships, activities, sales)
- **Authentication is required**: Ensure `NEXT_PUBLIC_GRAPH_TOKEN` is set in your `.env.local` file
- **NFT Activities API requirements**: Contract address is mandatory - cannot work with just wallet addresses
- **Time filtering prevents timeouts**: Default 30-day ranges are automatically applied for popular contracts
- **Data structure simplified**: All hooks now return arrays directly (`NFTCollection[]`), eliminating confusion
- **Error handling improved**: Clear messages for authentication, validation, and timeout issues

**Common Issues Resolved:**

- Authentication 401 errors → Set proper Graph API token
- "No NFT collections found" → Fixed authentication and data processing
- Database timeouts → Implemented automatic time filtering
- Validation errors → Added required parameter validation
- Data structure confusion → Hooks return arrays directly

Remember to consult the hook definitions and `_types` directory for detailed parameter options and response structures. Check the main README.md for troubleshooting common issues like authentication errors and database timeouts.
Loading