Build your own loop.
Loop Labs provides wallet authentication, project milestones, contribution review, and Solana escrow workflows through a same-origin JSON API. This implementation supports native SOL. XP is non-transferable learning progress.
Create an API key in Workspace → Settings after signing in with your wallet. Use the included JavaScript client:
import { LoopLabs } from './public/sdk.js';
const loop = new LoopLabs({
baseUrl: 'http://localhost:3000',
apiKey: process.env.LOOP_API_KEY,
});
const project = await loop.projects.create({
name: 'A better wallet experience',
description: 'Building accessible wallet onboarding for Solana.',
website: 'https://example.com',
});
const milestone = await loop.milestones.create({
projectId: project.id,
title: 'Ship accessible wallet onboarding',
description: 'Build a wallet connection screen with keyboard support and tests.',
category: 'Development',
amount: '0.1', // SOL, always a decimal string
deadline: new Date(Date.now() + 7 * 86400000).toISOString(),
});
// Draft only: the owner must sign the funding transaction.
const funding = await loop.escrow.prepareFunding(milestone.id);No package named @looplabs/sdk is published by this repository. Import the included file directly. The client is also served at /sdk.js.
Wallet authentication
POST /api/auth/challenge accepts { "wallet": "PUBLIC_ADDRESS" }. Sign the returned message with your wallet and send { "id": "CHALLENGE_ID", "signature": "BASE58_SIGNATURE" } to POST /api/auth/verify. Challenges expire after five minutes and can be used only once.
Browser sessions use HttpOnly, SameSite=Strict cookies. Production cookies are Secure. Browser mutations must carry the configured Origin. API clients send Authorization: Bearer loop_…. Keys are hashed at rest and can be revoked. A key cannot sign an escrow transaction or create more API keys.
The API returns { "error": "Readable message", "requestId": "…" } on failure. Expect 400 for invalid input, 401 for missing authentication, 403 for unauthorized actions, 404 for missing resources, 409 for state conflicts or pending finality, 429 for rate limits, and 503 for unavailable chain configuration.
Projects & tasks
Projects group milestones. Bounties may stand alone or belong to a project. A task starts as an owner-only draft. It appears publicly only after its exact escrow funding transaction has finalized and been verified.
Supported categories: Development, Design, Content, Community. Rewards use decimal SOL strings with up to nine places, between one lamport and 1,000 SOL. Deadlines must be one hour to 89 days ahead. Public lists return up to 50 tasks; use offset to paginate.
Each contributor may submit one proof per task, updating it until submissions close. Proof links must be HTTPS. Owners cannot submit to their own work. One approved contribution receives the entire reward.
Escrow lifecycle
- Create a draft. The server generates a unique seed and derives an escrow PDA from the owner, seed, and configured program.
- Fund. The owner signs an instruction that creates the account and deposits the full reward, plus rent and fees. Verification makes the task public.
- Review. Contributors submit evidence. The owner selects one contribution off-chain. This selection is permanent in the application.
- Release. The owner signs the escrow release to the selected contributor. The server verifies the finalized instruction and resulting escrow state before marking the reward paid.
- Refund if unpaid. After the deadline, the owner can reclaim the reward. Refund and release are mutually exclusive on-chain.
Trust model: the program locks funds but does not judge work. The owner chooses whom to pay. App approval does not reserve a recipient on-chain, prevent owner actions outside the app, or block a refund after the deadline. There is no arbitration or guaranteed payment for a submission. Permanent account rent remains in the escrow receipt to prevent replay; this version has no close-account instruction.
Unsigned transactions are returned as base64. Deserialize with Transaction.from, present them to the owner’s wallet, and submit the returned signature to the corresponding confirm endpoint. A confirm call never sends funds. If finalization is pending, retry confirmation using the same signature. Do not generate a second payment just because verification timed out.
Only the configured program and network are accepted. Mainnet payment preparation is disabled by default. The app does not mint tokens, custody private keys, execute swaps, or issue real assets for lesson completion.
API reference
| Method | Path | Purpose |
|---|---|---|
| GET | /api/config, /api/health | Deployment configuration and process health |
| GET / PATCH | /api/me | Account, progress, and profile |
| POST | /api/checkin | Daily UTC check-in, +10 XP once per day |
| GET | /api/lessons | Curriculum without answer keys |
| POST | /api/lessons/:id/complete | {answer: number}; +50 XP once per lesson |
| GET / POST | /api/projects | Project directory and creation |
| GET / POST | /api/work | Filter tasks or create a draft |
| GET | /api/work/:id | Task, contributions, payment |
| POST | /api/work/:id/fund/prepare | Prepare unsigned funding transaction |
| POST | /api/work/:id/fund/confirm | Verify {signature} and publish |
| POST | /api/work/:id/contributions | Submit or update {proof, note} |
| POST | /api/contributions/:id/approve | Owner selects a contributor |
| POST | /api/payments/:id/prepare | Prepare unsigned escrow release |
| POST | /api/payments/:id/confirm | Verify {signature} and record payment |
| POST | /api/work/:id/refund/prepare | Prepare expired escrow refund |
| POST | /api/work/:id/refund/confirm | Verify {signature} and close listing |
| GET | /api/activity, /api/leaderboard | Public progress |
| GET / POST | /api/keys | List or create API keys |
| DELETE | /api/keys/:id | Revoke an API key |
| POST | /api/work/:id/report | Report {reason} |
| GET | /api/admin/reports | Operator-only moderation queue |
| PATCH | /api/admin/reports/:id | Operator resolves with {action: "hide" | "dismiss"} |
Task filters: kind, category, status, project, q, mine=true, sort=newest|reward|deadline, offset.
Data & privacy
This application stores public wallet addresses, display names, bios, lesson completions, XP, projects, task briefs, proof links, reports, session hashes, API key hashes, and verified transaction signatures in its database. Project and contribution records are public. Never submit secrets or personal information in briefs or proof links.
Local browser storage contains your theme preference, wallet-provider choice, non-secret session-change notices, and transaction signatures awaiting verification. Google Fonts receives normal font requests. Wallet providers and the configured Solana RPC operate under their own policies. Blockchain records are public and cannot be erased by this app.
No advertising or analytics scripts are included. The production operator must supply its identity, support channel, retention/deletion policy, and applicable terms before inviting public users. This implementation note is not a substitute for the operator’s privacy policy.
Before a mainnet launch
The web application and escrow source are included. Live operation additionally requires a chosen reward asset, an independently reviewed escrow deployment, a funded deployment wallet, an RPC provider, a production domain, HTTPS hosting, backups, monitoring, and an operator policy/support channel.
The escrow implementation currently handles SOL only. SPL and Token-2022 escrow require an additional implementation and review. The server starts on devnet by default, with funding disabled until a program ID is configured. Development source and local tests are not evidence of a mainnet security audit.
See the repository’s README.md, docs/DEPLOYMENT.md, and docs/SECURITY.md for setup, operational procedures, and verification requirements.