Skip to main content

Overview

The useProtocols hook provides access to the complete list of Stacks DeFi protocols with built-in filtering and sorting capabilities. It enables users to browse protocols by type (Lending, DEX, Yield, Stacking) and automatically sorts by APY. Source: src/hooks/useProtocols.js

Import

import { useProtocols } from './hooks/useProtocols';

Hook Signature

function useProtocols(): {
  protocols: Array<Protocol>,
  filter: string,
  setFilter: (filter: string) => void,
  loading: boolean,
}

Parameters

This hook takes no parameters.

Return Values

protocols
Array<Protocol>
Array of protocol objects, filtered by current filter and sorted by APY (highest first).Each protocol object contains:
  • name (string): Protocol name (e.g., “Zest Protocol”)
  • type (string): Protocol type - "Lending", "DEX", "Yield", or "Stacking"
  • apy (string): Annual percentage yield (e.g., "8.2")
  • tvl (string): Total value locked (e.g., "$48.2M")
  • asset (string): Supported assets (e.g., "sBTC", "STX", "sBTC, STX")
  • risk (string): Risk level - "Low", "Medium", or "High"
  • description (string): Brief protocol description
  • url (string): Protocol website URL
  • logo (string, optional): Logo image URL or path
filter
string
Current filter selection. One of: "All", "Lending", "DEX", "Yield", or "Stacking".Defaults to "All" which shows all protocols.
setFilter
function
Update the protocol filter. Triggers a loading animation (800ms) when changed.Signature: (filter: string) => voidValid values: "All", "Lending", "DEX", "Yield", "Stacking"
loading
boolean
true during filter transition animation (800ms), false otherwise. Use this to show loading states when filter changes.

Usage Example

import { useProtocols } from './hooks/useProtocols';

function ProtocolList() {
  const { protocols, filter, setFilter, loading } = useProtocols();

  return (
    <div>
      <h2>DeFi Protocols</h2>
      
      {/* Filter Buttons */}
      <div className="filters">
        {['All', 'Lending', 'DEX', 'Yield', 'Stacking'].map(type => (
          <button
            key={type}
            onClick={() => setFilter(type)}
            className={filter === type ? 'active' : ''}
          >
            {type}
          </button>
        ))}
      </div>
      
      {/* Protocol Cards */}
      {loading ? (
        <div>Loading...</div>
      ) : (
        <div className="protocol-grid">
          {protocols.map(protocol => (
            <div key={protocol.name} className="protocol-card">
              <h3>{protocol.name}</h3>
              <p>{protocol.description}</p>
              <div className="protocol-stats">
                <span>APY: {protocol.apy}%</span>
                <span>TVL: {protocol.tvl}</span>
                <span>Risk: {protocol.risk}</span>
              </div>
              <a href={protocol.url} target="_blank">Visit Protocol →</a>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Filter Types

The hook supports these filter values:

All

Shows all protocols across all types. This is the default filter.Use case: Browse entire protocol ecosystem

Lending

Shows only lending and borrowing protocols.Examples: Zest Protocol, ArkadikoUse case: Users wanting to lend assets or take loans

DEX

Shows only decentralized exchanges and swap protocols.Examples: ALEX, VelarUse case: Users wanting to trade tokens

Yield

Shows only yield farming and liquidity mining protocols.Use case: Users seeking passive income opportunities

Stacking

Shows only STX stacking protocols and pools.Examples: StackingDAO, Xverse StackingUse case: Users wanting to stack STX and earn BTC

Sorting Behavior

Protocols are automatically sorted by APY in descending order (highest first):
const sorted = [...filtered].sort((a, b) =>
  parseFloat(b.apy) - parseFloat(a.apy)
);
This ensures users always see the highest-yielding opportunities first, regardless of the selected filter.

Loading Animation

When changing filters, the hook triggers an 800ms loading state:
useEffect(() => {
  setLoading(true);
  setTimeout(() => setLoading(false), 800);
}, [filter]);
This creates a smooth transition effect when switching between protocol types.

Protocol Data Source

The hook loads protocols from the static PROTOCOLS array:
import { PROTOCOLS } from '../services/protocolData';

const [protocols, setProtocols] = useState(PROTOCOLS);
The protocol data is static. For real-time updates, consider integrating with DeFiLlama API or other data providers.

Best Practices

Show Filter Count

Display the number of protocols matching the current filter to help users understand results.

Smooth Transitions

Use the loading state to animate filter changes and improve perceived performance.

Empty States

Handle cases where no protocols match the filter (shouldn’t happen with default data, but good practice).

External Links

Always open protocol URLs in new tabs with target="_blank" and rel="noopener noreferrer".

Common Patterns

Filter Pills with Active State

function FilterPills() {
  const { filter, setFilter } = useProtocols();
  
  const filters = ['All', 'Lending', 'DEX', 'Yield', 'Stacking'];
  
  return (
    <div className="filter-pills">
      {filters.map(f => (
        <button
          key={f}
          onClick={() => setFilter(f)}
          className={filter === f ? 'active' : ''}
        >
          {f}
        </button>
      ))}
    </div>
  );
}

Protocol Count Badge

function ProtocolHeader() {
  const { protocols, filter } = useProtocols();
  
  return (
    <div className="header">
      <h1>DeFi Protocols</h1>
      <span className="count">
        {protocols.length} {filter !== 'All' ? filter : ''} protocols
      </span>
    </div>
  );
}

Grid with Responsive Layout

function ResponsiveProtocolGrid() {
  const { protocols, loading } = useProtocols();
  
  if (loading) return <LoadingSkeleton />;
  
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
      {protocols.map(protocol => (
        <ProtocolCard key={protocol.name} protocol={protocol} />
      ))}
    </div>
  );
}

Protocol Object Structure

Each protocol in the protocols array has this structure:
interface Protocol {
  name: string;          // "Zest Protocol"
  type: string;          // "Lending" | "DEX" | "Yield" | "Stacking"
  apy: string;           // "8.2"
  tvl: string;           // "$48.2M"
  asset: string;         // "sBTC" | "STX" | "sBTC, STX"
  risk: string;          // "Low" | "Medium" | "High"
  description: string;   // Protocol description
  url: string;           // "https://zestprotocol.com"
  logo?: string;         // Optional logo URL
}

Build docs developers (and LLMs) love