looplabs.Open workspace ↗
DEVELOPER DOCUMENTATION

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.

Deployment status is environment-specific. Check this server’s configuration for its network, program ID, and transaction availability. Mainnet support in the application does not mean the program is deployed or audited.

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

  1. Create a draft. The server generates a unique seed and derives an escrow PDA from the owner, seed, and configured program.
  2. Fund. The owner signs an instruction that creates the account and deposits the full reward, plus rent and fees. Verification makes the task public.
  3. Review. Contributors submit evidence. The owner selects one contribution off-chain. This selection is permanent in the application.
  4. 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.
  5. 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

MethodPathPurpose
GET/api/config, /api/healthDeployment configuration and process health
GET / PATCH/api/meAccount, progress, and profile
POST/api/checkinDaily UTC check-in, +10 XP once per day
GET/api/lessonsCurriculum without answer keys
POST/api/lessons/:id/complete{answer: number}; +50 XP once per lesson
GET / POST/api/projectsProject directory and creation
GET / POST/api/workFilter tasks or create a draft
GET/api/work/:idTask, contributions, payment
POST/api/work/:id/fund/preparePrepare unsigned funding transaction
POST/api/work/:id/fund/confirmVerify {signature} and publish
POST/api/work/:id/contributionsSubmit or update {proof, note}
POST/api/contributions/:id/approveOwner selects a contributor
POST/api/payments/:id/preparePrepare unsigned escrow release
POST/api/payments/:id/confirmVerify {signature} and record payment
POST/api/work/:id/refund/preparePrepare expired escrow refund
POST/api/work/:id/refund/confirmVerify {signature} and close listing
GET/api/activity, /api/leaderboardPublic progress
GET / POST/api/keysList or create API keys
DELETE/api/keys/:idRevoke an API key
POST/api/work/:id/reportReport {reason}
GET/api/admin/reportsOperator-only moderation queue
PATCH/api/admin/reports/:idOperator 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.