Skip to main content

Overview

The Portfolio Protocols service analyzes a Stacks wallet address to detect active positions across DeFi protocols. It checks token balances and transaction history to identify where users have deposited funds. Location: src/services/portfolioProtocols.js

How It Works

1

Fetch Token Balances

Queries Hiro API for all fungible tokens held by the wallet
2

Fetch Transaction History

Retrieves recent 50 transactions to detect protocol interactions
3

Match Protocol Contracts

Checks if wallet holds LP/receipt tokens or has transacted with known protocol contracts
4

Return Detected Positions

Returns array of protocols with position details and confidence levels

Main Function

detectWalletProtocols(address)

Detects which protocols a wallet has active positions in.
address
string
required
Stacks wallet address (e.g., SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7)
Returns: Promise<Array<WalletProtocol>>
WalletProtocol
object
Detected protocol position with metadata

Usage Examples

import { detectWalletProtocols } from './services/portfolioProtocols';

const walletAddress = 'SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7';

const positions = await detectWalletProtocols(walletAddress);

console.log(`Found ${positions.length} protocol positions`);

positions.forEach(pos => {
  console.log(`${pos.name}: ${pos.balanceNum.toFixed(6)} ${pos.asset}`);
  console.log(`  Confidence: ${pos.confidence}`);
});

Protocol Contract Addresses

The service monitors these known protocol contracts:
Type: Stacking
Token: stSTX (liquid staking receipt)
Contract: SP4SZE494VC2YC5JYG7AYFQ44F5Q4PYV7DVMDPBG.ststx-token
Type: Lending
Token: zsBTC (lending position)
Contract: SP2VCQJGH7PHP2DJK7Z0V48AGBHQAW3R3ZW1QF4N.zest-reward-dist
Type: DEX / Yield
Token: atALEX (auto-compounding position)
Contract: SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.auto-alex-v3
Type: DEX LP
Token: stxSTX-LP (liquidity pool token)
Contract: STTWD9SPRQVD3P733V89SV0P8EP8QSB5B00ZBZQ.stxstx-lp-token-v-1-2
Type: Yield
Token: USDh (yield-bearing stablecoin)
Contract: SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1N.token-usdh
Type: DEX LP
Token: WELSH-LP (liquidity pool token)
Contract: SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.wstx-welsh-lp-token
Type: Borrowing
Token: sBTC Collateral
Contract: SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1N.granite-vault

Detection Logic

The service uses two detection methods for maximum accuracy:

1. Token Balance Check

const tokenBalance = tokenBalances[tokenKey]?.balance ?? '0';
const hasToken = BigInt(tokenBalance) > 0n;
If the wallet holds any amount of the protocol’s receipt/LP token, it’s a confirmed position.

2. Transaction History Check

const hasInteracted = [...interactedContracts].some(id =>
  id.startsWith(contractAddr)
);
If the wallet has called functions on the protocol’s contract in recent history, it’s a likely position (may have withdrawn all funds but still active).

Confidence Levels

Confirmed

Wallet holds the protocol’s token (balance > 0). High confidence active position.

Likely

Wallet has transacted with protocol but holds no tokens. May have withdrawn funds or pending deposits.

Data Sources

This service uses the Hiro Stacks API for:
  • Fungible token balances: /extended/v1/address/{address}/balances
  • Transaction history: /extended/v1/address/{address}/transactions

Error Handling

The function returns an empty array on errors:
try {
  [tokenBalances, recentTxs] = await Promise.all([
    fetchTokenBalances(address),
    fetchRecentTxs(address),
  ]);
} catch (e) {
  console.warn('[portfolioProtocols] fetch error:', e.message);
  return []; // Fail gracefully
}

Performance

  • Parallel Fetching: Token balances and transactions fetched simultaneously
  • Transaction Limit: Only analyzes last 50 transactions for efficiency
  • No Pagination: Single-request design for fast response times

useWalletProtocols Hook

React hook wrapper for position detection

DefiLlama Service

Fetch protocol TVL and APY data

Build docs developers (and LLMs) love