StackUp is a Stacks dApp for building daily momentum: claim once per day, grow your streak, and unlock on-chain badge NFTs at milestone days.
What You Get
- Leather wallet connect
- One-tap daily
claimtransaction - On-chain reads: current streak, last claim day, owned badges
- Milestone badge gallery (1 / 3 / 7 / 14 / 30 by default)
- Owner-only admin panel for milestones + metadata URIs
Default app target:
SP2022VXQ3E384AAHQ15KFFXVN3CY5G57HWCCQX23.streak-v3-5
Badge NFTs are minted automatically by the contract when a streak milestone is reached.
Badge art lives off-chain (IPFS) and is referenced by an on-chain token URI.
- Upload PNG + metadata JSON to IPFS (Pinata is fine).
- Set the URI on-chain via the admin function
set-badge-uri(kind, uri). - When a user hits that milestone, the contract mints the NFT and the wallet/explorer can resolve the token URI.
Metadata templates:
metadata/
Stacks contracts are immutable. This repo keeps versioned contract files so you can deploy a new name when you iterate.
Current contract (recommended):
contracts/streak-v3-5.clar
History:
contracts/streak.clar(v1): streak + 7-day badgecontracts/streak-v3.clar: configurable badge milestones + token URIscontracts/streak-v3-1.clar: redeploy name variantcontracts/streak-v3-2.clar: auto-mint 1-day badge on first claim (ifu1URI is configured)contracts/streak-v3-3.clar: admin-configurable milestones + optional paid mint (fees collected by contract)contracts/streak-v3-4.clar: paid mint fees routed directly to a configurablefee-recipientcontracts/streak-v3-5.clar: per-kind mint fees (fallback to global fee)
If a contract name is already taken on a network, deploy the next versioned name and point the frontend at it via env vars.
Read-only:
get-streak(user)get-last-claim-day(user)get-owner(token-id)andget-token-uri(token-id)(SIP-009-style)
User actions:
claim(once per day, on-chain)
Owner/admin actions:
set-badge-uri(kind, uri)(sets IPFS metadata URI for a badge kind)set-milestones(list-of-kinds)(configures which streak days mint badges automatically)set-fee-recipient(principal)(where paid mint fees are routed)set-mint-fee(microstx)andset-mint-fee-kind(kind, microstx)(configures paid mint pricing)mint-paid-kind(kind)(paid mint path, when enabled/configured)
Set these as Cloudflare Pages environment variables (or in a local .env file):
NEXT_PUBLIC_STACKS_NETWORK:mainnetortestnetNEXT_PUBLIC_CONTRACT_ADDRESS:SP...(mainnet) orST...(testnet)NEXT_PUBLIC_CONTRACT_NAME: e.g.streak-v3-5NEXT_PUBLIC_SITE_URL: your deployed site URL (used for absolute OG/Twitter tags)
If not set, the app falls back to defaults in app/ClientPage.tsx.
npm install
npm run devOpen http://localhost:3000.
Quality checks:
npm run lint
npm test
npm run buildThis app is configured for static export (next.config.ts sets output: "export").
- Build command:
npm run build - Build output directory:
out
The share card image is public/og.png (1200x630). Regenerate it with:
node scripts/gen-og.mjs- Logos:
public/logo/ - Icons:
public/icons/ - Badge images:
public/badges/
