A production-ready starter project for building a Stacks blockchain portfolio dashboard with Next.js, TypeScript, and Leather wallet integration.
- Next.js 16 with App Router and TypeScript
- Tailwind CSS for modern, responsive styling
- Leather Wallet integration for Stacks blockchain
- Real-time Balance Display - Fetch and display STX balance from Stacks API
- Clean Architecture with reusable components and hooks
- Production Ready with ESLint, Prettier, and TypeScript
- Responsive Design optimized for desktop and mobile
- Comprehensive Testing with Vitest and API test coverage
- Smart Contract Support - StackScope Notes Clarity contract included
- Frontend: Next.js (App Router) + TypeScript
- Styling: Tailwind CSS
- Blockchain: Stacks (Clarity smart contracts ready)
- Testing: Vitest + React Testing Library
- Smart Contracts: Clarity with automated deployment
- Wallet: Leather (formerly Hiro) wallet integration
- Package Manager: pnpm
- Code Quality: ESLint + Prettier
- Node.js 18+
- pnpm (recommended) or npm/yarn
- Leather wallet browser extension
-
Clone the repository
git clone https://github.com/Focus1010/stack-scope.git cd stack-scope -
Install dependencies
pnpm install
-
Set up environment variables
cp .env.example .env.local
Configure your environment variables:
# Stacks Network Configuration NEXT_PUBLIC_STACKS_NETWORK=mainnet NEXT_PUBLIC_STACKS_API_URL=https://api.mainnet.hiro.so # App Configuration NEXT_PUBLIC_APP_NAME=StackScope NEXT_PUBLIC_APP_ICON=/icon.png NEXT_PUBLIC_APP_DESCRIPTION=Stacks blockchain portfolio dashboard
-
Run the development server
pnpm dev
-
Open your browser Navigate to http://localhost:3000
This project includes the stackscope-notes Clarity smart contract for storing notes on the Stacks blockchain.
-
Set up environment
# Copy the template and add your mnemonic cp env-setup.txt .env.local # Edit .env.local with your actual wallet mnemonic
-
Deploy to testnet
pnpm deploy:testnet
-
Verify deployment
node scripts/verify-deploy.js <CONTRACT_ADDRESS> <TXID>
- Visit Stacks Explorer: https://explorer.stacks.co/
- Connect wallet (testnet mode)
- Deploy contract: Upload
contracts/stackscope-notes.clar - Contract name:
stackscope-notes - Fee:
0.001 STX
- Add notes linked to transaction IDs
- Update notes with new content
- Delete notes when no longer needed
- Owner-only access for note management
- Error handling with proper error codes
- Gas optimized for minimal fees
;; Add a note
(define-public (add-note (tx-id (buff 32) note (string 200)))
;; Update a note
(define-public (update-note (tx-id (buff 32) note (string 200)))
;; Delete a note
(define-public (delete-note (tx-id (buff 32)))
;; Get a note
(define-read-only (get-note (tx-id (buff 32)))After deployment, you'll receive:
- Contract Address:
ST...(testnet format) - Transaction ID:
0x...(64-character hex) - Explorer Link: Direct verification link
stackscope/
├── src/
│ ├── app/ # Next.js App Router pages
│ ├── components/ # Reusable UI components
│ │ ├── WalletButton.tsx
│ │ ├── ConnectionStatus.tsx
│ │ └── WalletSelector.tsx
│ ├── hooks/ # Custom React hooks
│ │ └── useStacksWallet.ts
│ ├── types/ # TypeScript type definitions
│ │ ├── stacks.ts
│ │ └── window.ts
│ ├── lib/ # Utility functions
│ │ └── walletDetection.ts
│ └── styles/ # Global styles
├── public/ # Static assets
├── .env.example # Environment variables template
└── README.md
pnpm dev- Start development serverpnpm build- Build for productionpnpm start- Start production serverpnpm lint- Run ESLintpnpm format- Format code with Prettierpnpm test- Run tests in watch modepnpm test:run- Run tests oncepnpm test:ui- Run tests with UI interface
The app integrates with Leather wallet for Stacks blockchain interaction:
- Connect Wallet: Click "Connect Wallet" to authenticate
- View Address: See your connected Stacks address (formatted as SP25***VFF3)
- Connection Status: Real-time connection status with green/gray indicators
- Balance Display: View your STX balance fetched from Stacks API
- Disconnect: Safely disconnect your wallet
StackScope fetches and displays your STX balance in real-time:
- API Integration: Uses Stacks public API (mainnet/testnet)
- Caching: 30-second cache to reduce API calls
- Error Handling: Graceful error states with retry functionality
- Formatting: Proper number formatting (e.g., 1,234.57 STX)
- Real-time Updates: Balance updates when wallet connects/disconnects
- Automatic Fetching: Balance loads when wallet connects
- Manual Refresh: Click "Refresh" button to update balance
- Loading States: Skeleton loaders during API calls
- Error Display: Clear error messages if API fails
- Network Support: Works with both mainnet and testnet
StackScope provides a comprehensive transaction history data layer:
- API Integration: Fetches transactions from Hiro Stacks API
- Transaction Types: Identifies send, receive, contract, and other transactions
- Status Tracking: Monitors success, pending, and failed transactions
- Data Normalization: Clean, consistent transaction data format
- Caching: 30-second cache for performance optimization
- Type Detection: Automatically categorizes transactions (send/receive/contract/other)
- Status Management: Tracks transaction status (success/pending/failed)
- Amount Extraction: Handles different transaction formats and operations
- Timestamp Conversion: Converts blockchain time to readable timestamps
- Address Resolution: Proper from/to address handling
interface StacksTransaction {
id: string; // Transaction hash
type: 'send' | 'receive' | 'contract' | 'other';
amount: string; // Amount in microSTX
timestamp: number; // Unix timestamp in milliseconds
status: 'success' | 'pending' | 'failed';
from: string; // Sender address
to: string; // Recipient address
fee: string; // Transaction fee
memo?: string; // Transaction memo
block_height?: number; // Block height
tx_type: string; // Raw transaction type
}import { useStacksTransactions } from '@/hooks/useStacksTransactions';
function TransactionHistory() {
const { address, network } = useStacksWallet();
const { transactions, isLoading, error, refetch } = useStacksTransactions(address, network, 20);
if (isLoading) return <div>Loading transactions...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h3>Recent Transactions</h3>
{transactions.map(tx => (
<div key={tx.id}>
{tx.type}: {tx.amount} STX ({tx.status})
</div>
))}
<button onClick={refetch}>Refresh</button>
</div>
);
}import { fetchWalletTransactions } from '@/lib/stacksApi';
// Fetch transactions
const transactions = await fetchWalletTransactions(
'SP1234567890abcdefghijklmnopqrstuvwxyz',
'mainnet',
20 // limit
);
// Transactions are normalized and ready to use
transactions.forEach(tx => {
console.log(`${tx.type}: ${tx.amount} STX`);
});- Mainnet:
https://api.mainnet.hiro.so/extended/v1/address/{address}/transactions - Testnet:
https://api.testnet.hiro.so/extended/v1/address/{address}/transactions
- Balance Cache: 30 seconds per address/network combination
- Transaction Cache: 30 seconds per address/network/limit combination
- Cache Invalidation: Manual cache clearing available via
clearBalanceCache()andclearTransactionCache()
- API Failures: Graceful error messages with retry options
- Network Errors: Automatic retry mechanisms
- Data Validation: Type-safe parsing and validation
- Fallback States: Empty states for no data scenarios
StackScope includes a comprehensive transaction history component:
Features:
- Responsive Design: Desktop table / Mobile cards layout
- Transaction Types: Visual indicators for send/receive/contract/other
- Status Indicators: Icons and badges for success/pending/failed
- Time Formatting: Relative timestamps (2h ago, Yesterday, etc.)
- Amount Display: Color-coded (green for receive, red for send)
- Copy Functionality: One-click transaction ID copying
- Loading States: Animated skeleton placeholders
- Error Handling: Clear error messages with retry buttons
- Empty States: Friendly messages with CTA to first transaction
UI Screenshots:
[Desktop Layout]
┌─────────────────────────────────────────────────────────┐
│ Transaction History [Refresh] │
├─────────────────────────────────────────────────────────┤
│ 🟢 Sent -1,000.00 STX ✅ success 1h ago │
│ ID: 0x1234567...abcdef [Copy ID] │
├─────────────────────────────────────────────────────────┤
│ 🟢 Received +2,000.00 STX ✅ success 2h ago │
│ ID: 0x0987654...fedcba [Copy ID] │
└─────────────────────────────────────────────────────────┘
[Mobile Layout]
┌─────────────────────┐
│ Transaction History │
│ [Refresh] │
├─────────────────────┤
│ 🟢 Sent │
│ -1,000.00 STX │
│ ✅ success 1h ago │
│ ID: 0x1234...def │
│ [Copy] │
├─────────────────────┤
│ 🟢 Received │
│ +2,000.00 STX │
│ ✅ success 2h ago │
│ ID: 0x0987...cba │
│ [Copy] │
└─────────────────────┘
Component Structure:
// TransactionHistory.tsx
- Responsive grid layout (desktop: 3-col, mobile: 1-col)
- Loading skeleton with animated placeholders
- Error state with retry functionality
- Empty state with CTA to first transaction
- Copy-to-clipboard for transaction IDs
- Hover effects and smooth transitions
- Accessibility with proper ARIA labelsThree-Column Grid:
- Main Content (2 columns): Portfolio overview and features
- Sidebar (1 column): Balance card + Transaction history
- Responsive: Stacked layout on mobile devices
Component Integration:
- BalanceCard: Real-time STX balance display
- TransactionHistory: Comprehensive transaction list
- WalletButton: Connect/disconnect functionality
- ConnectionStatus: Real-time connection indicator
The application supports multiple Stacks wallets:
- Leather: Primary wallet with full feature support
- Xverse: Mobile and desktop wallet compatibility
- Hiro: Legacy wallet support
The app automatically detects available wallets and provides a seamless connection experience.
By default, the app connects to the Stacks mainnet. You can change this in your environment variables:
NEXT_PUBLIC_STACKS_NETWORK=testnet # For testnet
NEXT_PUBLIC_STACKS_NETWORK=mainnet # For mainnet (default)The application is fully responsive and works seamlessly on:
- Desktop (1200px+)
- Tablet (768px - 1199px)
- Mobile (< 768px)
This foundation is ready for expansion:
- Portfolio Tracking: STX holdings and token performance
- NFT Gallery: Digital collectibles management
- Analytics: Blockchain activity insights
- DeFi Integration: Stacking and liquidity pools
- Transaction History: Detailed transaction logs
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Problem: "Connecting..." state persists after wallet approval
- Solution: The app uses URL-based authentication. After approving in your wallet, the page will reload and automatically detect the authentication state.
Problem: Wallet popup doesn't appear
- Solution: Ensure you have Leather, Xverse, or Hiro wallet installed and enabled in your browser.
Problem: Connection lost on page refresh
- Solution: The app automatically restores sessions on load. Check browser console for authentication errors.
Problem: Console shows authentication errors
- Solution: Clear browser storage and try reconnecting. Check that your wallet is unlocked.
Enable debug logging to trace connection issues:
- Open browser console (F12)
- Look for
[StacksWallet]prefixed logs - These logs show authentication flow details
- Extension Not Installed: Install Leather wallet from leather.io
- Wrong Network: Ensure wallet is on the same network as the app (mainnet/testnet)
- Browser Issues: Try refreshing the page or clearing cache
- Permission Denied: Grant the app permission to access your wallet
If you encounter issues:
- Check browser console for error messages
- Ensure your wallet is unlocked and on the correct network
- Try disconnecting and reconnecting
- Open an issue on GitHub with console logs
If you have any questions or need help, please open an issue on GitHub.