This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
cargo test --workspace # Run all contract tests
cargo test -p quest # Run tests for one crate (certificate, milestone, quest, or rewards)
cargo test -p milestone -- test_name # Run a single test by name
cargo fmt --all -- --check # Check formatting
cargo clippy --workspace --all-targets # Lint
stellar contract build # Build optimized WASM binariescd frontend
pnpm install --frozen-lockfile # Install deps
pnpm dev # Dev server at localhost:5173
pnpm build # Type-check (tsc -b) + production build
pnpm lint # ESLintLernza is a learn-to-earn platform on Stellar. A creator makes a Quest, enrolls learners, sets milestones with token rewards. Completed milestones trigger on-chain token distribution. There is no backend — all state lives on Stellar's ledger.
The Cargo workspace contains four #![no_std] Soroban contracts (each compiled to WASM with its own lib.rs + test.rs) and one shared library crate:
- quest — Entry point. Quest creation/update/archive, enrollee management (open join, owner add, invite-commitment redeem), admin pause/unpause, creator verification, and queries (
get_quest,get_enrollees,is_expired). StoresQuestInfoand enrollee lists keyed by auto-incrementing IDs (NextId). - milestone — Per-quest milestone definition (single + batch create), owner- or peer-review verification modes, distribution modes (flat/custom/competitive), submission/approval flow, and completion tracking. Returns
reward_amounton verification so the frontend can trigger reward transfers. - rewards — SAC-based token pools.
fund_quest()deposits tokens (funder becomes authority),distribute_reward()transfers from pool to enrollee. Usessoroban_sdk::token::Clientfor transfers. - certificate — Soroban non-fungible token (
stellar-tokens) for quest-completion certificates. Owner-gatedmint_certificate/mint_quest_certificate, metadata lookup, revocation tombstones (issue #720), and configurable base URI (issue #719). - common — Pure library crate (not a contract; no WASM, no
test.rs). Houses shared types (QuestInfo,Visibility,QuestStatus), TTL constants (BUMP,THRESHOLD), reward bounds (MAX_REWARD_AMOUNT), shared error codes, theIsDataKeymarker trait, and helpers likeis_contract_address/extend_persistent_ttl. Imported by the four contract crates.
Contract patterns:
- Auth:
address.require_auth()+ storage-based ownership checks - Storage tiers: Instance (counters/config), Persistent (entities/auth)
- TTL bumping:
BUMP = 518_400(~30 days),THRESHOLD = 120_960(~7 days) - No cross-contract calls — frontend orchestrates the flow between contracts
- No router library — URL-based routing in
App.tsxviapushState/popstate - Path alias:
@/maps tosrc/(configured invite.config.ts) hooks/use-wallet.ts— Freighter wallet integration (@stellar/freighter-api)components/ui/— shadcn/ui components (button, card, badge, progress)pages/— Landing, Dashboard, Quest, Create Quest, Creator, Leaderboard, Profile, Not Foundlib/mock-data.ts— Mock data (contracts not wired to frontend yet)
- Conventional Commits required for PR titles (enforced by CI):
feat:,fix:,docs:,refactor:,test:,chore:,ci:,build:,perf:,style:,revert: - PRs require at least one label from the project's label set
- Frontend: TypeScript strict mode, no
anytypes, kebab-case filenames, Tailwind only (no CSS modules), prefer shadcn/ui components - Contracts:
cargo fmt, address clippy warnings, public functions returnResult<T, Error> - Deployment handled by Vercel (no deploy workflows in CI)
"Workspace" → "Quest" rename is largely complete: the contract crate and directory are contracts/quest/, and on-chain APIs use create_quest / fund_quest / QuestInfo. Stragglers may still appear in mock-data identifiers (MOCK_WORKSPACES), the legacy /workspace/:id redirect route, and a handful of test names — these are intentional or out-of-scope and tracked in their own issues.